Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Dealing with DllImport, (Part 2 of 2)  : Page 3

Learn how to use the DllAttribute's MarshalAs and StructLayout options to interoperate with unmanaged code that uses structures, and to control data layouts and marshalling precisely.


advertisement
The Win32 API makes heavy use of callback functions when enumerating Windows or registry items for example. That raises the question of how you can use callbacks from native code into managed code without function pointers? Fortunately, that has not been overlooked.

In the .NET Framework, delegates serve the role of function pointers, but in a type-safe way. The Platform Invoke machinery knows how to convert managed delegates to function pointers that can be used by unmanaged code. In addition, the machinery knows that it should pin managed buffers (keep them fixed in a particular memory location) for the duration of a call to unmanaged code.

Consider the EnumWindows Win32 API function:

BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)

In that function, lpEnumFunc is a pointer for the callback function, which wants two arguments, a Window handle and a long parameter (lParam), both of which correspond to managed integers. To create a delegate, you need to match the callback parameter types. A delegate for a callback function with this signature would look like this:

delegate bool CallBack(int hwnd, int lParam);

After defining the delegate, you can use it in the definition of a DLLImport prototype for EnumWindows:



DllImport("user32")] static extern int EnumWindows(CallBack x, int y);

At runtime, you need to create an instance of the delegate before passing it to the wrapped Win32 API:

CallBack myCallBack = new CallBack(ListTitle); EnumWindows(myCallBack, 0);

Now you just have to implement the managed callback function, called ListTitle in this case. Its job is to get and print out the caption of each window enumerated, which gives you a rather raw indication of the currently running applications. The callback function receives the handle of each enumerated window and can use that to find the window caption using another Win32 API, GetWindowText. If there's a managed equivalent of GetWindowText, I don't know about it, but I do know how to write its DllImport wrapper. Its unmanaged signature is:

int GetWindowText( HWND hWnd, // handle to window or control LPTSTR lpString, // text buffer int nMaxCount // max characters to copy );

So you can write an import wrapper for it as

[DllImport("user32")] static extern int GetWindowText( int hWnd, //handle to window or control StringBuilder lpString, //text buffer int nMaxCount //maximum number of characters to copy );

With that in place, the callback function implementation is trivial:

static bool ListTitle(int hWnd, int lParam) { StringBuilder buf=new StringBuilder(100); if ( GetWindowText(hWnd, buf, 100)==0 ) return true; Console.WriteLine(buf); return true; }

Altogether, the code looks like this:

using System; using System.Runtime.InteropServices; using System.Text; namespace RunningApps { /// <summary> /// Obtain and display running applications by /// enumerating windows /// </summary> class Class1 { public delegate bool CallBack(int hwnd, int lParam); [DllImport("user32")] public static extern int EnumWindows( CallBack x, int y); [DllImport("user32")] public static extern int GetWindowText( int hWnd, // handle to window or control StringBuilder lpString, // text buffer int nMaxCount // max characters to copy ); /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { CallBack myCallBack = new CallBack(ListTitle); EnumWindows(myCallBack, 0); } public static bool ListTitle( int hWnd, int lParam) { StringBuilder buf=new StringBuilder(100); if ( GetWindowText(hWnd, buf, 100)==0 ) return true; Console.WriteLine(buf); return true; } } }

When you run this code, you'll see a list all the current windows in the system—both visible and invisible. You may be surprised at what shows up, especially if you're running a complicated application such as Visual Studio .NET at the time!

While many other subtleties can crop up when you try to import unmanaged code, you've covered the most common issues. You know enough now to write you own DLLImport statements, and most importantly, you know that you should look for equivalent classes in the .NET Framework before you go to the trouble of importing a Win32 API function.



Martin Heller is a Web and Windows programming consultant, an author, and a Senior Contributing Editor at BYTE.com. His most recent publicly viewable project is PC Pitstop. You can reach Martin at webmail@mheller.com.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap