Ivan Krivyakov's Blog

Premature optimization is the root of all evil

September 30, 2010

MessageBoxes and worker threads

This will hopefully become a more organized article with code samples, but I need to record my results for now. Here’s the practical problem I encountered in the application I am wokring on: several message boxes initiated by worker threads would pop up simultaneously confusing the user and wrecking havoc.

So, the task is: you want to display a notification (message box) from a worker thread. Sometimes it is fire-and-forget, sometimes you want to know the answer (“Do you want to continue? Yes|No”). I will assume the answer is important, since this is case is more complicated.

Here are some facts that I discovered:

Fact #1: Dismissing a message box may enable the parent even if there are other pending message boxes. I am not sure what is the exact algorithm here, but if you have multiple message boxes on the screen, there is at least one of them that would re-enable the parent when dismissed. This will render all other message boxes effectively modeless. The user can continue to work on the parent and maybe even create more message boxes.

Fact #2: Calling MessageBox() from a worker thread effectively converts that thread to a UI thread with the message pump.

Fact #3: If the UI thread is blocked, MessageBox() will also block, even when called on a worker thread. The reason for that is that MessageBox() internally called DialogBox2() function in user32.dll, which calls NtUserCallHwndParamLock(). I am not sure what that function does, but it blocks if the UI thread does not respond.

Fact #4: If you use PostMessage (BeginInvoke) or SendMessage (Invoke) to render the message boxes on the UI thread, the message boxes can still appear in parallel. In fact, they become recursive. If you look at the call stack it looks like one message box calls another.

This happens because the parent window is not dead while showing a message box: it is just disabled. The message box runs its own message pump, and when another thread sends a message instructing the parent window to show another message box, it will be happily processed, showing the second message box on top of the first.

Bottom line: “serializing” message box calls via PostMessage/SendMessage to the UI thread does not work.

Fact #5. If the UI thread is blocked while we send it “show that message box” messages, the message boxes will appear in sequence, starting with the latest. This puzzled me for a while, but after some research I found the truth. The message boxes are still being called recursively, only they don’t have a chance to show. Showing a window is a complex process that requires handling multiple WM_ messages. When MessageBox() function is called and starts running the inner message loop, there is no window yet. It will appear a little bit later. However, the first message that is processed in the new loop is a request for another message box, which effectively defers creation of the window until later. Only the last message box in the chain has a chance to display itself. Once it is dismissed, previous message box(es) take turn.

September 27, 2010

CSV: Carelessly Saved Values

I currently work with some numeric methods that accept large quantities of data as inputs. Normally the input comes from a database. As I was writing the tests, I needed a suitable external format to represent relatively large quantities of data. CSV seemed like a natural choice, because it is widely used and supported by SQL Management Studio and Excel. However, I found CSV very inconvenient, for the following reasons:

- There is no standard way to export a data table to CSV. CSV files can be read by OLE DB Jet driver, but apparently this driver cannot create new tables/files. Google is full of samples on how to write to CSV files by hand.

- There is no standard data format. Should the data be included in quotes? How do you handles strings with embedded commas? What is the date format? Apparently, there is no such things as “CSV standard” and everyone does what they please.

- There is no type information. OLE DB driver can use schema.ini, but it is non-standard and cumbersome to work with. Also, it combines type information for multiple tables. Without explicit type information, OLE DB driver tries to “guess” the types, but often does it wrong. It seems that it looks at the first couple of dozen rows, and makes its decision based on that. If further rows are incompatible, they will suffer. The driver will either complain (“cannot convert string to integer”), or silently truncate doubles to ints, etc. , which is even worse.

- There is no null value. Empty strings are treated as NULLs on read, even if included in quotes. However, SQL Management Studio when exporting NULL values puts litereal NULL into the file, which is read back as string.

All this makes CSV format somewhat difficult to use – it is very hard to guarantee that the data read will be exactly equivalent (in type and value) to the data written. I gave up and switched to DataTable.WriteXml() and WriteXmlSchema(), but this leads to much bigger files and is not compatible with anything but .NET. I am still looking for an alternative.

September 14, 2010

.NET: Exception stack trace has no frames above the catch point

I never thought about it, but it turns out that exception’s stack trace does not contain the full stack. Instead, it contains only frames between the point where the exception was thrown and the point it is caught. This is bad if exception is caught close to the point of throwing and logged:

using System;

 

namespace ExceptionTrace

{

    class Program

    {

        void f1()

        {

            f2();

            f3();

        }

 

        void f2() { f4(); }

        void f3() { f4(); }

 

        void f4()

        {

            try { throw new Exception("Boo!"); }

            catch (Exception ex)

            {

                Console.WriteLine("Problem: " + ex); // stack trace contains only f4()

            }

        }

 

        static void Main(string[] args)

        {

            new Program().f1();

        }

    }

}

This prints:

Problem: System.Exception: Boo!
   at ExceptionTrace.Program.f4() in C:\Ivan\dev\exp\ExceptionTrace\Program.cs:line 18
Problem: System.Exception: Boo!
   at ExceptionTrace.Program.f4() in C:\Ivan\dev\exp\ExceptionTrace\Program.cs:line 18

Note that both stack traces are exactly identical and contain only one frame. The message does not say whether f4() was called from f2() or from f3(). This information can be obtained by calling new StackTrace() inside the catch, which returns the full stack, but this stack trace is not part of the exception.

If we rethrow the exception and let it travel up the call chain, its StackTrace will automatically grow to reflect additional frames, but it will never include the frames above the catching block.

September 1, 2010

RedGate SQL Source Control

Another tool I tried today. The idea is very cool, but I don’t like the fact that after I “link” the database I suddenly get gazillion changes to commit. I would think that “linking” means submitting current state to the DB.

Also, it is not clear how to get rid of the users and roles information, I don’t want it in source control.

RedGate SQL Compare

As per this survey, RedGate SQL Compare is one of the best SQL comparison tools on the market. I downloaded a trial today. It works fast, produces safe synchronization scripts wrapped in transaction, and is generally cool.

I did, however, stumble upon a stored procedure that it marked as “different”, although it could not show a single difference between two databases. Applying synchronization script once did not help, I need to apply it twice.