Error! The Operation Completed Successfully.

Illustration

Most applications add error handling as an afterthought. There is just cursory testing and application goes out in the wild. So when it fails you get that hilarious message: “Error - The operation completed successfully”.

It is very easy to laugh at such oversight but most users have no idea how easy is to make a such mistake when you deal with Win32 API. Yes, it is time for excuses.

Let’s imagine simplest scenario - deleting a file. And .NET has no such function (imagination is a key) so we go down Win32 route. First step is to define DeleteFile in C#:

private static class NativeMethods {
    [DllImport("kernel32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern Boolean DeleteFile(
                                            [In()]
                                            [MarshalAs(UnmanagedType.LPWStr)]
                                            String lpFileName
                                           );
}

To use it we just put some boilerplate code:

try {
    if (!(NativeMethods.DeleteFile("MissingFile.txt"))) {
        throw new Win32Exception();
    }
} catch (Win32Exception ex) {
    MessageBox.Show(this, ex.Message);
}

Idea is simple. If DeleteFile fails we just throw Win32Exception to grab what was the error. All that we have to do is to show message to user. And you have guessed it - this will result in dreadful error “The operation completed successfully”.

Our error lies in definition. DllImport is just missing one small detail. We haven’t told it to collect last error code for us:

[DllImport("kernel32.dll", SetLastError = true)]

This is an oversight that is extremely easy to make. Worse still, exception still happens. Code does work properly. It is just an error message that fails. Whatever you do in your automated testing, chances are that you are not checking exception text (nor should you).

And you cannot just sprinkle your DllImports with SetLastError because some functions (yes, I am looking at you SHFileOperation) don’t use it at all. Let’s face it, you will probably only catch this when you hear your customer’s laugh.

Broken example is available for download.