Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / MS Press - Msdn Training Programming Net Framework With C#

.pdf
Скачиваний:
173
Добавлен:
12.02.2016
Размер:
16.87 Mб
Скачать

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

5

 

 

 

Interop Marshaling Overview

Topic Objective

To provide an overview of interop marshalling.

Lead-in

Interop marshaling governs how data is passed in method arguments and return values between managed and unmanaged memory during calls.

!Interop marshaling governs how data is passed between managed and unmanaged memory during calls

#Is a run time activity performed by the common language runtime marshaling service

!Blittable data types are common to managed and unmanaged memory and require no conversion – data types (C# keyword) :

# System.Byte (byte)

System.SByte (sbyte)

# System.Int16 (short)

System.UInt16 (ushort)

# System.Int32 (int)

System.UInt32 (uint)

# System.Int64 (long)

System.IntPtr System.UIntPtr

*****************************ILLEGAL FOR NON-TRAINER USE******************************

Interop marshaling governs how data is passed in method arguments and return values between managed and unmanaged memory during calls. Interop marshaling is a run-time activity performed by the common language runtime's marshaling service.

Most data types have a common representation in both managed and unmanaged memory and do not require special handling by the interop marshaler. These types are called blittable types because they do not require conversion when passed between managed and unmanaged code.

The following types from the System namespace are blittable types:

!System.Byte

!System.SByte

!System.Int16

!System.UInt16

!System.Int32

!System.UInt32

!System.Int64

!System.IntPtr

!System.UintPtr

6Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

Interop Marshaling Overview (continued)

Topic Objective

To complete the overiew of interop marshalling.

Lead-in

Let’s discuss how nonblittable types differ from blittable types with regard to Interop marshaling and how custom attributes may be used to in place of the standard marshaling operations.

!Non-blittable types have different or ambiguous representations in managed and unmanaged languages and may require conversion

#For example, managed strings are non-blittable types

!The standard RCW or CCW usually provides adequate marshaling for calls that cross the boundary between COM and the .NET Framework

#Custom attributes can optionally adjust the way the runtime represents managed and unmanaged code

*****************************ILLEGAL FOR NON-TRAINER USE******************************

Non-blittable types have different or ambiguous representations in managed and unmanaged languages. These types may require conversion when they are marshaled between managed and unmanaged code. For example, managed strings are non-blittable types because they can have several different unmanaged representations, some of which can require conversion.

The following table lists non-blittable types from the System namespace. Delegates, which are data structures that refer to a static method or to a class instance, are also non-blittable.

Non-blittable type

Description

 

 

System.Array

Converts to a C-style or a SAFEARRAY.

System.Boolean

Converts to a 1, 2, or 4-byte value with true as 1 or -1.

System.Char

Converts to a Unicode or ANSI character.

System.Class

Converts to a class interface.

System.Object

Converts to a variant or an interface.

System.Mdarray

Converts to a C-style array or a SAFEARRAY.

System.String

Converts to a null-terminated string or to a BSTR.

System.Valuetype

Converts to a structure with a fixed memory layout.

System.Szarray

Converts to a C-style array or a SAFEARRAY.

In most cases, the standard RCW or CCW that is generated by the runtime provides adequate marshaling for calls that cross the boundary between COM and the .NET Framework. Using custom attributes, you can optionally adjust the way the runtime represents managed and unmanaged code.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

7

 

 

 

" Platform Invoke

Topic Objective

To introduce platform invoke.

Lead-in

In this section you will learn how platform invoke can be used to call unmanaged code.

!How Platform Invoke Works

!Calling a Win32 API From Managed Code

!Calling Unmanaged Functions

!Pinning

!Marshaling

!Performance Considerations and Limitations of Platform Invoke

*****************************ILLEGAL FOR NON-TRAINER USE******************************

Platform invoke allows managed code to call unmanaged functions that are implemented in a DLL. Platform invoke is primarily used to call C functions that are part of the Win32 API. To use these functions, you must import the DLL that hosts the functions. The .NET Framework provides default marshaling to marshal data between managed and unmanaged code. You can, however, override the marshaling provided by the .NET Framework whenever you require custom marshaling to be performed.

8Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

How Platform Invoke Works

Topic Objective

To describe how platform invoke executes methods that are implemented in a DLL.

Lead-in

This is how platform invoke loads and executes a method that is implemented in a DLL.

*****************************ILLEGAL FOR NON-TRAINER USE******************************

When platform invoke calls an unmanaged function, it performs the following sequence of actions:

1.Platform invoke locates the DLL containing the function.

2.It loads the DLL into memory.

3.It locates the address of the function in memory and pushes its arguments onto the stack, marshaling data as required.

4.Platform invoke then transfers control to the unmanaged function.

You provide the DLL and function information to platform invoke by annotating your code. This information is used by platform invoke to locate the DLL and load it into the memory of the process, after which the address of the function is located and control is transferred.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

9

 

 

 

Calling a Win32 API From Managed Code

Topic Objective

To describe how to call a Win32 API from managed code.

Lead-in

To use an unmanaged function that is implemented in a DLL, you must first import the DLL into your code.

!Declare the Method with the static and extern C# Keywords

!Import the DLL That Implements the Unmanaged Function That You Wish to Call

[DllImport(<DLL name>, EntryPoint=<function name>, [DllImport(<DLL name>, EntryPoint=<function name>,

CharSet=<type of characterset>] CharSet=<type of characterset>]

!Optionally, Specify Custom Marshaling Information to Override the .NET Framework Default Marshaling

*****************************ILLEGAL FOR NON-TRAINER USE******************************

To call an unmanaged function, the first step is to annotate your code by importing the DLL file in which the function is implemented. You use the DllImport attribute to import the DLL. The DllImport attribute requires the DLL_name argument, and also takes any of the following additional arguments.

Argument

Description

EntryPoint

Specifies the DLL entry point to be called.

CharSet

Controls name mangling and the way that string arguments

 

should be marshaled to the function. The default is

 

CharSet.Ansi.

ExactSpelling

Prevents an entry point from being modified to correspond to

 

the character set. If CharSet.Auto is enabled, the default is

 

False. Otherwise, the default is True.

CallingConvention

Specifies the calling-convention values used in passing method

 

arguments. The default is Winapi.

PreserveSig

Indicates that the managed method signature should not be

 

transformed into an unmanaged signature that returns an

 

HRESULT, and might have an additional [out, retval]

 

argument for the return value.

 

The default is True (the signature should not be transformed).

SetLastError

Enables the caller to use the GetLastError Win32 API

 

function to determine whether an error occurred while

 

executing the method. In Microsoft Visual Basic®, the default is

 

True; in C# and C++, the default is False.

If the DLL has both an ANSI and a Unicode implementation of the same function, then the CharSet parameter specifies which version of the function is called.

10

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

Calling Unmanaged Functions

Topic Objective

To describe how to annotate unmanaged method calls so that they can be called from

.NET Framework applications.

Lead-in

Unmanaged methods that are implemented as a DLL and called from managed code must be annotated before they can be executed by the runtime.

!To Call a Function That Is Implemented in an Unmanaged DLL

#Add a using statement for System.Runtime.InteropServices

#Add a DllImport attribute to a method, specifying the name of the unmanaged DLL that exports the function to be called

#Declare with the static and extern C# keywords the method that is used to call unmanaged code without providing any implementation for the method

using System.Runtime.InteropServices; using System.Runtime.InteropServices;

[DllImport("msvcrt.dll", CharSet=CharSet.Ansi)] [DllImport("msvcrt.dll", CharSet=CharSet.Ansi)] public static extern int puts(String str); public static extern int puts(String str);

*****************************ILLEGAL FOR NON-TRAINER USE******************************

Delivery Tip

Refer to the .NET SDK for more information about

DllImport, calling conventions, marshaling, and character sets.

When you call unmanaged functions from .NET Framework applications, you must add a DllImport attribute to a method that is to be used by platform invoke. The DllImport attribute is defined in System.Runtime.InteropServices. Platform invoke uses the information in the attribute to call the appropriate underlying DLL function, marshal parameters to the function, and return values from the function when the method is called. The example on the slide shows the use of the DllImport attribute.

To annotate a method in managed code that is used to call a function in an unmanaged DLL, you must specify the name of the DLL that exports the unmanaged function. You must also specify with the static and extern C# keywords the name of the exported function or its equivalent entry point ordinal, if the exported function name is different than the name of the method that you declared in the managed module. Optionally, you can specify a flag to indicate the underlying calling convention and to automatically marshal string data types correctly. The calling convention flag can be set to Cdecl, FastCall, StdCall, ThisCall, or Winapi. If no calling convention is specified, Winapi is the default. You can also optionally specify the character set to use as part of the function call. The values that you can specify for the character set are ansi, unicode, or auto.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

11

 

 

 

There are two general approaches when declaring methods that match unmanaged functions:

!You can declare the method to call the unmanaged DLL without providing any implementation for the method, as shown in the following example:

using System;

using System.Runtime.InteropServices;

[DllImport("msvcrt.dll", CharSet=CharSet.Ansi)] public static extern int puts(String str);

static void Main()

{

String Str = "Hello World!"; puts(Str);

}

The compiler uses the method declaration to generate the metadata that the runtime needs to locate and correctly marshal the call to the DLL. When declaring the method in your managed code, you can substitute the equivalent runtime types for the function’s types. In the previous example, a string object is substituted for a character string.

!You can also declare a .NET Framework class that is a collection of declarations for an API exported by an unmanaged DLL. The advantage of creating such a class is that you do not have to declare and annotate the methods for the unmanaged DLL that you want to call in all the applications that you create. After it is created, you can include the class in your application, and you can call the unmanaged functions that are declared in the class as if they were .NET Framework methods.

Annotated methods behave like managed .NET Framework methods. When an annotated method is called, platform invoke calls the unmanaged function, marshaling any data that needs to be marshaled to and from the unmanaged function.

12

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

Pinning

Topic Objective

To define pinning.

Lead-in

When data is marshaled between managed and unmanaged code, it can either be copied from one memory location to another, or it can be pinned.

!Data Is Temporarily Locked in Its Current Memory Location to Keep It from Being Relocated by the Common Language Runtime’s Garbage Collector

!Pinning Is Performed When Data Has to Be Passed Between Managed and Unmanaged Code and

#Has a fixed layout and common data representation in both managed and unmanaged memory

-or -

#Has a fixed layout but the data representation is different in managed and unmanaged memory and the class is marshaled by reference

*****************************ILLEGAL FOR NON-TRAINER USE******************************

Pinning is a technique in which data is temporarily locked in its current memory location to keep it from being relocated during garbage collection. Whether data is copied or pinned during the marshaling process depends on the type of the data and its InAttribute and OutAttribute.

When classes that have a fixed layout and common data representation in both managed and unmanaged memory require marshaling, a pointer to the actual object is passed to the called function. The called function is then free to change the contents of the memory location being referenced by the pointer.

When classes have a fixed layout but the data representation is different in managed and unmanaged memory and the class is marshaled by reference, the called function receives a pointer to a copy of the data structure. If the InAttribute is set, the copy is always initialized with the instance’s state. If the OutAttribute is set, the state is always copied back in to the instance upon return. If both the InAttribute and OutAttribute are set, the copy is always initialized with the instance’s state, and the last state is always copied back into the instance on return. If either attribute is omitted, the runtime may choose to eliminate either copy as an optimization.

When classes that do not have a fixed layout—such as System.String and System.Text.StringBuilder—have to be marshaled by value or by reference to unmanaged code, the runtime typically copies the data of either type to a secondary buffer and passes a reference to the buffer to the called function. The reference is always allocated with CoTaskMemAlloc.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

13

 

 

 

Marshaling

Topic Objective

To describe how marshalling is performed by platform invoke.

Lead-in

Platform invoke automatically marshals data between unmanaged types and managed types.

!Platform Invoke Marshals Simple Data Types Between Managed and Unmanaged Code

!Custom Marshalling Can Be Specified by Using the MarshalAs Attribute

public static extern int MessageBoxW( public static extern int MessageBoxW(

int h, int h,

[MarshalAs(UnmanagedType.LPWStr)] string m, [MarshalAs(UnmanagedType.LPWStr)] string m, …); …);

*****************************ILLEGAL FOR NON-TRAINER USE******************************

For arguments that are simple data types—such as bytes or integers—platform invoke marshals the managed argument to the corresponding unmanaged data type. The following table shows how the data types used in the Win32 API (wtypes.h) should be expressed in C#.

Data Type in wtypes.h

C# Data Type

HANDLE

int

BYTE

byte

SHORT

short

WORD

ushort

INT

int

UINT

uint

LONG

int

ULONG

uint

BOOLEAN

int

CHAR

char

LPSTR (and most other string types)

String for in, StringBuilder for inout

FLOAT

float

DOUBLE

double

If any parameter is passed by reference, the ref keyword in C# should be added to the method declaration used to call unmanaged code.

14

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

For example, the GetUserNameEx Win32 API function has the following declaration:

BOOLEAN GetUserNameEx(

 

 

EXTENDED_NAME_FORMAT NameFormat,

// name format

LPTSTR lpNameBuffer,

// name

buffer

PULONG nSize

// size

of name buffer

);

 

 

To call this from managed code, you would use the following declaration:

[DllImport("secur32.dll", CharSet=CharSet.Auto)]

public static extern int GetUserNameEx (int nameFormat, StringBuilder userName, ref uint userNameSize);

Notice that an integer is substituted for the enumeration parameter, a StringBuilder object is substituted for the string parameter, and the ref keyword is added to the last parameter, because it is passed by reference.

Your choice of data types may affect applications when the data types are marshaled to and from managed code. For example, in Win32 APIs, a LONG data type is 32 bits, whereas the C# long and Visual Basic .NET Long data types are 64 bits.

When calling API functions, you can specify custom marshaling attributes by adding a MarshalAsAttribute to the parameters of the function. You can also use the MarshalAsAttribute with structures. When using the MarshalAsAttribute with structures, you must also use the StructLayout attribute to set the native layout of the structure.

Соседние файлы в папке c#