Previous Section   Next Section

Using P/Invoke to Call the MessageBox Function

With any new technology, it's best to start out small and work your way up. You're now going to expand on the project you've been working on this hour. As mentioned earlier, the first step is to use the DLLImport attribute. When applied to a function definition, the DLLImport attribute specifies which dynamic link library (DLL) the function you are referencing is contained within. In addition, there are several optional parameters for the attribute which control how that function is defined within your source code.

The first function you are going to use is the WIN32 API function MessageBox. Before you can create its signature, however, you need to know which DLL that function is contained within. There are two ways you can do this. The first way is to use the Dependency Walker tool, depends.exe. Using this tool, however, is cumbersome and slow because it involves manually opening a system DLL such as user32.dll or kernel32.dll and looking through the large list of exports to see whether the function you need is there. If it isn't, you must try a different DLL. Dependency Walker is a great tool, just not for this procedure. Figure 22.3 shows Dependency Walker with the MessageBox function highlighted.

Figure 22.3. Finding DLL functions using Dependency Walker.

graphics/22fig03.jpg

The easiest way to find which DLL contains the function you need is to use the MSDN documentation itself. Click Help, Index in the main menu. In the Look For field within the Index dialog, enter MessageBox function and click that phrase within the index result list. This will open the help documentation associated with the WIN32 API function MessageBox. Scroll down to the bottom of the document and you'll see a line that says the function is implemented in user32.lib. Because there is a user32.dll file, you can infer that user32.lib is linked into that library and therefore the MessageBox function is contained in user32.dll.

The first parameter for the DllImport attribute is the name of the DLL that contains the function you are interested in. Following that are a number of optional parameter attributes you can apply. These optional attribute parameters include the following:

After using the DLLImport attribute, you must then create a function signature for the function you wish to call. However, because you are working within managed code, the parameters to the function signature should be types that can be marshaled successfully from the managed data type to the unmanaged data type. Table 22.1 lists unmanaged data types and their equivalent managed data types.

Table 22.1. Unmanaged Data Types and the Equivalent Managed Types Used for Marshaling
Unmanaged Windows Type Unmanaged C Language Type Managed Class Name
HANDLE void* System.IntPtr
BYTE unsigned char System.Byte
SHORT Short System.Int16
WORD unsigned short System.UInt16
INT Int System.Int32
UINT unsigned int System.UInt32
LONG Long System.Int32
BOOL Long System.Int32
DWORD unsigned long System.UInt32
ULONG unsigned long System.UInt32
CHAR Char System.Char
LPSTR char* System.String or System.StringBuilder
LPCSTR Const char* System.String or System.StringBuilder
LPWSTR wchar_t* System.String or System.StringBuilder
LPCWSTR Const wchar_t* System.String or System.StringBuilder
FLOAT Float System.Single
DOUBLE Double System.Double

The process of creating a function signature is similar to declaring any other function. However, because the function is not implemented in your assembly, the extern keyword must precede the actual definition. Before you add the code to define the MessageBox function contained within user32.dll, import the System::Runtime::InteropServices namespace. Next, define the MessageBox function by first creating the DllImport attribute and then creating the function definition with the equivalent managed data types. This is done as follows:

[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet::Ansi)]
extern int MessageBoxA(void* hWnd,
                        String* pText,
                        String* pCaption,
                       unsigned int uType);

Within the SayHello function contained in the CSystemTime class, call the MessageBoxA function you just defined:

MessageBoxA( 0, "Hello World", "CSystemTime", 0 );

Compile and run your application. If everything has worked correctly, you will see a message box similar to the one shown in Figure 22.4.

Figure 22.4. Invoking the MessageBox function contained within user32.dll.

graphics/22fig04.jpg


  Previous Section   Next Section
Top