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

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

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

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

15

 

 

 

Performance Considerations and Limitations of Platform Invoke

Topic Objective

To list some performance considerations and limitations of using platform invoke.

Lead-in

When calling unmanaged code from managed code by using platform invoke, you must keep the following limitations and performance considerations in mind.

!Platform Invoke Supports Only Integer Arguments to Callback Functions

!Platform Invoke Does Not Support All Data Types

!Platform Invoke Supports Calling Only Global Functions Exported from the DLL

!Array Arguments That Are Passed by Reference and Copied Back Are Resized to 1

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

Some of the limitations that you must keep in mind when calling unmanaged functions by using platform invoke are:

!Platform invoke supports the callback mechanism. However, only integers are currently permitted as the arguments to the callback function.

!

!

Platform invoke does not support all data types.

Platform invoke supports calling only global functions exported from the DLL.

!When you call an unmanaged function, passing a reference to an array argument, all the array elements are copied to an unmanaged buffer. When the values are copied back, the size of that unmanaged buffer is no longer known. Therefore, only one element is copied back. The array is resized to 1.

16

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

Lab 15.1: Calling Win32 APIs

Topic Objective

To introduce the lab.

Lead-in

In this lab, you will call a Win32 API from managed code.

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

Objectives

After completing this lab, you will be able to call a Win32 API from managed code.

Estimated time to complete this lab: 30 minutes

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

17

 

 

 

Exercise 1

Calling a Win32 API from Managed Code

In this exercise, you will call Win32 APIs from managed code. This includes adding DllImport attributes to methods in your class, and then invoking those methods. The first unmanaged function you call retrieves the user name, and the second unmanaged function you call displays the user name in a message box.

!Open the Visual Studio .NET project for this exercise and examine the application UI

1.In Microsoft Windows® Explorer, move to <install folder>\Labs\ Lab15\Lab15.1\Starter.

2.Double-click CallingUnmanagedCode.csproj to open the project for this exercise in Visual Studio .NET.

3.In the Solution Explorer pane, double-click ManagedCode.cs. The UI design for the Windows Forms application appears. Examine the UI for a moment to become familiar with it.

4.Press F7 to edit the code that implements the Windows Form application.

!Add the DllImport attribute for the method used to retrieve the user name

GetUserNameEx is the Win32 API to be called. The signature for this function is as follows:

BOOLEAN GetUserNameEx(

 

 

EXTENDED_NAME_FORMAT NameFormat,

// name format

LPTSTR lpNameBuffer,

// name

buffer

PULONG nSize

// size

of name buffer

);

 

 

In the ManagedCode.cs file, notice the ‘TODO’ comment near the beginning, instructing you to add the declaration for a method that is used to call GetUserNameEx. Add the declaration for the method, including the DllImport attribute. Your method should also be named GetUserNameEx. Some key information you need in order to add the declaration is listed in the following table.

Information

Value

DLL containing the GetUserNameEx function

secur32.dll

Character set to use

CharSet.Auto

For information about the managed data types to use in your method declaration, see Marshaling earlier in this module. Notice that you can use the task list tab in the lower-left hand pane to find the ‘TODO’ comments. Click View, click Show Tasks, and then click All if the ‘TODO’ comments do not appear in the task list.

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

!Add the DllImport attribute for the method used to display the user name

MessageBox is the Win32 API to be called. The signature for this function is as follows:

int MessageBox(

 

 

HWND

hWnd,

// handle to owner

window

LPCTSTR lpText,

// text in message

box

LPCTSTR lpCaption,

// message box title

UINT

uType

// message box style);

In the ManagedCode.cs file, notice the next ‘TODO’ comment near the beginning, instructing you to add the declaration for a method that is used to call MessageBox. Add the declaration for the method, including the DllImport attribute. Your method should also be named MessageBox. Some key information you need in order to add the declaration is listed in the following table.

Information

Value

 

 

DLL containing the MessageBox function

user32.dll

Character set to use

CharSet.Auto

For information about the managed data types to use in your method declaration, see Marshaling earlier in this module. Notice that the strings passed to MessageBox are input-only parameters.

!Implement the methods that call unmanaged code

1.Scroll down in the ManagedCode.cs file to find the next ‘TODO’ comment near the end of the file in the buttonRetrieveUserName_Click method. The comment instructs you to add the code to retrieve the user name and display it in a message box. Replace the comment with a call to

GetUserNameEx followed by a call to MessageBox.

The SamCompatibleNameFormat constant represents the format of the username that will be returned from GetUserNameEx. Note that GetUserNameEx returns a non-zero value if it succeeds. Otherwise it returns a value of zero.

For the uType parameter to MessageBox, you should pass in

(uint)MessageBoxIcon.Information if GetUserNameEx succeeds, or (uint)MessageBoxIcon.Error if GetUserNameEx fails. MessageBox returns a value for the button clicked on the message box, but this should not affect the application.

2.Scroll down to the catch block to find the next ‘TODO’ comment instructing you to add a MessageBox call to report the exception as an error. Replace the comment with a call to MessageBox after the exception message is created. Pass in (uint)MessageBoxIcon.Error for the uType parameter.

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

19

 

 

 

! Build and test your application

1.On the File menu, click Save All.

2.On the Build menu, click Build Solution. Your application should build successfully. The following statement should appear as the last line of the output window:

Build: 1 succeeded, 0 failed, 0 skipped.

3.On the Debug menu, click Start, and then click Retrieve User Name. The user name should be displayed in a message box. Click OK to dismiss the message box.

4.To close the application, click Exit.

20

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

" Calling COM Objects from Managed Code

Topic Objective

To introduce how COM objects are exposed to managed code.

Lead-in

In this section you will learn how to expose COM objects to managed code by using runtime callable wrappers.

!Runtime Callable Wrappers

!Generating Runtime Callable Wrappers

!Threading Models

!Signature Translation and Error Handling

!Marshaling

!Performance and Security Issues

!Best Practices

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

COM objects are exposed to managed code by creating runtime callable wrappers for the objects. The purpose of the wrappers is to marshal calls between a .NET Framework client and a COM object.

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

21

 

 

 

Runtime Callable Wrappers

Topic Objective

To describe the purpose of runtime callable wrappers.

Lead-in

The primary goal of runtime callable wrappers is to hide the differences between the managed and unmanaged programming models.

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

In order to call a COM object, the runtime uses a runtime callable wrapper. Runtime callable wrappers contain all of the information needed to call the COM object. The runtime callable wrapper maintains a cache of interface pointers on the COM object it wraps and releases its reference on the COM object when the wrapper is no longer needed. The runtime performs garbage collection on the runtime callable wrapper after the COM object has been released.

One of the primary functions of the runtime callable wrapper is to marshal data between managed and unmanaged code. The runtime callable wrapper provides marshaling for method arguments and method return values whenever the client and server have different representations of the data passed between them. For example, when a .NET Framework client passes a String type as part of an argument to a managed object, the wrapper converts the String type to a BSTR type. Should the COM object return a BSTR type to its managed caller, the caller receives a String type. Both the client and the server send and receive data types that are familiar to each of them. Some other types require no conversion. For instance, a standard wrapper will always pass a 4-byte integer between managed and unmanaged code without converting the type.

The runtime callable wrapper implements the interfaces that the COM object implements and exposes the methods, properties, and events from the object’s interfaces. In the illustration, the wrapper exposes the INew interface and all its methods and properties to the client, but consumes the IUnknown and IDispatch interfaces. The IUnknown interface is used by the runtime to identify the COM object, provide type coercion, and control lifetime management. The runtime distinguishes between COM objects by comparing the value of the IUnknown interface for each object. The wrapper uses the QueryInterface method to get and hold a reference to an unmanaged object. The reference is retained until the runtime performs garbage collection on the wrapper. The wrapper releases the unmanaged object during garbage collection.

22

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

The runtime callable wrapper also consumes the interfaces listed in the following table.

Interface

Description

IErrorInfo

If the COM object being wrapped implements the IErrorInfo

 

interface, the exceptions generated by the wrapper contain the

 

information provided by the interface

IProvideClassInfo

If the COM object being wrapped implements the

 

IProvideClassInfo interface, the wrapper extracts the type

 

information from this interface to provide better type identity

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

23

 

 

 

Generating Runtime Callable Wrappers

Topic Objective

To define the three ways to generate runtime callable wrappers.

Lead-in

Runtime callable wrappers are generated in one of three ways.

!Runtime Callable Wrappers Are Generated in One of Three Ways:

#Adding a reference to a COM component in a Visual Studio .NET project

#Employing the Type Library Importer

#Creating custom wrappers

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

Delivery Tip

You may want to create an RCW and use the Microsoft Intermediate Language disassembler to show what the metadata looks like.

Runtime callable wrappers are generated in one of three ways:

!Adding a reference to a COM component in a Visual Studio .NET project

This automatically converts COM types in a type library to metadata in an assembly.

!By using the Type Library Importer

This provides command-line switches to adjust metadata in the resulting assembly file, imports types from an existing type library, and generates an assembly and a namespace.

!Creating custom wrappers

As a less-desirable option, you can create type definitions. This requires advanced programming skills.

Visual Studio .NET generates an assembly containing metadata when you add a reference to a specific type library.

! To add a reference to a type library in Visual Studio .NET

1.Install the COM DLL or EXE file manually on your computer and use Regsrv32.exe to add a component to the registry, unless a Microsoft Windows installation program performs the installation for you.

2.In Visual Studio .NET, on the Project menu, click Add Reference.

3.Click the COM tab.

4.In the Component Name list, double-click the type library, and then click

OK.

24

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

The Type Library Importer (Tlbimp.exe) is a command-line tool that converts the coclasses and interfaces contained in a COM type library to metadata. This tool creates an assembly and namespace for the type information automatically. After the metadata of a class is available, managed clients can create an instance of the COM type and call its methods, as if it were a .NET Framework instance. The Type Library Importer converts an entire type library to metadata at once but cannot generate type information for a subset of the types defined in a type library.

!To generate an assembly from a type library

To produce the Loanlib.dll assembly in the Loanlib namespace, type the following command:

tlbimp Loanlib.tlb

Adding the /out: switch produces an assembly with an altered name, such as Loanlib_RCW.dll. Altering the runtime callable wrapper assembly name can help distinguish it from the original COM DLL. The following example uses the /out: switch of the Type Library Importer to alter the generated assembly’s name:

tlbimp Loanlib.dll /out: Loanlib_RCW.dll

When a type library is unavailable or incorrect, one option is to create a duplicate definition of the class or interface in managed source code. You then compile the source code with a compiler that targets the runtime in order to produce metadata in an assembly.

To define COM types manually, you must have access to the following items:

!Precise descriptions of the coclasses and interfaces being defined.

!A compiler, such as the C# compiler, that can generate the appropriate .NET Framework class definitions.

!Knowledge of the rules for conversion from a type library to an assembly.

Writing a custom wrapper is an advanced technique that you seldom perform. However, if you need to create custom wrappers, there are two methods to do this:

!If you have access to the Interface Definition Language (IDL) source, you can modify the source by applying type library file attributes and import the type library.

!You can apply interop-specific attributes to imported types and generate a new assembly.

For additional information on generating a custom wrapper, see “Customizing Standard Wrappers” in the .NET Framework SDK documentation.

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