Создание прототипов в управляемом коде 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Создание прототипов в управляемом коде



В этом разделе описывается порядок обращения к неуправляемым функциям и представлено несколько полей атрибутов, которые уточняют определение метода в управляемом коде. Примеры, в которых показывается способ создания объявлений на основе.NET, предназначенных для использования с вызовом неуправляемого кода, см. в разделе Маршалинг данных с вызовом неуправляемого кода.

Чтобы можно было обратиться к неуправляемой функции DLL из управляемого программного кода, требуется знать имя функции и имя библиотеки DLL, которая ее экспортирует. Располагая этими сведениями, разработчик может приступить к созданию управляемого определения для неуправляемой функции, реализованной в DLL. Кроме этого, можно настроить порядок создания функции при вызове неуправляемого кода, а также маршалинг данных в функцию и обратно.

Примечание.
Функции Win32 API, которые распределяют строку, позволяют освободить строку с помощью, например, метода LocalFree. При вызове неуправляемого кода эти параметры обрабатываются иначе. Для вызовов неуправляемого кода следует использовать параметр типа IntPtr, а не типа String. Чтобы вручную преобразовать тип в строку и вручную освободить его, можно использовать методы, предоставленные классом System.Runtime.InteropServices..::.Marshal.

Основы объявления

Как показано в следующих примерах, управляемые определения неуправляемых функций зависят от используемого языка. Более полные примеры кода см. в разделе Примеры вызовов неуправляемого кода.

Чтобы применить в объявлении Microsoft Visual Basic 2005 поля BestFitMapping, CallingConvention, ExactSpelling, PreserveSig, SetLastError или ThrowOnUnmappableChar, необходимо использовать атрибут DllImportAttribute вместо инструкции Declare.

ß--------


Adjusting the Definition

Whether you set them explicitly or not, attribute fields are at work defining the behavior of managed code. Platform invoke operates according to the default values set on various fields that exist as metadata in an assembly. You can alter this default behavior by adjusting the values of one or more fields. In many cases, you use the DllImportAttribute to set a value.

The following table lists the complete set of attribute fields that pertain to platform invoke. For each field, the table includes the default value and a link to information on how to use these fields to define unmanaged DLL functions.

Field Description
BestFitMapping Enables or disables best-fit mapping.
CallingConvention Specifies the calling convention to use in passing method arguments. The default is WinAPI, which corresponds to __stdcall for the 32-bit Intel-based platforms.
CharSet Controls name mangling and the way that string arguments should be marshaled to the function. The default is CharSet.Ansi.
EntryPoint Specifies the DLL entry point to be called.
ExactSpelling Controls whether an entry point should be modified to correspond to the character set. The default value varies by programming language.
PreserveSig Controls whether the managed method signature should be transformed into an unmanaged signature that returns an HRESULT and has 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 Marshal.GetLastWin32Error API function to determine whether an error occurred while executing the method. In Visual Basic, the default is true; in C# and C++, the default is false.
ThrowOnUnmappableChar Controls throwing of an exception on an unmappable Unicode character that is converted to an ANSI "?" character.

Настройка определения

Значения атрибутов, заданные явно или неявно, определяют выполнение управляемого программного кода. Вызов неуправляемого кода выполняется работает в соответствии с набором стандартных значений различных полей, хранящихся в сборке как метаданные. Подстраивая значения одного или нескольких полей, можно изменить это поведение по умолчанию. Во многих случаях для установки значения используется DllImportAttribute.

В следующей таблице представлен полный набор полей атрибутов, имеющих отношение к вызову неуправляемого кода. Для каждого поля в таблице имеется стандартное значение и ссылка на сведения об использовании этих полей для определения неуправляемых функций DLL.

Поле Описание
BestFitMapping Включает и отключает наилучшее сопоставление.
CallingConvention Задает соглашение о вызовах, которое должно использоваться при передаче аргументов методов. По умолчанию используется значение WinAPI, соответствующее режиму __stdcall для 32-разрядных платформ на основе процессора Intel.
CharSet Управляет изменением имен при передаче и задает способ маршалинга строковых аргументов в функцию. По умолчанию используется CharSet.Ansi.
EntryPoint Задает точку входа DLL для вызова.
ExactSpelling Определяет, должна ли изменяться точка входа в соответствии с кодировкой. Значение зависит от языка программирования.
PreserveSig Определяет, должна ли управляемая подпись метода преобразоваться в неуправляемую подпись, которая возвращает значение HRESULT и для возвращаемого значения имеет дополнительный аргумент [out, retval]. По умолчанию используется значение true (подпись не должна преобразовываться).
SetLastError Позволяет вызывающему объекту при выполнении метода для определения факта ошибки использовать функцию интерфейса API Marshal.GetLastWin32Error. В Visual Basic по умолчанию используется значение true, в C# и C++ — значение false.
ThrowOnUnmappableChar Управляет возникновением исключения при появлении несопоставимого символа Юникода, который преобразуется в символ ANSI "?".

 


Specifying an Entry Point

An entry point identifies the location of a function in a DLL. Within a managed project, the original name or ordinal entry point of a target function identifies that function across the interoperation boundary. Further, you can map the entry point to a different name, effectively renaming the function.

Following is a list of possible reasons to rename a DLL function:

· To avoid using case-sensitive API function names

· To comply with existing naming standards

· To accommodate functions that take different data types (by declaring multiple versions of the same DLL function)

· To simplify using APIs that contain ANSI and Unicode versions

This topic demonstrates how to rename a DLL function in managed code.

Renaming a Function in C# and C++

You can use the DllImportAttribute..::.EntryPoint field to specify a DLL function by name or ordinal. If the name of the function in your method definition is the same as the entry point in the DLL, you do not have to explicitly identify the function with the EntryPoint field. Otherwise, use one of the following attribute forms to indicate a name or ordinal:

[DllImport("dllname", EntryPoint="Functionname")] [DllImport("dllname", EntryPoint="#123")]

Notice that you must prefix an ordinal with the pound sign (#).

The following example demonstrates how to replace MessageBoxA with MsgBox in your code by using the EntryPoint field.

using System.Runtime.InteropServices;   public class Win32 { [DllImport("user32.dll", EntryPoint="MessageBoxA")] public static extern int MsgBox(int hWnd, String text, String caption, uint type); }

 


Задание точки входа

Точка входа определяет расположение функции в DLL. В управляемом проекте исходное имя или порядковый номер точки входа целевой функции определяет эту функцию в границах взаимодействия. Также разработчик может сопоставить точку входа с другим именем, фактически переименовывая функцию.

Ниже приведен перечень возможных причин переименования функции DLL:

· избежать использования имен API-функций, чувствительных к регистру знаков;

· привести имена в соответствие с существующими стандартами именования;

· сделать возможным вызов функций, принимающих данные разных типов (объявляя несколько версий одной и той же функции DLL);

· упростить применение API-интерфейсов, которые содержат функции версий для ANSI и Юникода.

В этом разделе показан способ переименования функции DLL в управляемом коде.

Переименование функции в C# и C++

Для задания функции по имени или порядковому номеру можно использовать поле DllImportAttribute..::.EntryPoint. Если имя функции в определении метода совпадает с именем точки входа в DLL, явно задавать функцию с помощью поля EntryPoint не требуется. В противном случае, чтобы указать имя или порядковый номер, следует использовать одну из следующих форм атрибута:

[DllImport("dllname", EntryPoint="Functionname")] [DllImport("dllname", EntryPoint="#123")]

Обратите внимание, что порядковому номеру должен предшествовать знак #.

В следующем примере показан способ замены в программном коде MessageBoxA на MsgBox с помощью поля EntryPoint

ß-------


Calling a DLL Function

Although calling unmanaged DLL functions is nearly identical to calling other managed code, there are differences that can make DLL functions seem confusing at first. This section introduces topics that describe some of the unusual calling-related issues.

Passing Structures

Many unmanaged functions expect you to pass, as a parameter to the function, members of structures (user-defined types in Visual Basic) or members of classes that are defined in managed code. When passing structures or classes to unmanaged code using platform invoke, you must provide additional information to preserve the original layout and alignment. This topic introduces the StructLayoutAttribute attribute, which you use to define formatted types. For managed structures and classes, you can select from several predictable layout behaviors supplied by the LayoutKind enumeration.

Central to the concepts presented in this topic is an important difference between structure and class types. Structures are value types and classes are reference types — classes always provide at least one level of memory indirection (a pointer to a value). This difference is important because unmanaged functions often demand indirection, as shown by the signatures in the first column of the following table. The managed structure and class declarations in the remaining columns show the degree to which you can adjust the level of indirection in your declaration.

Unmanaged signature Managed declaration: no indirection struct MyStruct(…); Managed declaration: one level of indirection class MyStruct(…);
DoWork(MyStruct x); Demands zero levels of indirection. DoWork(ByVal x As MyStruct) Adds zero levels of indirection. Not possible because there is already one level of indirection.
DoWork(MyStruct* x); Demands one level of indirection. DoWork(ByRef x As MyStruct) Adds one level of indirection. DoWork(ByVal x As MyStruct) Adds zero levels of indirection.
DoWork(MyStruct** x); Demands two levels of indirection. Not possible because ByRef ByRef cannot be used. DoWork(ByRef x As MyStruct) Adds one level of indirection.

Вызов функции DLL

Хотя вызов неуправляемых функций DLL почти идентичен вызову другого управляемого кода, все же существуют отличия, которые поначалу могут вызвать некоторые сложности в освоении функций DLL. В этом разделе представлены темы, касающиеся некоторых особенностей вызовов.

Передача структур

Для многих неуправляемых функций в качестве параметра должны быть переданы члены структур (в Visual Basic это определяемые пользователем типы) или члены классов, определяемые в управляемом коде программы. Для сохранения исходного размещения и выравнивания при передаче структур или классов в неуправляемый код необходимо предоставить дополнительные сведения при вызове неуправляемого кода. В этом разделе описывается атрибут StructLayoutAttribute, который можно использовать для определения форматированных типов. Для управляемых структур и классов можно выбрать одно из стандартных размещений, предоставленных перечислением LayoutKind.

Важнейшим из понятий, описанных в этом разделе, является существенное различие между структурами и классами как типами. Структуры представляют собой типы значений, а классы —ссылочные типы, которые всегда обеспечивают, по крайней мере, один уровень косвенного обращения к памяти (указатель на значение). Это различие очень важно, так как неуправляемые функции часто требуют косвенного обращения, что видно из примеров подписей в первом столбце следующей таблицы. Объявления управляемых структур и классов в остальных столбцах показывают, насколько возможна настройка уровня косвенного обращения в объявлении.

Неуправляемая подпись Управляемое объявление: без косвенного обращения struct MyStruct(…); Управляемое объявление: один уровень косвенного обращения class MyStruct(…);
DoWork(MyStruct x); Требует отсутствия уровней косвенного обращения. DoWork(ByVal x As MyStruct) Добавляет ноль уровней косвенного обращения. Невозможно, так как уже существует один уровень косвенного обращения.
DoWork(MyStruct* x); Требует одного уровня косвенного обращения. DoWork(ByRef x As MyStruct) Добавляет один уровень косвенного обращения. DoWork(ByVal x As MyStruct) Добавляет ноль уровней косвенного обращения.
DoWork(MyStruct** x); Требует двух уровней косвенного обращения. Невозможно, так как объявление ByRef ByRef использовать нельзя. DoWork(ByRef x As MyStruct) Добавляет один уровень косвенного обращения.

 


The table describes the following guidelines for platform invoke declarations:

· Use a structure passed by value when the unmanaged function demands no indirection.

· Use either a structure passed by reference or a class passed by value when the unmanaged function demands one level of indirection.

· Use a class passed by reference when the unmanaged function demands two levels of indirection



Поделиться:


Последнее изменение этой страницы: 2017-01-19; просмотров: 123; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.225.31.159 (0.02 с.)