Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Dealing with DllImport, (Part 2 of 2)

Learn how to use the DllAttribute's MarshalAs and StructLayout options to interoperate with unmanaged code that uses structures, and to control data layouts and marshalling precisely.


advertisement
In the first part of this article, I explained the basics of calling functions in unmanaged DLLs from managed .NET code. In this part, I'll show you how to use the MarshalAs and StructLayout options to control precisely how the runtime passes data to and from unmanaged code.

For example, the main Win32 API used to retrieve operating system version information, GetVersionEx, is exported from Kernel32.dll, and requires a pointer to an OSVERSIONINFO structure. The OSEVERSIONINFO structure includes an embedded, fixed-length character string, szCSDVersion. The first member of the structure contains the size of the structure, which must be set on input. On output, the function fills all the members of the structure within the declared size.



//GetVersionEx exported from Kernel32.dll. // BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo); //The original structure passed to the function //contains the following elements: //typedef struct _OSVERSIONINFO // { // DWORD dwOSVersionInfoSize; // DWORD dwMajorVersion; // DWORD dwMinorVersion; // DWORD dwBuildNumber; // DWORD dwPlatformId; // TCHAR szCSDVersion[ 128 ]; // } OSVERSIONINFO; //


Using the StructLayoutKind Attribute
You can describe this structure as a class using the StructLayout attribute. The LayoutKind.Sequential value in the StructLayout constructor means that the object members are laid out sequentially in the order in which they appear when the framework marshals the class instance to unmanaged memory. The members themselves are laid out according to the packing size specified in StructLayoutAttribute.Pack field. The default packing size is 8, which will work just fine for this structure.

using System; using System.Runtime.InteropServices; namespace OSInfo { class Class1 { [ StructLayout( LayoutKind.Sequential )] public class OSVersionInfo { public int dwOSVersionInfoSize; public int dwMajorVersion; public int dwMinorVersion; public int dwBuildNumber; public int dwPlatformId; [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )] public String szCSDVersion; } ...


Each unmanaged DWORD corresponds to a managed int. The embedded fixed-length string TCHAR szCSDVersion[128] must be marshaled by value. The MarshalAs attribute can set the type of string marshaling to use as well as the length of the string. The most appropriate unmanaged type for this case is ByValTStr, which was designed specifically to be used for in-line fixed length character arrays that appear within a structure.

You don't have to use LayoutKind.Sequential. Another possible LayoutKind arrangement is [StructLayout(LayoutKind.Explicit)], in which you can explicitly control the precise position of each member of an object in unmanaged memory by specifying the offset of that member from the start of the object's memory.
You don't have to use LayoutKind.Sequential. Another possible LayoutKind arrangement is [StructLayout(LayoutKind.Explicit)], in which you can explicitly control the precise position of each member of an object in unmanaged memory by specifying the offset of that member from the start of the object's memory. In an explicit layout, you must add a FieldOffset attribute to each member to indicate the position of that field within the type. In this example, you don't need explicit field offset control for this structure, although you could use it, particularly if you wanted to skip fields or describe an irregularly packed structure. For the OSVERSIONINFO structure a LayoutKind.Explicit arrangement would look like this:



[StructLayout( LayoutKind.Explicit )] public class OSVersionInfo2 { [FieldOffset(0)] public int dwOSVersionInfoSize; [FieldOffset(4)]public int dwMajorVersion; [FieldOffset(8)]public int dwMinorVersion; [FieldOffset(12)]public int dwBuildNumber; [FieldOffset(16)]public int dwPlatformId; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] [FieldOffset(20)]public String szCSDVersion; }




Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap