Thursday, 22 November 2007

This blog has moved

This blog has moved to http://rdingwall.name. You should be automatically redirected in a second or two, but if not, click here!

Thursday, 15 November 2007

Adding GMail's "Archive" button to Microsoft Outlook

Recently, I have been using GMail as my primary e-mail client. It's simple to use, lightweight, fast and powerful. One feature I particularly like is the Archive button, which lets me clear messages out of my inbox with a single click. Instead of letting e-mails clutter up my inbox just in case I need them again, I can archive them as soon as I've read them. Fewer items in my inbox makes it easier to focus and prioritize tasks, which in turn makes me more productive.

In the high-pressure environment at work, where I frequently receive up to a hundred or so e-mails a day, everything I can do to make my life easier helps. Here is how I added an Archive button to Microsoft Outlook:

  1. Make a new folder in Outlook called Archive.
  2. Open the macro editor under Tools > Macros > Visual Basic Editor.
  3. Open ThisOutlookSession under Project1 in the Project Explorer window at the left side of the screen.
  4. Paste the following code:
    Option Explicit

    Public Sub ArchiveSelectedItems()
        MoveSelectedItemsToFolder "Archive"
    End Sub

    Private Sub MoveSelectedItemsToFolder(FolderName As String)
        On Error GoTo ErrorHandler
        
        Dim Namespace As Outlook.Namespace
        Set Namespace = Application.GetNamespace("MAPI")
       
        Dim Inbox As Outlook.MAPIFolder
        Set Inbox = Namespace.GetDefaultFolder(olFolderInbox)
       
        Dim Folder As Outlook.MAPIFolder
        Set Folder = Inbox.Folders(FolderName)

        If Folder Is Nothing Then
            MsgBox "The '" & FolderName & "' folder doesn't exist!", _
                vbOKOnly + vbExclamation, "Invalid Folder"
        End If

        Dim Item As Object
        For Each Item In Application.ActiveExplorer.Selection
            If Item.UnRead Then Item.UnRead = False
            Item.Move Folder
        Next
       
        Exit Sub
       
    ErrorHandler:
        MsgBox Error(Err)
       
    End Sub
  5. Save and close the editor.

Now the archive macro has been created. Let's add a button that will trigger it:

  1. Click on View > Toolbars > Customize, and select the Commands tab.
  2. Scroll down to the Macros category.
  3. Drag the Project1.ArchiveSelected command to a toolbar.
  4. Right-click on your new button, and rename it to Archive. Set it to display Text Only.
  5. Click Close.

All done!

Monday, 2 July 2007

If it ain't broke...

Resisting the urge to rewrite other peoples' code is one of the hardest challenges an inexperienced developer may encounter when working in a team environment. It is perfectly understandable; after all it is much easier to write code than to understand it. Not to mention the desire to fix and improve on any genuine flaws that may exist.

Recently, I have been involved in a number of projects that require extending and changing existing applications, developed by other people. Many times I have been tempted to rewrite functions that look buggy or inefficient. Much of the code is simply downright awful. However, as bad as it may seem to me, it works and it is trusted. I cannot touch it. In the increasingly marshaled enterprise environment I work in, changes that have not been agreed with the customer simply cannot be made. System requirements have formed a project contract which I cannot step outside of.

Existing code has been tested. Other people understand it. It is known to work. Making unnecessary changes risks introducing new bugs. Introducing a new bug would be a big step backwards.

Ultimately, because you're not adding anything new, any unnecessary changes will be a complete waste of time, in the eyes of your customer. And if you're being paid for your work, a waste of time equates to a waste of money.

No matter how bad the code, no matter how brain-damaged the design, do not change anything unless you absolutely have to. Log issues. Discuss them. But otherwise, if it ain't broke, don't fix it!

Thursday, 21 June 2007

Implementing header-only libraries in C++

Recently I have been investigating the feasibility of implementing a C++ curses library using only header files.

A header-only library is very simpler to use, as it does not require any object linking or dependencies. The relevant parts of the library are included entirely into the program itself. However, there are a few caveats:

  • We cannot use static variables, as their definitions will cascade to every object file that includes them. We could have the user define our internal static variables in their source files (perhaps with a macro for convenience), but I believe this is unreasonable and poor design.
  • Without static variables, our memory management options are limited, and we are prevented from using design patterns such as singletons.
  • The entire library is re-compiled each time with the program, causing it to take longer to compile.
  • If the implementation of our library changes, the entire program must be re-compiled to reflect the its changes.
  • The file size of the program will be greater because it includes the entire library.
  • Only private class members will be unavailable to the program. Everything else is open season.

I believe header-only libraries are well-suited where the ownership (including memory and lifetime management) of library objects lies with the user.

Thursday, 19 April 2007

Generating documentation with Doxygen

A few days ago, I had my first experience with Doxygen, an open-source documentation generator similar to Javadoc.

After a few hours of documenting my code to a satisfactory level, I had a very professional-looking set of HTML documentation. At work the next day, I used Doxygen to generate code for a Visual C# class library, which had been documented with XML comments.

Doxygen supports most C-derived programming languages including C, C++, Java and C#. It also allows you to define custom pages and sections; you are not limited to code documentation.

Documenting a method is very simple:

/// @brief Calculate the sum of two values.
///
/// Adds the two values together and returns their sum.
///
/// @param[in] aa The first value.
/// @param[in] bb The second value.
///
/// @return The sum of both values.
///
/// @note This method is deprecated!
///
/// @see operator+()
int add(int aa, int bb);

A full list of Doxygen commands is available here.

Tuesday, 10 April 2007

Short-circuit evaluation in VB.NET

When evaluating an and statement, there is no point testing the right hand side if the left is false.

If (False And SomeOtherCondition) Then
    ' ...
End If

In this example, there is no point evaluating SomeOtherCondition, because its value has no effect on the overall result of the and statement (false).

If (True Or SomeOtherCondition) Then
    ' ...
End If

Similiarly, in this example, there is no point evaluating SomeOtherCondition because it will have no effect on the overall result of the or statement. Breaking out of such a statement early is known as short-circuit evaluation, and is performed automatically in many programming languages.

Unfortunately, the And and Or operators VB and VB.NET perform no such optimization, and always evaluate both conditions, regardless of their values.

To alleviate this problem, VB.NET introduces a couple of handy new operators, AndAlso and OrElse:

If (True OrElse SomeOtherCondition) Then
    ' SomeOtherCondition will never be evaluated
End If

If (False AndAlso SomeOtherCondition) Then
    ' SomeOtherCondition will never be evaluated
End If

These two simple additions provide VB.NET programmers with a convenience that has been taken for granted with other languages for years, and allows them to reduce the number of VB/VB.NET's syntactically bulky flow control statements.

Monday, 9 April 2007

A method for handling SIGWINCH in C++

Programs running in a terminal are notified of terminal resize events with the SIGWINCH signal. To catch and process such a signal, we use the signal(3) command, which accepts a function to be called when the signal is caught by the program:

void (*signal(int sig, void (*func)(int)))(int);

As noted here, the C++ standard (section 18.7/5) states that:

"All signal handlers shall have C linkage. A POF [Plain Old Function] that could be used as a signal handler in a conforming C program does not produce undefined behavior when used as a signal handler in a C++ program. The behavior of any other function used as a signal handler in a C++ program is implementation defined... In particular, a signal handler using exception handling is very likely to have problems."

Furthermore, section 1.9/9 states that:

"When the processing of the abstract machine is interrupted by a signal, the values of objects with type other than volatile sig_atomic_t are unspecified, and the value of any object not of volatile sig_atomic_t that is modified by the handler becomes undefined."

These two requirements severely limit our options for handling signals with modern C++ design techniques.

One solution I have identified involves using a single sig_atomic_t variable to be set by our POF signal handler, and to be polled periodically for change by our application's main loop. Here is an example static class (and associated POF handler) that can be polled for terminal size change:

extern "C"
{

volatile sig_atomic_t sigwinch_flag = 0;

void handle_sigwinch(int signal)
{
sigwinch_flag = 1;
}

} // extern "C"

class sigwinch_handler
{
public:

static bool caught_event()
{
return (sigwinch_flag != 0);
}

static bool reset()
{
sigwinch_flag = 0;
}

static void attach()
{
if (signal(SIGWINCH, &handle_sigwinch) == SIG_ERR)
throw new exception("Could not attach signal handler: " + string(strerror(errno)));
}

static void detach()
{
if (signal(SIGWINCH, SIG_DFL) == SIG_ERR)
throw new exception("Could not detach signal handler: " + string(strerror(errno)));
}

}; // class sigwinch_handler

Example usage:

// Main application loop.
void run()
{
// Attach SIGWINCH handler.
sigwinch_handler::attach();

for (;;)
{
// Poll keyboard and mouse events etc.

if (sigwinch_handler::caught_event())
{
// Handle new terminal size.
sigwinch_handler::reset();
}
}

// Detach SIGWINCH handler.
sigwinch_handler::detach();
}

You can read more about signal handling in C++ here.

Windows Integrated Authentication in ScrewTurn Wiki

ScrewTurn Wiki is a simple, open source wiki engine that reproduces much of the functionality found in Mediawiki. ScrewTurn Wiki is powered by ASP.NET 2 and Microsoft SQL Server, which makes it ideal for Windows-centric corporate environments. Unfortunately, ScrewTurn Wiki has no out-of-the box support for Windows Integrated Authentication (and, according to the developer, never will).

Windows Integrated Authentication allows users' credentials to be automatically passed to IIS. This allows the application (if it supports it) to use Windows login details - i.e., the same user name across an entire domain. The user is automatically and seamlessly logged in to the application - a huge benefit over having to remember multiple user names and passwords.

I have created a simple Windows Integrated Authentication implementation for ScrewTurn Wiki, similar to that used by Community Server (another ASP.NET/SQL Server-based collaboration tool). Note that ScrewTurn Wiki's Plugin Framework does not cater for extra functionality at this level (yet). When a new session is spawned on the web server, the application searches for an account matching the user's login name. If none is found, a new account is created automatically. Events are logged via the standard ScrewTurn Wiki event log.

Replace Session_Start in ScrewTurn Wiki's Global.asax with the following:

void Session_Start(object sender, EventArgs e) {
    // Code that runs when a new session is started
    ScrewTurn.Wiki.Users.OnlineUsers++;
    ScrewTurn.Wiki.SessionFacade.Breadcrumbs = new ScrewTurn.Wiki.BreadcrumbsManager();

    // Get identity name from web server.
    string identityName = System.Web.HttpContext.Current.User.Identity.Name;
    if (identityName == null || identityName.Length < 1)
        throw new System.ApplicationException("Could not get current Windows user name. Ensure Integrated Windows Authentication is enabled.");

    string username;

    // Strip domain prefix (e.g. "\\COMPANY.NET\DoeJ").
    int domainDelimOffset = identityName.IndexOf("\\");
    if (domainDelimOffset > 0)
        username = identityName.Substring(domainDelimOffset + 1);
    else
        username = identityName;

    if (username.Length < 1)
        throw new System.ApplicationException("Username " + identityName + " is empty after domain stripped.");

    // Locate user.
    ScrewTurn.Wiki.PluginFramework.UserInfo user = ScrewTurn.Wiki.Users.Instance.Find(username);

    if (user == null)
    {
        // User not found, add a new one.
        if (!ScrewTurn.Wiki.Users.Instance.AddUser(username, string.Empty, string.Empty, true, false, null))
            throw new System.ApplicationException("Could not add user \"" + username + "\".");

            // Get freshly-added user.
            user = ScrewTurn.Wiki.Users.Instance.Find(username);
            if (user == null)
                throw new System.ApplicationException("Could not find user \"" + username + "\".");
    }

    // Set up session.
    ScrewTurn.Wiki.SessionFacade.LoginKey = ScrewTurn.Wiki.Tools.ComputeSecuredUsernameHash(user.Username);
    ScrewTurn.Wiki.SessionFacade.Username = user.Username;
    ScrewTurn.Wiki.SessionFacade.Admin = user.Admin;

    // Log event.
    ScrewTurn.Wiki.Log.LogEntry("User " + ScrewTurn.Wiki.SessionFacade.Username + " logged in through Windows Integrated Authentication", ScrewTurn.Wiki.EntryType.General, "SYSTEM");
}

For more information about Windows Integrated Authentication and ScrewTurn Wiki (including comments on this implementation), see this thread at the ScrewTurn Wiki forum.

Sunday, 8 April 2007

Generating a Makefile from Xcode

Almost all open source software projects I have encountered rely on GNU Make as a build tool. Make is a tool available on many platforms (most notably Linux and UNIX) that manages the compilation and installation of software programs. A Makefile defines the location of source files and steps required to compile and link targets to create the executable program file.

Importing existing Make-based software projects into Apple's Xcode IDE is relatively easy; source files can be dragged and dropped into a Project, and Xcode will link and compile them automatically.

Unfortunately, porting Xcode Projects to other platforms is not so simple. While Xcode can integrate a Makefile as an External Build Target, it cannot export or create one. This functionality is granted with the use of a third party tool called PBTOMAKE. Note that Xcode was originally called Project Builder.

PBTOMAKE is a command line utility which creates a simple Makefile from an Xcode Project file. Integrating PBTOMAKE into an Xcode Project allows us to create a Makefile on the fly as part of the build process. Here's how:

  1. Download and install PBTOMAKE, so that the 'pbtomake' command is available to the current user.
  2. In Xcode, ensure all Project file reference paths are specified Relative to the Project.
  3. Right click on the relevant build Target, and add a New Run Script Build Phase. Enter the following command:
    pbtomake -i $PROJECT_NAME.xcodeproj -o path/to/Makefile
  4. Build your Project.

PBTOMAKE's default compiler is GCC. Use the -cc option to change compiler, and -bin_dir to specify an alternate output directory.

An example cross-platform command-line application written in C++ which links against OpenSSL's libraries would use the following Run Script Build Phase to generate a Makefile from within Xcode:

pbtomake -i $PROJECT_NAME.xcodeproj -o path/to/Makefile -link_opt "-lssl -lcrypto" -no_framework -cc g++ -bin_dir path/to/bin

This method allows us to create and maintain C and C++ projects in Xcode, while providing excellent cross-platform portability via GNU Make.