Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСиСП. Часть 3. Контрольная работа 1.doc
Скачиваний:
39
Добавлен:
01.04.2014
Размер:
238.59 Кб
Скачать
    1. Работа службы Platform Invoke. Запуск функций WinApi

Наиболее часто служба Platform Invoke применяется для запуска функций WinAPI, находящихся в файлах dll. Когда служба вызывает функцию, совершаются следующие операции:

  • обнаружение необходимой библиотеки;

  • загрузка найденной библиотеки в оперативную память;

  • обнаружение адреса библиотеки в памяти и передача аргументов функции, с их преобразованием при необходимости;

  • после этого Platform Invoke передает управление неуправляемой функции и ждет завершения.

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

Windows API — это набор функций, входящий в состав семейства операционной системы Microsoft Windows. Преимуществом использования этих функций является то, что они уже полностью готовы и не приходится тратить время на реализацию подобной функциональности. Однако с ними тяжело работать — в частности, довольно сложно отлавливать исключения, возникающие в работе приложения.

Первым шагом в запуске неуправляемой функции является объявление функции. Функция должна быть статической (static) и внешней (extern). Далее следует импорт библиотеки, содержащей эту функцию. Импортировать библиотеку нужно, используя атрибут DllImport, который находится в пространстве имен System.Runtime.InteropServices. Атрибут DllImport нуждается в названии библиотеки и может принимать один из параметров, указанных в таблице 2:

Таблица 2. Некоторые параметры атрибута DllImport

Аргумент

Описание

EntryPoint

Указывает название функции. Если название метода совпадает с названием неуправляемой функции, то этот аргумент ставить необязательно

CharSet

Указывает кодировку строковых значений. Значением по умолчанию является ANSI

ExactSpelling

Предотвращает изменение точки входа (entry point) при изменении кодировки. Если значение аргумента CharSet установлено в Auto, то значение по умолчанию — true, в противном случае — false

CallingConvention

Указывает тип конвертирования аргументов, передаваемых в функцию. Значением по умолчанию является WinAPI

PreserveSig

Указывает, что сигнатура управляемого метода не должна трансформироваться в сигнатуру неуправляемого метода, который возвращает значение типа HRESULT и может иметь дополнительные аргументы в качестве возвращаемых значений Значением по умолчанию является true (сигнатура не должна трансформироваться).

SetLastError

Указывает возможность использования метода GetLastError для обработки ошибок при выполнении неуправляемого метода. Значением по умолчанию является false

Аргументы, которые принадлежат к простым типам данных, такие как byte или int, Platform Invoke автоматически преобразовывает в соответствующие типы в неуправляемой платформе. В таблице 3 приводится соответствие типов данных в функциях WinAPI и библиотеки .NET Framework.

Таблица 3. Типы данных в неуправляемом и управляемом кодах

Тип данных в неуправляемом коде

Тип данных в .NET Framework (C#)

HANDLE

Int

BYTE

Byte

SHORT

Short

WORD

Ushort

INT

Int

UINT

Uint

LONG

Int

ULONG

Uint

BOOLEAN

Int

CHAR

Char

LPSTR (и большинство строковых типов данных)

String для входящих аргументов, StringBuilder для двусторонних аргументов

FLOAT

Float

DOUBLE

double

При указании библиотеки не нужно указывать путь до неё. CLR ищет библиотеку в каталоге приложения, затем в подкаталогах, в папке Windows и папке Window\System32. При указании адреса библиотеки могут возникнуть исключения — CLR проверяет только его. Например, если был указан адрес "C:\Windos\system32\someDll.dl", а у пользователя операционная система располагается на диске D — приложение работать не будет. При использовании функций WinAPI сами файлы библиотек не нужно включать в проект.

  1. C++ .NET. Совмещение управляемого и неуправляемого кодов

Язык программирования C++ .NET является единственным, который позволяет создавать как управляемый, так и неуправляемый код. Это дает возможность не только использовать неуправляемый библиотечный код, но и смешивать управляемый и неуправляемый коды в одном приложении.

В приводимых ниже примерах кроме языка программирования C# будет использоваться язык C++.

Сначала создается C++ Win32 Console Project, то есть неуправляемое консольное приложение на C++. Visual Studio с версии .NET 2005 позволяет в широких пределах смешивать управляемый и неуправляемый коды.

// Транслятору задали опцию /clr.

// Эта опция преобразует все объявляемые в программе типы.

// От имени объекта элементарного типа (например, int) можно

// вызвать методы базового класса object.

// Но только вызываются они лишь из фрагментов управляемого

кода.

// Иначе – сообщение транслятора:

// ... managed type or function cannot be used in an unmanaged function

#include "stdafx.h"

#include <iostream>

using namespace std;

#using <mscorlib.dll> // Ядро CLR

using namespace System;

class uClass; // Предварительное неполное объявление класса.

class mClass; // Предварительное неполное объявление класса.

#pragma managed

class mClass

{

public:

uClass *ucP;

mClass *mcP;

int x;

mClass()

{

// Только в неуправляемом коде!

// cout << "Ha-Ha-Ha";

Console::WriteLine("mClass");

// Легко посмотрели значение непроинициализированной переменной.

Console::WriteLine(x.ToString());

}

~mClass()

{

Console::WriteLine("~mClass");

}

void mcF0()

{

Console::WriteLine("mcF0()");

}

mClass* mcGenerator();

};

#pragma unmanaged

class uClass

{

public:

uClass *ucP;

mClass *mcP;

int x;

uClass()

{

// Только в управляемом коде!

//Console::WriteLine("Ha-Ha-Ha");

printf("uClass\n");

}

~uClass()

{

printf("~uClass\n");

}

void ucF0()

{

cout << "ucF0()\n";

}

uClass* ucGenerator();

};

// Судя по всему, функция Управляемого

// класса может быть НеУправляемой!

mClass* mClass::mcGenerator()

{

//x.ToString();

//Console::WriteLine("Ha-Ha-Ha");

cout << "Ha-Ha-Ha from unmanaged function of managed class!" << endl;

ucP = new uClass();

ucP->ucF0();

delete ucP;

return new mClass();

}

#pragma managed

// А сделать Управляемой функцию НеУправляемого класса невозможно.

// Прагма managed для функции - члена неуправляемого класса игнорируется.

uClass* uClass::ucGenerator()

{

cout << "Ha-Ha-Ha from function of unmanaged class!" << endl;

//Console::WriteLine("Ha-Ha-Ha");

//x.ToString();

mcP = new mClass();

mcP->mcF0();

delete mcP;

return new uClass();

}

#pragma unmanaged

int _tmain(int argc, _TCHAR* argv[])

{

void *xPoint;

int x = 125;

// Только не смешивать!

//Console::WriteLine("Ha-Ha-Ha");

mClass *mc = new mClass();

mc->mcF0();

xPoint = mc->mcGenerator();

delete (mClass*)xPoint;

delete mc;

uClass *uc = new uClass();

uc->ucF0();

xPoint = uc->ucGenerator();

delete (uClass*)xPoint;

delete uc;

return 0;

}