Грамотная документация — залог здоровья и спокойствия программиста. Причем начинающего программиста, так как эксперт проблему решит намного быстрее. Да и не впервой ему — эксперту сталкиваться с плохой документацией, с программным кодом без комментариев и прочими неприятными вещами.
Одной из самых объемных и важных документаций для программистов является MSDN (Microsoft Developer Network). Для низкоуровневых программистов и программистов драйверов существует отдельная документация WDK (Windows Driver Kit), входящая в состав MSDN. В MSDN перечислены функции, параметры к ним, объяснения, примеры кода и многое другое.
Большая документация — сложный продукт. В любом сложном продукте есть недочеты, ошибки и недоработки. Встречаются они и в документации, ведь все мы люди, все мы ошибаемся. Недавно с такой ошибкой столкнулся и я.
Операционная система Windows предоставляет специальную функцию, которая позволяет отслеживать различные изменения в системном реестре указанного ключа. Она есть как в пользовательском пространстве (RegNotifyChangeKeyValue), так и в пространстве ядра (ZwNotifyChangeKey), там, где работает сама операционная система и драйверы. Этой функцией пользуются как антивирусные продукты, так и вредоносный код, который следит за изменениями своих вредоносных веток антивирусом (обычно это лечение веток реестра).
Прототип функции ZwNotifyChangeKey выглядит так:
NTSTATUS ZwNotifyChangeKey( __in HANDLE KeyHandle, __in_opt HANDLE Event, __in_opt PIO_APC_ROUTINE ApcRoutine, // указатель на нашу функцию __in_opt PVOID ApcContext, __out PIO_STATUS_BLOCK IoStatusBlock, __in ULONG CompletionFilter, __in BOOLEAN WatchTree, __out_bcount_opt(BufferSize) PVOID Buffer, __in ULONG BufferSize, __in BOOLEAN Asynchronous );
Через параметр KeyHandle необходимо передать дескриптор открытого ключа, изменения которого мы хотим отслеживать. Параметр ApcRoutine — это указатель на нами реализованную функцию, которая будет вызываться в случае изменений в указанной ветке реестра.
Функция должна быть определена так:
typedef VOID (NTAPI *PIO_APC_ROUTINE) ( IN PVOID ApcContext, IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved )
Не суть важно, что тут за параметры, главное — то, что у функции три аргумента. Это важно.
В одном из драйверов мне понадобилась эта функция. Я написал весь сопутствующий код, использовал функцию, скомпилировал драйвер, положил в нужное место и запустил. Система упала в BSOD. ‘Не в первый и не в последний раз’, — подумал я и начал проверять параметры функции. Все было идеально, все было правильно, а BSOD повторялся каждый раз.
Google не смог мне помочь с данной проблемой и пришлось разбираться самому. Потратив некоторое количество часов, я выяснил, что в недрах операционной системы при определенных обстоятельствах указатель PIO_APC_ROUTINE трактуется совершенно по-другому, как указатель на структуру WORK_QUEUE_ITEM, в которой содержится указатель на нами определенную функцию. И этого не было в документации, эту информацию я даже не смог найти в сети.
Структура выглядит следующим образом:
typedef struct _WORK_QUEUE_ITEM { LIST_ENTRY List; PWORKER_THREAD_ROUTINE WorkerRoutine; // указатель на нашу функцию __volatile PVOID Parameter; } WORK_QUEUE_ITEM, *PWORK_QUEUE_ITEM;
Функция должна быть определена так:
typedef VOID (*PWORKER_THREAD_ROUTINE)( IN PVOID Parameter )
И она принимает всего один параметр. И это важно.
Довольно быстро я переписал код, и драйвер перестал рушить операционную систему. Сразу после этого я написал письмо в компанию Microsoft где указал им на это досадное упущение с их стороны. Примерно через три часа (около четырех часов утра) я получил от них ответ, в котором они обещали исправить документацию в ближайшее время (в конце месяца).
Ошибки бывают разные, но ошибки в документации дорогого стоят. До следующих ошибок, а они обязательно будут.
Онлайновая версия MSDN имеет тупейший поиск (кроме WIN API функций искать что-либо еще безрезультатно) и навигацию. Для поиска юзается гугл с запросом _value_ inurl:»msdn» = )
Угу, с поиском у них какие-то проблемы, но я обычно юзаю или оффлайн версию MSDN или тоже гугл :)
> MSDN (Microsoft Development)
«Microsoft Developer Network» однако
Угу, проглядел что-то. Поправлю :)