Tải bản đầy đủ - 0 (trang)
12-3. Call an Unmanaged Function That Uses a Structure

12-3. Call an Unmanaged Function That Uses a Structure

Tải bản đầy đủ - 0trang

CHAPTER 12 ■ UNMANAGED CODE INTEROPERABILITY



[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;

}

Notice that this structure also uses the attribute System.Runtime.InteropServices.

MarshalAsAttribute, which is required for fixed-length strings. In this example, MarshalAsAttribute

specifies that the string will be passed by value and will contain a buffer of exactly 128 characters, as

specified in the OSVERSIONINFO structure. This example uses sequential layout, which means that the data

types in the structure are laid out in the order they are listed in the class or structure. When using

sequential layout, you can also configure the packing for the structure by specifying a named Pack field

in the StructLayoutAttribute constructor. The default is 8, which means the structure will be packed on

8-byte boundaries.

Instead of using sequential layout, you could use LayoutKind.Explicit; in which case, you must

define the byte offset of each field using FieldOffsetAttribute. This layout is useful when dealing with

an irregularly packed structure or one where you want to omit some of the fields that you do not want to

use. Here is an example that defines the OSVersionInfo class with explicit layout:

[StructLayout(LayoutKind.Explicit)]

public class OSVersionInfo {

[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;

}

Now that you’ve defined the structure used by the GetVersionEx function, you can declare the

function and then use it. The following console application shows all the code you will need. Notice that

InAttribute and OutAttribute are applied to the OSVersionInfo parameter to indicate that marshaling

should be performed on this structure when it is passed to the function and when it is returned from the

function. In addition, the code uses the Marshal.SizeOf method to calculate the size the marshaled

structure will occupy in memory.

using System;

using System.Runtime.InteropServices;

namespace Apress.VisualCSharpRecipes.Chapter12

{

class Recipe12_03

{



604



www.it-ebooks.info



CHAPTER 10 ■ UNMANAGED CODE INTEROPERABILITY



// Declare the external function.

[DllImport("kernel32.dll")]

public static extern bool GetVersionEx([In, Out] OSVersionInfo osvi);

static void Main(string[] args)

{

OSVersionInfo osvi = new OSVersionInfo();

osvi.dwOSVersionInfoSize = Marshal.SizeOf(osvi);

// Obtain the OS version information.

GetVersionEx(osvi);

// Display the version information.

Console.WriteLine("Class size: " + osvi.dwOSVersionInfoSize);

Console.WriteLine("Major Version: " + osvi.dwMajorVersion);

Console.WriteLine("Minor Version: " + osvi.dwMinorVersion);

Console.WriteLine("Build Number: " + osvi.dwBuildNumber);

Console.WriteLine("Platform Id: " + osvi.dwPlatformId);

Console.WriteLine("CSD Version: " + osvi.szCSDVersion);

Console.WriteLine("Platform: " + Environment.OSVersion.Platform);

Console.WriteLine("Version: " + Environment.OSVersion.Version);

// Wait to continue.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Main method complete. Press Enter.");

Console.ReadLine();

}

}

// Define the structure and specify the layout type as sequential.

[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;

}

}



605



www.it-ebooks.info



CHAPTER 12 ■ UNMANAGED CODE INTEROPERABILITY



If you run this application on a Windows 7 system, you will see information such as this:

Class size: 148

Major Version: 6

Minor Version: 1

Build Number: 7600

Platform Id: 2

CSD Version:

Platform: Win32NT

Version: 6.1.7600.0



12-4. Call an Unmanaged Function That Uses a Callback

Problem

You need to call an unmanaged function and allow it to call a method in your code.



Solution

Create a delegate that has the required signature for the callback. Use this delegate when defining and

using the unmanaged function.



How It Works

Many of the Win32 API functions use callbacks. For example, if you want to retrieve the name of all the

top-level windows that are currently open, you can call the unmanaged EnumWindows function in the

User32.dll file. When calling EnumWindows, you need to supply a pointer to a function in your code. The

Windows operating system will then call this function repeatedly—once for each top-level window that

it finds—and pass the window handle to your code.

The .NET Framework allows you to handle callback scenarios like this without resorting to pointers

and unsafe code blocks. Instead, you can define and use a delegate that points to your callback function.

When you pass the delegate to the EnumWindows function, for example, the CLR will automatically

marshal the delegate to the expected unmanaged function pointer.



606



www.it-ebooks.info



CHAPTER 10 ■ UNMANAGED CODE INTEROPERABILITY



The Code

Following is a console application that uses EnumWindows with a callback to display the name of every

open window:

using System;

using System.Text;

using System.Runtime.InteropServices;

namespace Apress.VisualCSharpRecipes.Chapter12

{

class Recipe12_04

{

// The signature for the callback method.

public delegate bool CallBack(IntPtr hwnd, int lParam);

// The unmanaged function that will trigger the callback

// as it enumerates the open windows.

[DllImport("user32.dll")]

public static extern int EnumWindows(CallBack callback, int param);

[DllImport("user32.dll")]

public static extern int GetWindowText(IntPtr hWnd,

StringBuilder lpString, int nMaxCount);

static void Main(string[] args)

{

// Request that the operating system enumerate all windows,

// and trigger your callback with the handle of each one.

EnumWindows(new CallBack (DisplayWindowInfo), 0);

// Wait to continue.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Main method complete. Press Enter.");

Console.ReadLine();

}

// The method that will receive the callback. The second

// parameter is not used, but is needed to match the

// callback's signature.

public static bool DisplayWindowInfo(IntPtr hWnd, int lParam)

{

int chars = 100;

StringBuilder buf = new StringBuilder(chars);

if (GetWindowText(hWnd, buf, chars) != 0)

{

Console.WriteLine(buf);

}



607



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

12-3. Call an Unmanaged Function That Uses a Structure

Tải bản đầy đủ ngay(0 tr)

×