Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows

Создание объекта ядра


Когда процесс инициализируется в первый paз, таблица описателей еще пуста. Но стоит одному из его потоков вызвать функцию, создающую объект ядра (например, CreateFtleMapping), как ядро выделяет для этого объекта блок памяти и инициализирует его, далее ядро просматривает таблицу описателей, принадлежащую данному процессу, и отыскивает свободную запись. Поскольку таблица еще пуста, ядро обнаруживает структуру с индексом 1 и инициализирует ее. Указатель устанавливается на внутренний адрес структуры данных объекта, маска доступа — на доступ без ограничений и, наконец, определяется последний компонент — флаги (О флагах мы поговорим позжс, в разделе о наследовании )

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

HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD dwStackSize,
PTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreationFlags,
PDWORD pdwfhreadId);

HANDEE CreateFile(
PCTSTR pszFileName,
DWORD dwDesiredAccebS,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttnbutes,
HANDEE hTemplateFile);

HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMdximumSizcHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);

HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,

LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);

Все функции, создающие объекты ядра, возвращают описатели, которые привязаны к конкретному процессу и могут быть использованы в любом потоке данного процесса Значение описателя представляет собой индекс в таблице описателей, принадлежащей процессу, и таким образом идентифицирует место, где хранится информация, связанная с объектом ядра. Вот поэтому при отладке своего приложения и просмотре фактического значения описателя объекта ядра Вы и видите такие малые величины: 1, 2 и т. д. Но помните, что физическое содержимое описателей не задокументировано и может быть изменено. Кстати, в Windows 2000 это значение определяет, по сути, не индекс, а скорее байтовое смещение нужной записи от начала таблицы описателей.


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

Если Вы передаете неверный индекс (описатель), функция завершается с ошибкой и GetLastError возвращает 6 (ERROR_INVALID_HANDLE). Это связано с тем, что на самом деле описатели представляют собой индексы в таблице, их значения привязаны к конкретному процессу и недейовительны в других процессах.

Если вызов функции, создающей объект ядра, оказывается неудачен, то обычно возвращается 0 (NULL). Такая ситуация возможна только при острой нехватке памяти или при наличии проблем с защитой. К сожалению, отдельные функции возвращают в таких случаях пе 0, а -1 (INVALID_HANDLE_VALUE) Например, если CreateFile не сможет открыть указанный файл, она вернет именно INVALID_HANDLE_VALUE. Будьте очень осторожны при проверке значения, возвращаемого функцией, которая создает объект ядра. Так, для CreateMutex проверка на INVALID_HANDlE_VALUE бессмысленна:

HANDLE hMutex = CreateMutex(...);
if (hMutex == lNVALID_HANDLE_VALUE) {
// этот код никогда не будет выполнен, так как
// при ошибке CreateMutex возвращает NLlLL
}

Точно так же бессмыслен и следующий код:

HANDIE hFile = CreateFile(.. );
if (hFile — NULL} {
// и этот код никогда не будет выполнен, так как
// при ошибке CreateFile возвращает lNVALID_HANDLE_VALUE (-1)
}


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