Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
АОПИ. Старое / АОПИ. Глава 2. Конспекты (02_04_19).rtf
Скачиваний:
65
Добавлен:
10.09.2019
Размер:
363.46 Кб
Скачать

3. После этого вызова система проверяет, существует ли уже объект ядра с таким же именем. Если существует, то

1) Система проверяет тип этого объекта. Если не совпадает, то вызов CreateMutex второго процесса заканчивается неудачно, возвращается NULL.

2) Система проверяет права доступа. Если второй процесс имеет полные права на доступ к существующему объекту ядра, то система создает новую запись в таблице описателей второго процесса (Удачное выполнение, возврат дескриптора.) В противном случае — возврат NULL (неудача).

3) Если и типы объектов совпали, и права доступа у второго процесса имеются, то второй процесс получает описатель существующего объекта (новый объект не создается!).

4. Если второй процесс получил описатель объекта, то счетчик этого объекта увеличиться на 1. Теперь этот объект не уничтожиться, пока оба процесса не закроют свои описатели этого объекта функцией CloseHandle().

5. Приложение может определить, что оно делает: создает новый объект ядра или просто открывает уже существующий. Нужно просто вызвать GetLastError сразу же после вызова одной из Create-функций:

DWORD M_ERROR_TYPE = GetLastError();

if (M_ERROR_TYPE == ERROR_ALREADY_EXISTS) {

/// Ошибка. Объект данного типа с данным именем уже существует

}

else if (M_ERROR_TYPE == ERROR_INVALID_HANDLE) {

/// Ошибка. Объект другого типа, но с данным именем уже существует

}

else {

/// Все в порядке. Мы создали новый объект

}

Таким образом, создавая объект с определенным именем, вы никак не застрахованы от того, что в системе ещё нет объекта ядра с таким же именем. И что ещё более важно, все эти объекты делят единое пространство имен (два объекта с одним и тем же именем не могут существовать в одно и то же время).

Open-функции

Если же ставиться задача открыть уже существующий объект ядра, то следует использовать специальные Open-функции. Такие функции имеют всего три параметра: DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName.

Пример такой функции.

HANDLE OpenMutex(

IN DWORD dwDesiredAccess,

IN BOOL bInheritHandle,

IN LPCTSTR lpName

);

Последний параметр, lpName, определяет имя объекта ядра. В нем нельзя передавать NULL.

Функция работает следующим образом.

1. Функция просматривает единое пространство имен объектов ядра, пытаясь найти совпадение.

2. Если объекта ядра с указанным именем нет, функция возвращает NULL, a GetLastError — код 2 (ERROR_FILE_NOT_FOUND).

3. Если объект ядра с заданным именем существует и если его тип идентичен тому, что Вы указали, система проверяет, разрешен ли к данному объекту доступ запрошенного вида (через параметр dwDesiredAccess).

4. Если такой вид доступа разрешен, таблица описателей в вызывающем процессе обновляется, и счетчик числа пользователей объекта возрастает на 1. Если Вы присвоили параметру bInheritHandle значение TRUE, то получите наследуемый описатель.

Главное отличие между вызовом Create- и Open-функций в том, что при отсутствии указанного объекта Create-функция создает его, а Open-функция просто уведомляет об ошибке.

Применение.

Именованные объекты часто применяются для того, чтобы не допустить запуска нескольких экземпляров одного приложения. Для этого Вы просто вызываете одну из Create-функций в своей функции main и создаете некий именованный объект. Какой именно — не имеет значения. Сразу после Create-функции Вы должны вызвать GetLastError. Если она вернет ERROR_ALREADY_EXISTS, значит, один экземпляр Вашего приложения уже выполняется и новый его экземпляр можно закрыть.

Пример (C++).

Первый экземпляр программы выдаст сообщение «Добро пожаловать в программу!». Второй экземпляр программы выдаст сообщение «Программа уже запущена!».

Достаточно запустить программу дважды, чтобы увидеть эффект.

#include <iostream>

#include <windows.h> /// обязательно подключаем

using namespace std;

int main() {

setlocale(LC_ALL, "Russian"); /// русский язык в консоли

HANDLE h1 = CreateMutex(NULL, FALSE, "{SPECCODEFORYOURAPP-123412341234}"); /// создаем объект с длинным именем

if (GetLastError() == ERROR_ALREADY_EXISTS){

/// объект уже создан

cout << "Программа уже запущена!";

cin.get(); /// чтение символа — пауза перед выходом

return 0; /// выходим из программы

}

cout << "Добро пожаловать в программу!";

/// делаем, что хотим

cin.get(); /// чтение символа — пауза перед выходом

CloseHandle(h1); /// не забываем закрывать дескриптор

return 0;

}