Understanding Platform Invoke Services


Platform Invocation Services (PInvoke) provide a link between managed and unmanaged code by allowing managed applications that are written using .NET languages, to call unmanaged, C-style functions exposed by Win32 APIs or other DLLs. PInvoke locates the exported unmanaged function, invokes it, and marshals its arguments across the boundary of managed and unmanaged code at runtime. To achieve this, PInvoke uses the information stored in the metadata. The .NET runtime automatically handles marshaling of data. As a result, you need not use PInvoke unless you want customized data marshaling. This means marshaling the types that do not correspond to char, string, and struct types. PInvoke simplifies customized data marshaling by allowing you to declare the marshaling information in attributes instead of explicitly coding the marshaling procedure.

When a managed application calls an unmanaged function, PInvoke executes the following steps:

  1. Locates the DLL that contains the exported unmanaged function.

  2. Loads the DLL in the memory.

  3. Locates the address of the unmanaged function in the memory, invokes the function with marshaled arguments, and pushes the arguments on the stack.

  4. Transfers control to the unmanaged function.

  5. Passes exceptions, if any, raised by the unmanaged code to the managed code, after wrapping the unmanaged exceptions as managed exceptions.

Note

The location and subsequent loading of the DLL and the unmanaged function in the memory takes place only during the first invocation of the function. Subsequent calls to the function use the memory-resident DLL.

To use an unmanaged function from managed code, you need to know the name of the function and the DLL in which the function resides. If you know these, you can include a declaration of the unmanaged function in the managed code. This declaration is different for all languages. In managed C++ extensions, you use the DllImport attribute to declare the unmanaged function. In addition, the unmanaged function needs to be marked with the extern C construct to indicate to the compiler that the definition of the function is included in an external file and will not be defined in the managed code. This extern C also states that the compiler needs to use the C calling convention. The following code shows an example of the use of the DllImport attribute in managed extensions:

 [DllImport("employee.dll", EntryPoint="CopyFileA",  SetLastError=true, CharSet=CharSet.Ansicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] extern "C" int CalculateBonus(String *); 

The above code uses the DllImport attribute to declare the unmanaged function, CalculateBonus(), which resides in the employee.dll file.

Table 6-1 lists the parameters associated with the DllImport attribute along with their descriptions:

Table 6-1: DllImport Attribute Parameters

Name of the Parameter

Description

BestFitMapping

Enables or disables the marshaler to find a best-fit mapping between ANSI and Unicode characters. Defaults to True.

CallingConvention

Indicates the calling convention of the DLL entry point. Defaults to the StdCall convention.

CharSet

Indicates how to marshal string arguments and the entry point name to choose when both ANSI and Unicode versions are available. Defaults to Charset.Auto.

EntryPoint

States the name or ordinal value of the called DLL entry point. If not specified, the DLL uses the function marked with the DllImport attribute as the entry point.

ExactSpelling

Controls whether or not the .NET runtime looks for an entry-point other than the one specified. Default settings depend on the programming language and the value of the CharSet field.

PreserveSig

States whether or not to preserve function signature at the time of conversion. Defaults to true.

SetLastError

Indicates whether or not the called method calls Win32 SetLastError API function. To retrieve the error value, you can use Marshal.GetLastWin32Error. Defaults to false.

ThrowOnUnmappableChar

Throws an exception when it encounters an unmappable character, if enabled. If disabled, replaces the unmappable characters by an ANSI question mark (?). Defaults to false.

Listing 6-10 shows a Win32 DLL that exports an unmanaged function:

Listing 6-10: Using Message.dll

start example
 #include<iostream>  using namespace std;  extern "C" __declspec(dllexport) void __stdcall showMessage(char *str)  {    cout<<"In the unmanaged function"<<endl;     cout<<str<<endl;  } 
end example

The above listing defines the Message.dll file that exports the showMessage() function using the __declspec(dllexport) keyword. The showMessage() function shows the string argument passed to it on the command prompt. To export a function, you also need to include a .def file in your VC++ project, which states the names of the exported functions. This text file is shown in the following code:

The Message.def File

 LIBRARY message EXPORTS showMessage @1 

Listing 6-11 shows a VC++.NET application written using managed extensions. This application calls the exported unmanaged function, showMessage() of Listing 6-10, using PInvoke:

Listing 6-11: Using PInvoke in Managed Extensions

start example
 #include "stdafx.h" #using <mscorlib.dll> using namespace System; using namespace System::Runtime::InteropServices;  __gc class ManagedClass {    public:     [DllImportAttribute("Message.dll")] static void showMessage(char *str);    };  __delegate void CallShowMessage(char *);  int main(void)  {    ManagedClass *pm = new ManagedClass();     pm->showMessage("Calling Unmanaged function from Managed Code using PInvoke");    CallShowMessage *pDelegate = new CallShowMessage(pm,& ManagedClass::showMessage);     pDelegate->Invoke("Testing PInvoke Using Delegates");    return 0;  } 
end example

The above listing calls the unmanaged method, showMessage() defined in Message.dll, directly using an instance of the managed class and using delegates. The ManagedClass class acts as a wrapper around the showMessage() method. You need to declare a prototype for the showMessage() method in the ManagedClass class using the DllImport attribute. In addition, the unmanaged method that you want to call using PInvoke needs to be declared as static.




Migrating Unmanaged Applications to. NET
Migrating Unmanaged Applications to. NET
ISBN: N/A
EAN: N/A
Year: 2004
Pages: 31

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net