Platform Invoke Wrapper Example
If a structure contains simple types, it can be passed to a native function. The native routine must conform to how the .NET Compact Framework packs the structure.
Consider a native function called DoRequest
that takes one parameter, a pointer to a structure. The structure defines two fields:
A character array containing a NULL terminated ANSI string.
An integer.
Here is the structure in C++:
typedef struct
{
char *RequestName,
int Count,
} ALERT_REQUEST;
int DoAlertRequest(ALERT_REQUEST *pRequest);
Its corresponding managed version in C# is:
struct AlertRequest
{
String RequestName;
int Count;
}
class AlertClass
{
[DLLImport("ALERT.DLL", EntryPoint="DoAlertRequest",
CharSet=CharacterSet.Ansi)]
public static extern int DoRequest(ref AlertRequest Req);
}
The DllImportAttribute attribute annotates the metadata of the native method call. It notifies the common language runtime that the DoRequest
method is in ALERT.DLL, that the name of the method is DoAllertRequest
, and to marshal strings to ANSI because all strings in managed code are Unicode strings.
A call to this method in C++ in the .NET Framework might look like this:
AlertRequest Request = new AlertRequest()
Request.RequestName = "beep";
Request.Count = 10;
AlertClass.DoRequest(ref Request);
When the .NET Framework's common language runtime encounters the DoRequest
, call it dynamically loads ALERT.DLL, gets the address of DoAlertRequest
, builds an unmanaged version of the structure converting strings as needed, pushes a pointer to this structure, and calls DoAlertRequest
. It cannot just pass a pointer to the structure because it contains an embedded String object.
Given these constraints, the native DoRequest
method cannot be called directly. Instead, an intermediate thunking call must wrap DoRequest
. The following C# code is an example:
class AlertClass
{
[DllImport("ALERT.DLL", EntryPoint="DoAlertRequestThunk")]
private static extern int DoRequestThunk(String RequestName, int Count);
public static int DoRequest(ref AlertRequst Req)
{
return DoRequestThunk(Req.RequestName, Req.Count);
}
}
AlertClass
still contains a method with the same signature as its counterpart on the .NET Framework. The .NET Compact Framework DoRequest
is a managed routine that calls a private native routine. Notice that the fields of the structure have been broken out into separate argument in the call to the native routine because the String object within the structure would not be marshaled. The thunk wraps the native DoRequest
. It builds an unmanaged version of the structure and performs the string conversion, as shown here in C++:
int DoRequestThunk(wchar_t *RequestNameW, int Count)
{
ALERT_REQUEST Req;
int ReturnCode;
// CreateAnsiFromUnicodeString allocates and builds an ANSI
// version of the Unicode string.
Req.RequestName = CreateAnsiFromUnicodeString(RequestNameW);
if (Req.RequestName == NULL)
Return 0;
Req.Count = Count;
// This is the native DoRequest, not to be confused
// with the managed method of the same name.
ReturnCode = DoAlertRequest(&Req);
free(Req.RequestName)
return ReturnCode;
}