< Day Day Up > |
21.10 Calling Native Unmanaged Code Using PInvoke
TechniqueTo call unmanaged code using the PInvoke mechanism, you follow these steps:
For example, suppose you are doing some graphics processing and you need to create a memory device context compatible with the screen. You normally use the Windows API function CreateCompatibleDC() , defined in the file gdi32.dll . This function has the following unmanaged C++ signature: HDC CreateCompatibleDC(HDC hdc); Here, HDC is simply a typedef for a 32-bit integer used as a handle. Good managed programming practice normally suggests we use a System.IntPtr instance to represent 32-bit integers that are intended to be used as Windows handles. Hence, a suitable managed wrapper definition follows : class ClassThatDoesGraphicsProcessing { [DllImport("gdi32.dll")] static extern IntPtr CreateCompatibleDC(IntPtr hdc); You can now call the method as if it were a normal static class method. The following code shows this move and also includes the supporting (managed) code to create and release the screen device context to be passed to CreateCompatibleDC() : // get a screen device context // we assume this code is in a Windows.Forms.Control-derived class, hence // we can call Control.CreateGraphics(). Graphics g = this.CreateGraphics(); IntPtr hdcScreen = g.GetHdc(); // get a memory device context IntPtr hdcMemory = CreateCompatibleDC(hdcScreen); // other code to use the device context g.ReleaseHdc(hdcScreen); CommentsIn general, the hardest part of using PInvoke to call an unmanaged function is the choice of parameter type. Using an inappropriate type can decrease performance, but in general, you will find that the type you intuitively expect is often the most appropriate type. For example, if an unmanaged function expects a C-style string, then pass in String . If it expects a 16-bit integer, then pass in short or ushort , depending on how the integer is best interpreted in the managed code. For a 32-bit integer, pass in int , uint , or IntPtr , again depending on which one represents the most appropriate usage of the value. Notice that in many cases there is no one correct type: It is a question of what the most appropriate type is depending on the purpose of the parameter. In these cases, choosing an inappropriate type will not cause any bugs but will make your code harder to understand. Although the security risks are similar for unsafe code and unmanaged code, the two types of code are conceptually very different. There is no need to use the unsafe C# statement or /unsafe compiler option to invoke unmanaged code. Your code will, however, need the unmanaged code security permission to execute. The PInvoke wrapper functions are always declared as static members of a class. This step is not actually a requirement of the CLR, which simply requires a non-instance function, but is necessary because C# does not support global functions. |
< Day Day Up > |