Marshalling Simple Structures

The .NET Compact Framework can marshal simple structures between the managed and native worlds. Unlike the full desktop .NET Framework, there are strong restrictions governing what kinds of structures can be marshalled automatically.

First, the .NET Compact Framework marshals all simple structures by reference. Thus, the native side sees parameters that are structures as pointers to the structure. As such, the native code can alter the contents of structures, and the alterations are visible as side effects on the managed side.

Another important rule is that only references to “shallow” structures can be marshalled automatically. This means that the structure can contain an arbitrary number of fundamental data types, as described in previous sections, but the structure cannot contain strings or nested structures. For example, the first structure shown below can be marshalled automatically, but the second cannot.

The following is a structure that can be automatically marshalled:

C#
public struct MarshallableStruct
{
   public int m_Int;
   public char m_Char;
   public Int32 m_DWORD;
   public bool m_Bool;
}

VB
Public Structure MarshallableStruct
   Public m_Int As Integer
   Public m_Char As Char
   Public m_DWORD As Int32
   Public m_Bool As Boolean
End Structure

The following is a structure that cannot be automatically marshalled:

C#
public struct NestedStruct
{
   public int m_Int;
   public char m_Char;
}

public struct CannotAutoMarshal
{
   public int m_Int;
   public NestedStruct m_Nested;
   public Int32 m_DWORD;
   public bool m_Bool;
}

VB
Public Structure NestedStruct
   Public m_Int As Integer
   Public m_Char As Char
End Structure

Public Structure CannotAutoMarshal
   Public m_Int As Integer
   Public m_Nested As NestedStruct
   Public m_DWORD As Int32
   Public m_Bool As Boolean
End Structure

Complex structures that cannot be marshalled automatically and structures with strings in them can be passed to native code, but doing so requires manual marshalling. The next section describes how to do manual marshalling.

Once you understand the rules, passing shallow structures into native code is not significantly different from passing fundamental data types into native code. You need to declare the native function that is passed the structure. You also need to create a structure in managed code that has a compatible layout to the structure you create in native code. For example, if your managed structure is composed of two Int32 values, then you also need a structure that houses two 32-bit integers on the native side.

The code in Listing 12.4 is derived from the MarshalShallowStruct sample application. It shows the structure and method declarations in C# and Visual Basic to set up for a call to a native C function called ManipulateStruct. It also shows the corresponding C code for the ManipulateStruct.

Listing 12.4. Structure and method declarations in C# and Visual Basic to set up for a call to a native C function called ManipulateStruct
C#
// Structure declaration
public struct ShallowStruct
{
   public int m_Int;
   public char m_Char;
   public Int32 m_DWORD;
   public bool m_Bool;
}

// Method declaration
// Method invocation on native function
// Set up input...
ShallowStruct in_Struct = new ShallowStruct();
in_Struct.m_Int = Convert.ToInt32(4);
in_Struct.m_Char = Convert.ToChar('C'),
in_Struct.m_DWORD = Convert.ToInt32(4434);
in_Struct.m_Bool = true;
ShallowStruct out_Struct = new ShallowStruct();
// Call native function
ManipulateStruct(ref in_Struct, ref out_Struct);
// out_Struct has been altered by the native code implementation
// of ManipulateStruct

VB
' Structure declaration
Public Structure ShallowStruct
   Public m_Int As Integer
   Public m_Char As Char
   Public m_DWORD As Int32
   Public m_Bool As Boolean
   End Structure

' Method declaration
Declare Sub ManipulateStruct Lib "ManipulateStruct.dll" (ByRef
        in_ShallowStruct As ShallowStruct,
        ByRef out_ShallowStruct As ShallowStruct)

' Method invocation on native function
' Set up input...
Dim in_Struct As ShallowStruct = New ShallowStruct
in_Struct.m_Int = Convert.ToInt32(4)
in_Struct.m_Char = Convert.ToChar("C")
in_Struct.m_DWORD = Convert.ToInt32(4434)
in_Struct.m_Bool = True
Dim out_Struct As ShallowStruct = New ShallowStruct

' Call native function
ManipulateStruct(in_Struct, out_Struct)
' out_Struct has been altered by the native code implementation
' of ManipulateStruct

Native C implementation for ManipulateStruct
/* Structure declaration */
struct ShallowStruct
{
   int    m_Int;
   char   m_Char;
   DWORD  m_DWORD;
   bool   m_Bool;
};

/* ManipulateStruct function implementation */
void __cdecl ManipulateStruct(ShallowStruct * in_ShallowStruct,
        ShallowStruct * out_ShallowStruct)
{
   out_ShallowStruct->m_Int   = in_ShallowStruct->m_Int + 1;
   out_ShallowStruct->m_Char  = in_ShallowStruct->m_Char + 1;
   out_ShallowStruct->m_DWORD = in_ShallowStruct->m_DWORD + 1;
   out_ShallowStruct->m_Bool  = (in_ShallowStruct->m_Bool !=
           true);
}

Marshalling Shallow Structures with the MarshalShallowStruct Sample Application

The MarshalShallowStruct sample application demonstrates an end-to-end scenario for calling a native function and passing automatically marshalled shallow structures as parameters. The sample application is located in the folder SampleApplicationsChapter12. There are C# and Visual Basic versions.

MarshalShallowStruct uses a native DLL, ManipulateStruct.dll. The source code for this DLL is in the folder SampleApplicationsChapter12NativeBinariesManipulateStruct. Just like the SquareAnInt sample application, there are also pre-compiled DLL binaries in the SampleApplicationsChapter12NativeBinariesManipulateStruct directory. Each binary is in its own subdirectory according to the hardware and operating system for which the DLL was built.

To use the MarshalShallowStruct application, build and deploy the managed project to your device. Then copy the appropriate ManipulateStruct.dll library to your device, either to the Windows directory or the directory where the managed executable, ManipulateStruct.exe, resides. You can now launch the application.

When MarshalShallowStruct launches, it shows a form with four fields: one for an integer, one for a character, one for a DWORD value, and one for a Boolean value. Each holds a default value. When you click the button labeled Update Struct, the application passes a structure holding each field's value to the native function ManipulateStruct() that resides in ManipulateStruct.dll.

The ManipulateStruct() function increments each field in the shallow structure passed to it. When the function returns, the managed application updates the main form to display the new values that were set by the native code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.128.105