Architecture Net

       

Службы обращения к платформе: Plnvoke (Platform Invocation Services)


Службы обращения к платформе, или Plnvoke (Platform Invocation Services,), делают неуправляемые экспортируемые динамически подключаемой библиотекой (DLL) функции доступными для управляемой программы клиента. Службы обращения к платформе Plnvoke (Platform Invocation Services) позволяют сделать это для любой управляемой программы, написанной на любом языке программирования .NET. Заметим, что Plnvoke является не именем класса или метода, а мнемоническим именем для Platform Invocation Services (Службы обращения к платформе). Службы обращения к платформе Plnvoke (Platform Invocation Services) следят за маршалингом между типами данных общеязыковой среды выполнения CLR и типами собственных данных, и играют роль моста, благодаря которому преодолеваются прочие различия между управляемой и неуправляемой средой запуска программ. Несмотря на то, что службы обращения к платформе PInvoke (Platform Invocation Services) изначально использовались для доступа к интерфейсам 32-разрядных Windows-приложений (Win32 API), они могут использоваться и для вызовов унаследованных динамически подключаемых библиотек (DLL). К сожалению, применение PInvoke (Platform Invocation Services, Службы обращения к платформе) в большинстве случаев оказывается дорогой с односторонним движением. Службы обращения к платформе можно использовать для вызова из управляемой программы неуправляемых функций динамически подключаемой библиотеки (DLL) и, конечно, для возврата в управляемую программу. Службы обращения к платформе PInvoke (Platform Invocation Services) используются для доступа к глобальным экспортированным функциям динамически подключаемых библиотек (DLL), поэтому, даже если динамически подключаемая библиотека (DLL) экспортирует методы класса, они остаются недоступными через PInvoke (Platform Invocation Services, Службы обращения к платформе).

В принципе, средств C++ достаточно, чтобы даже не задумываться о существовании служб обращения к платформе PInvoke (Platform Invocation Services). Ведь в отличие от других языков .NET, Visual C++ .NET позволяет смешивать управляемый и неуправляемый код непосредственно в вашей программе. Таким образом, чтобы вызвать функцию динамически подключаемой библиотеки (DLL) из кода на управляемом C++ вы можете просто вызвать собственный код на неуправляемом C++, который, в свою очередь, обычным образом вызовет неуправляемую функцию динамически подключаемой библиотеки (DLL). Однако вы можете использовать и службы обращения к платформе PInvoke (Platform Invocation Services) для непосредственного вызова из кода на управляемом C++ неуправляемого кода динамически подключаемой библиотеки (DLL), как это показано в следующем примере кода.


//PInvoke.срр

fusing <mscorlib.dll>

using namespace System;

// использование пространства имен Система;

using namespace System::Runtime::InteropServices;

// использование пространства имен

// Система::Время выполнения::InteropServices;

typedef void* HWND;

[Dlllmport("user32")]

extern "C" int MessageBoxA( // интерфейс 32-разрядных



// Windows-приложений (Win32 API)

HWND hWnd, // дескриптор окна владельца

String* pText, // текст окна сообщений

String* pCaption, // заголовок окна сообщений

unsigned int uType // стиль окна сообщений

);

void main(void) {

String* pText = L"Hello PInvoke!"; // Привет PInvoke!

String* pCaption = L"PInvoke Example"; // Пример PInvoke

MessageBoxA(0, pText, pCaption, 0); }

В результате выполнения этой программы будет выведено окно сообщения, показанное на рис. 15.7.




Рис. 15.7. Это окно сообщения будет выведено при выполнении программы PInvoke.cpp

В приведенном примере PInvoke (Platform Invocation Services, Службы обращения к платформе) не показано, как службы обращения к платформе PInvoke (Platform Invocation Services) автоматически выполняют маршалинг выходных параметров. Это связано с тем, что MessageBox имеет только входные параметры. В следующем примере вызываются интерфейсы прикладных программ (API) GetComputerName и GetLastError посредством служб обращения к платформе PInvoke (Platform Invocation Services)

Первый параметр функции GetComputerName с именем IpBuffer, является выходным указателем на буфер, в который записывается строка с завершающим нулем, содержащая имя компьютера в случае успешного выполнения функции Второй параметр IpnSize является и входным, и выходным. В случае использования его в качестве входного параметра, в нем задается длина буфера IpBuffer в символах TCHAR. В случае использования его в качестве выходного параметра в нем указывается фактическая длина имени компьютера в символах TCHAR, которая содержится в IpBuffer, причем завершающий нулевой символ при подсчете длины не учитывается. Возвращаемое значение указывает, было ли успешным выполнение функции. Ненулевое значение указывает на ее успешное выполнение, а нулевое — на ошибку. Если возвращенное значение равно нулю, можно использовать функцию GetLastError для определения причины ошибки. Например, если буфер оказался недостаточно длинным для имени компьютера, эта функция вернет константу ERROR_BUFFER_OVERFLOW, имеющую значение 111. Если вы хотите попробовать самостоятельно использовать службы обращения к платформе PInvoke (Platform Invocation Services), и не будете против приложить некоторые усилия, то можете вызвать функцию интерфейса прикладных программ (API) FormatMessage для перевода этого номера ошибки в более осмысленную строку. Если вы это сделаете, и в достаточной мере укоротите длину буфера, то получите описание ошибки: "The File name is too long" ("Имя файла слишком длинное"). Прототипы функций GetComputerName и GetLastError приведены ниже:



BOOL GetComputerName( // ЛОГИЧЕСКАЯ (БУЛЕВА)

LPTSTR IpBuffer, // имя компьютера

LPDWORD IpnSize // размер буфера для имени

) ;

DWORD GetLastError(VOID) ;

В следующем примере показано, как вызвать функции GetLastError и GetComputerName из кода на управляемом C++ с помощью служб обращения к платформе РInvoke (Platform Invocation Services). Обе эти функции интерфейса прикладного программирования находятся в библиотеке Kernel32 .dll, поэтому атрибут [Dlllmport ("Kernel32" ) ] использован в обоих случаях. Заметим, что маршалинг для каждого выходного параметра выполняется автоматически. Хотя это и не показано в данном простом примере, для управления деталями маршалинга, выполняемого службами обращения к платформе PInvoke (Platform Invocation Services), можно использовать атрибуты. Впрочем, это необходимо только в том случае, если маршалинг, выполняемый по умолчанию службами обращения к платформе PInvoke (Platform Invocation Services), является неудовлетворительным.

//PInvokeOutParam.cpp

fusing <mscorlib.dll>

using namespace System;

// использование пространства имен Система;

using namespace System::Runtime::InteropServices;

// использование пространства имен

// Система::Время выполнения::InteropServices;

typedef int BOOL; // ЛОГИЧЕСКИЙ (БУЛЕВ)

typedef unsigned long DWORD; // без знака

#define MAX_COMPUTERNAME_LENGTH 31

[Dlllmport("Kernel32")]

extern "C" BOOL GetComputerName(

signed char *lpBuffer, UInt32* IpnSize); // символ

// со знаком

*lpBuffer

[Dlllmport("Kernel32")]

extern "C" DWORD GetLastError();

void main(void) {

signed char * IpBuffer = // символ со знаком

new signed char[MAX_COMPUTERNAME_LENGTH + 1]; // новый символ

// со знаком

UInt32 size = MAX_COMPUTERNAME_LENGTH + 1; // размер

BOOL bResult = GetComputerName(IpBuffer, Ssize);

if (bResult)

{

String *pstrComputerName = // Строка

new String((signed char *)IpBuffer); // новая Строка ((символ со знаком *)

IpBuffer);

Console::WriteLine(

"Computer Name: {0}", pstrComputerName); // Имя компьютера

}

else

{

DWORD dwLastError = GetLastError ();

Console::WriteLine(

"Last Error: {0}", _box(dwLastError)); // Последняя

// ошибка

}

}

Когда вы запустите на выполнение пример PInvokeOutParam, то увидите нечто подобное приведенному ниже, за исключением того, что будет указано реальное имя вашего компьютера, а не моего.

Computer Name: PT-2HBHVPJUGOT9

CompEbook.ru Железо, дизайн, обучение и другие


Содержание раздела