Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab7.doc
Скачиваний:
4
Добавлен:
12.11.2019
Размер:
286.72 Кб
Скачать

11. Дублирование описателей объектов

Последний механизм совместного использования объектов ядра несколькими процессами требует функции DuplicateHandle;

BOOL DuplicateHandle( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, PHANDLE phTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);

Говоря по-простому, эта функция берет запись в таблице описателей одного процесса и создает ее копию в таблице другого. DuplicateHandle принимает несколько параметров, но на самом деле весьма незамысловата. Обычно ее применение требует наличия в системе трех разных процессов.

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

Второй параметр, hSourceHandle, — описатель объекта ядра любого типа. Однако его значение специфично не для процесса, вызывающего DuplicateHandle, а для того, на который указывает описатель hSourceProcessHandle. Параметр phTargetHandle — это адрес переменной типа HANDLE, в которой возвращается индекс записи с копией описателя из процесса-источника. Значение возвращаемого описателя специфично для процесса, определяемого параметром bTargetProcessHandle.

Предпоследние два параметра DuplicateHandle позволяют задать маску доступа и флаг наследования, устанавливаемые для данного описателя в процессе-приемнике. И, наконец, параметр dwOptions может быть 0 или любой комбинацией двух флагов. DUPLICATE_SAME_ACCESS и DUPLICATE_CLOSE_SOURCE.

Первый флаг подсказывает DuplicateHandle: у описателя, получаемого процессом-приемником, должна быть та же маска доступа, что и у описателя в процессе-источнике Этот флаг заставляет DuplicateHandle игнорировать параметр dwDesiredAccess.

Второй флаг приводит к закрытию описателя в процессе-источнике. Он позволяет процессам обмениваться объектом ядра как эстафетной палочкой. При этом счетчик объекта не меняется.

Представьте, что один процесс имеет доступ к объекту, к которому хочет обратиться другой процесс, или что один процесс хочет предоставить другому доступ к «своему» объекту ядра. Например, если процесс S имеет доступ к объекту ядра и нужно, чтобы к этому объекту мог обращаться процесс Т, используйте DuplicateHandle так:

// весь приведенный ниже код исполняется процессом S // создаем объект-мьютекс, доступный процессу S HANDLE hObjProcessS = CreateMutex(NULL, FALSE, NULL);

// открываем описатель объекта ядра "процесс Т" HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessIdT); HANDLE hObjProcessT; // неинициализированный описатель,

// связанный с процессом Т // предоставляем процессу Т доступ к объекту-мьютексу DuplicateHandle(GetCurrentProcess(), hObjProcessS, hProcessT, &hObjProcessT, 0, FALSE, DUPLICATE_SAME_ACCESS);

// используем какую-нибудь форму межпроцессной связи, чтобы передать // значение описателя из hObjProcessS в процесс Т

// связь с процессом Т больше не нужна CloseHandle(hProcessT),

// если процессу S не нужен объект-мьютекс, он должен закрыть его CloseHandle(hObjProcessS);

Вызов GetCurrentProcess возвращает псевдоописатель, который всегда идентифицирует вызывающий процесс, в данном случае — процесс S. Как только функция DuplicateHandle возвращает управление, bObjProcessT становится описателем, связанным с процессом Т и идентифицирующим тот же объект, что и описатель bObjProcessS (когда на него ссылается код процесса S). При этом процесс S ни в коем случае не должен исполнять следующий код:

// процесс S никогда не должен пытаться исполнять код, // закрывающий продублированный описатель CloseHandle(hObjProcessT);

Если процесс S выполнит этот код, вызов может дать (а может и не дать) ошибку. Он будет успешен, если у процесса S случайно окажется описатель с тем же значением, что и в hObjProcessT. При этом процесс S закроет неизвестно, какой объект, и что будет потом — остается только гадать.

Теперь о другом способе применения DuplicateHandle. Допустим, некий процесс имеет полный доступ (для чтения и записи) к объекту «проекция файла» и из этого процесса вызывается функция, которая должна обратиться к проекции файла и считать из нее какие-то данные. Так вот, если мы хотим повысить отказоустойчивость приложения, то могли бы с помощью DuplicateHandle создать новый описатель существующего объекта и разрешить доступ только для чтения. Потом мы передали бы этот описатель функции, и та уже не смогла бы случайно что-то записать в проекцию файла.

int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PSTR pszCmdLine, int nCmdShow) {

// создаем объект "проекция файла", // его описатель разрешает доступ как для чтения, так и для записи HANDLE hFileMapRW = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGF_READWRITE, 0, 10240, NULL);

// создаем другой описатель на тот же обьект; // этого описатель разрешает дocтyп только для чтения HANDLE hFileMapRO;

DuplicateHandle(GetCurrentProcess(), hFileMapRW, GetCurrentProcess(), &hFileMdpRO, FILE_MAP_READ, FALSE, 0);

// вызываем функцию, которая не должна ничего записывать в проекцию файла ReadFromTheFileMapping(hFileMapRO);

// закрываем объект "проекция файла" , доступный только для чтения CloseHandle(hFileMapRO);

// проекция файла нам по-прежнему полностью доступна через hFileMapRW . . . // если проекция файла больше не нужна основному коду, закрываем ее CloseHandle(hFileMapRW); }

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]