Changing Network Name (Etc.)

Illustration

As I was playing with my wireless router, I noticed that Windows started referring to my text network with number two (2) in suffix. Each visit to Network and Sharing center resulted in annoyance since my good old MedvedAlt network was now named MedvedAlt 2 without any obvious way to change it.

We start adventure by entering gpedit.msc to Windows start menu. This will open Local Group Policy Editor in which we have to navigate to Computer Configuration, Windows Settings, Security Settings, Network List Manager Policies. There we can see our network in all its glory. All that is left at this point is to go into Properties and change Name setting from Not configured to whatever name we prefer.

TextBox With a Cue

Illustration

On web it became very popular to have gray, watermarked, text that offers a cue for filling out a field. As you start writing, cue disappears.

For a while now, Windows have full support of this feature. However, Windows Forms in .NET framework are bit behind. Fortunately implementing this feature is not really hard. All we need is property (e.g. CueText) in a class inherited from TextBox.

Setting value is done by sending a EM_SETCUEBANNER message to TextBox:

NativeMethods.SendMessage(this.Handle,
                          EM_SETCUEBANNER,
                          new IntPtr(1),
                          new StringBuilder(value));

There is no need to check this function for success. If visual styles are turned on, it will not fail. And even if it fails, there is not a thing we can do to fix it. Ignoring result code is as good solution as any.

Retrieving value via EM_GETCUEBANNER is a bit more involved:

var text = new StringBuilder(256);
var res = NativeMethods.SendMessage(this.Handle,
                                    EM_GETCUEBANNER,
                                    text,
                                    new IntPtr(text.Capacity));
if (res.ToInt64() != 0) {
    return text.ToString();
} else {
    return null;
}

This time check for valid result is warranted. If result is good, string will be returned. Otherwise, null gets to mess things up.

These few lines (along with Interop definitions) are all that is needed for this useful functionality.

Sample project is available for download.

Multi-statement Conditions in PostgreSQL

Conditions are really easy in SQL Server. Simple IF at the top and multiple SQL statements in the middle:

IF (SELECT Foo FROM Test WHERE Bar='X') = 42
BEGIN
    DROP TABLE Some;
    CREATE TABLE Some(Thing INT);
END

Unfortunately this is not a standard SQL feature so you cannot count on other databases having it implemented in same manner. One database that does not really support this is PostgreSQL. No matter how you do it, you cannot use pure SQL for conditional execution of multiple SQL statements.

What we can do is fake it:

CREATE OR REPLACE FUNCTION TEMPSQL() RETURNS INT AS '
    DROP TABLE Some;
    CREATE TABLE Some(Thing INT);
    SELECT 0;
' LANGUAGE SQL VOLATILE;

SELECT Foo,
    CASE Foo WHEN 42 THEN
        TEMPSQL()
    END
    FROM Test WHERE Bar='X';

DROP FUNCTION TEMPSQL();

All SQL statements sit inside of a function and condition is modified to use standard SQL 92 CASE statement. SELECT will trigger execution of TEMPSQL function every time Foo is equal to 42.

Notice that this means there should be nothing in function that prevents it from being called more than once. Alternative is to do condition (Bar='X') on field that is unique or just adding LIMIT 1 to statement.

PS: For homework, check why function has INT for return type instead of more logical VOID.

UTC Time in PostgreSQL

If you are dealing with multiple different clients, each with its own clock, it pays of to have central time-keeping device. And, if your program uses Microsoft SQL Server, you can use its GETUTCDATE() function to retrieve current server time:

GETUTCDATE() function is ideal for this purpose. It returns UTC time so you don’t need to worry about time zones and daylight-saving time. Your database and programs can keep time in UTC. Conversion to local time is done only when displaying data to user.

You can get current time either by doing SELECT query or by inserting time directly into database:

SELECT GETUTCDATE();
INSERT INTO Foo(Bar) VALUES(GETUTCDATE());

However, this function is very SQL Server specific. For example, you will not find it in PostgreSQL. Yes, I know that there are other functions that can do the same. But this means that your application needs to do one query for SQL Server and another for PostgreSQL. It would be fantastic if same function could be used in both databases.

Well, you can. Only thing we need is a new function:

CREATE OR REPLACE FUNCTION GETUTCDATE() RETURNS TIMESTAMP AS '
    SELECT CAST(LOCALTIMESTAMP AT TIME ZONE ''UTC'' AS TIMESTAMP);
' LANGUAGE SQL VOLATILE;

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.