Nov 292009
 

In the last post, we saw how the Message Loop in Windows works, with Windows constantly getting messages from the various events and dispatching them to correct window procedures. The Window Procedure then takes the message and it is responsible for handling the event. This handling of the message is done in the callback method WndProc. Most of them times the default processing is done by calling the DefWindowProc method, but it is left to the procedure which can override any messages it wants.

Since its message based all windows can talk to each other using these messages and pass commands. An extremely useful feature which means your .NET application can communicate with your C application and send it commands as well. I tried to get a C application to display a message box triggered from a .NET application and then bring it to top.

First we need to write the C application to display a simple window which has a Hello World message. I will post just the relevant code here.

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc ;
	PAINTSTRUCT ps ;
	RECT rect ;
	switch (message)
	{
		case WM_PAINT:
			hdc = BeginPaint (hwnd, &ps) ;
			GetClientRect (hwnd, &rect) ;
			DrawText (hdc, TEXT ("Hello World"), -1, &rect,
			DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
			EndPaint (hwnd, &ps) ;
			return 0 ;
		case WM_USER:
			MessageBox (NULL, TEXT (".NET App Says Hello"), TEXT(".NET"), 0) ;
			return 0 ;
		case WM_DESTROY:
			PostQuitMessage (0) ;
			return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

Along with the rest of the plumbing code, this will draw a window on the screen with the text “Hello World” written in the center. It behaves like any other normal window where you can resize it, maximize or minimize it etcetera.

CApplicationWindow

If you see in the WndProc code there are three messages being intercepted. All others will be handled as default. One is the WM_PAINT, which is responsible for drawing the window and the text written in the center. The last one is WM_DESTROY which is called when the user closes the window. The WM_USER is of our interest. All we did is call another API function MessageBox which displays a message box with the text “.NET App says Hello” and the title “.NET”. Now the idea is to call this message from our .NET application

In our .NET Application we will pass the message to the Hello World window and make it the Active Window. To do this, a handle to the window is needed. Handles are nothing but an integer which Windows (OS) uses to uniquely identify each window. Think of it as something like a pointer to the window we want to modify or retrieve information about. In .NET the IntPtr class can be used in place of a Handle to a window. From .NET 2.0 onwards, the SafeHandle can be used to do the same thing and is more reliable. Getting a handle is done through the FindWindow API call. Then using the handle, the window is sent a message and brought to the foreground. The Pinvoke declarations are:-

[DllImport("user32.dll", SetLastError = true)]
   static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

   [DllImport("user32.dll")]
   [return: MarshalAs(UnmanagedType.Bool)]
   static extern bool SetForegroundWindow(IntPtr hWnd);

   [DllImport("user32.dll", CharSet = CharSet.Auto)]
   static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

As you can see the FindWindow takes in strings the class name and the Window name. The class name and the Window name are used while calling the RegisterClass WIN32 function. Since we do this manually for C we know these values. There is no way in .NET to get the WIN 32 class name for a window. We need to use the GetClassName function for doing that.

So in .NET we first get the IntPtr handle to the C application window, and then check if its a valid window handle. If so we send a message WM_USER to the application. This WM_USER is defined as a constant in .NET. “C” however is aware of all these constants. After sending the WM_USER , we set the window as foreground by calling the SetForegroundWindow and passing the handle to it. The code is given below.

public const int WM_USER = 0X400;
static void Main(string[] args)
{
    IntPtr _CWindowHandle = FindWindow("HelloWin", "The Hello Program");

    if (_CWindowHandle.ToInt32() != 0)
    {
        SendMessage(_CWindowHandle, WM_USER, IntPtr.Zero, IntPtr.Zero);

        SetForegroundWindow(_CWindowHandle);
    }
}

So run the C program first and leave it as such. Now run the .NET application and it will work. The message box (written in the C Program) will be triggered from the .NET application and once you click on it, the window will automatically come to the foreground. Of course this is just a trivial functionality that we just implemented. A lot more complex things can be achieved once you start playing around with it.

MessageBox

SetForegroundWindow

Nov 282009
 

From an end user point of view, your application UI is the single most important part of your application. There may be a million lines of code in the business layer doing all sorts of magic, but try giving a unresponsive UI with it, and no guessing, how many takers you will find for your application. So a lot of thinking goes into how to keep the UI always responding to the user’s actions and conveying that processing is being done.

A very common piece of code which I have observed is the call to the method Application.DoEvents() in some long running iterations to update the UI if there is some long running operation in the background. This could be a control like the ProgressBar or the Form Itself. So even when the UI is moved around or dragged below and above other windows, it always manages to redraw itself. Application.DoEvents is certainly not the only way to do this, nor the best either. Some common alternatives are using a BackgroundWorker, or write your own threading logic. But given the choice of writing threading, its natural that quite a few developers would be inclined to use DoEvents which does the same work with just one line of code.

Here is some sample code for Application.DoEvents

string[] _strarray = Directory.GetDirectories("Path with a lot of files");
          foreach (string _tempString in _strarray)
          {
              string[] _fileArray = Directory.GetFiles(_tempString, "*", SearchOption.AllDirectories);
              foreach (string _fileString in _fileArray)
              {
                  listBox1.Items.Add(_fileString);
                  Application.DoEvents();
              }
          }

This code works great and makes the UI completely responsive irrespective of the background function running. How does this work? Windows apps are event driven. They respond to mouse moves, clicks and various events. Whenever the window is moved, windows detects that the Client area is invalidated so it has to be redrawn. So how do so many windows talk to each other and make sure they process all the events? A Message Queue is where all the messages are queued up so they can be processed one by one. This is how they are processed

   while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 )
   {
      if (bRet == -1)
      {
         // handle the error and possibly exit
      }
      else
      {
         TranslateMessage( &msg );
         DispatchMessage( &msg );
      }
   }

As you can see Windows continuously looks for Messages in the queue, the moment it finds one, it enters the loop and checks if any error was thrown, if not the message is translated and dispatched to the right window procedure. When one message is being processed, the others like WM_PAINT to redraw your UI, since these messages are waiting for your long operation to complete, the form stops responding and you get the irritating ghost window.

notRespondingh

So What does Application.DoEvents() actually do? It takes the remaining events which are still waiting and processes them. This include the WM_PAINT messages which are waiting to update your UI. So your applications seems much more responsive, all with 2 lines of code. Great, so why use BackgroundWorkers or Threading when Application.DoEvents does your job. Because Application.DoEvents doesnt really limit itself to the WM_PAINT messages, it tries to clear up the whole queue. This can lead to unpredictable results. For e.g. the user might again trigger the long running operation leading to a deadlock for resources. Such errors might be hard to trace out and debug as well.

So something that looks easier in the long run might end up costing you more effort. So where do we use Application.DoEvents()? The method isn’t deprecated yet, so Microsoft doesn’t consider it all that bad, as long as the programmer knows that he is taking a risk. It might be great for prototyping your application for customer demos, where you only care about functionality. But in production code, its best to write out your own threading logic or atleast a BackgroundWorker component, especially in cases where you are accessing resources that have locks, for e.g. editing a file which is already open.