The following code enumerates and prints out the captions of all the windows in the system: -
using System; using System.Runtime.InteropServices; using System.Text; class CallbackApp { [DllImport("user32.dll")] static extern int GetWindowText(int hWnd, StringBuilder text, int count); delegate bool CallbackDef(int hWnd, int lParam); [DllImport("user32.dll")] static extern int EnumWindows (CallbackDef callback, int lParam); static bool PrintWindow(int hWnd, int lParam) { StringBuilder text = new StringBuilder(255); GetWindowText(hWnd, text, 255); Console.WriteLine("Window caption: {0}", text); return true; } static void Main() { CallbackDef callback = new CallbackDef(PrintWindow); EnumWindows(callback, 0); } }
First I define the Win32 functions EnumWindows and GetWindowText by using the DllImport attribute. I then define a delegate called CallbackDef and a method named PrintWindows. After that all I need to do in Main is instantiate the CallbackDef delegate (passing to it the PrintWindows method) and call the EnumWindows method. For each window found in the system, Windows will call the PrintWindows method.
The PrintWindows method is interesting because it uses the StringBuilder class to create a fixed-length string that is passed to the GetWindowText function. This is why the GetWindowText function is defined as follows: -
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
Anyway, the reason for all this is that the DLL function is not permitted to alter a string, so you can't use that type. And even if you attempt to pass by reference, there's no way for the calling code to initialize a string to the correct size. That's where the StringBuilder class comes in. A StringBuilder object can be dereferenced and modified by the called function, as long as the length of the text does not exceed the maximum length passed to the StringBuilder constructor.