エクスポート ドライバーの作成

エクスポート ドライバーは、他のさまざまなハードウェア固有またはデバイス スタック固有のコンポーネントによって読み込むことができるカーネルモード DLL ですが、完全なカーネルモード ドライバーではなく、一部の特性が欠けています。 具体的には、エクスポート ドライバーにはディスパッチ テーブルがありません。また、ドライバー スタック内の場所が存在せず、サービス コントロール マネージャーのデータベースには、システム サービスとして定義するエントリがありません。 エクスポート ドライバーにはディスパッチ テーブルがありませんが、標準ドライバーにディスパッチ ルーチンを装備できます。 標準ドライバーは、ディスパッチ ルーチンを自身のディスパッチ テーブルに挿入します。 エクスポート ドライバーには、呼び出されることのないスタブ DriverEntry ルーチンがあります。

カーネルモード エクスポート ドライバーは、基になるスタックやハードウェアの特性に依存しない、ドライバー ペアの一部を実装するのに特に適しています。

Windows には、他のドライバーによって読み込まれる複数のエクスポート ドライバーが搭載されています。たとえば次のようなドライバーです。

  • SCSI ポート ドライバー
  • テープ クラス ドライバー
  • IDE コントローラー ドライバーは、すべてをシステムが提供するエクスポート ドライバーです

標準ドライバーは、エクスポート ドライバーとしても機能します。 1 つのドライバーを両方の役割で機能させるには、エクスポート ドライバーとしてビルドし、通常のドライバーとして読み込む必要があります。

エクスポート ドライバーのビルド

Visual Studio でエクスポート ドライバーを作成するには、次の手順に従います。

  1. テンプレートから新しいプロジェクトを作成します (空の WDM ドライバーなど)。
  2. 次のように、モジュール定義ファイルをプロジェクトに追加します。
LIBRARY mydriver.sys
EXPORTS
  DllInitialize PRIVATE
  DllUnload PRIVATE

カーネルモード DLL のエントリ ポイントは常に DllInitialize です。 システムは、DLL が読み込まれた直後に、カーネルモード DLL の DllInitialize ルーチンを呼び出します。 エクスポート ドライバーは、DllInitialize ルーチンを提供する必要があります。 DLL 内の他のルーチンに必要なリソースは、DllInitialize ルーチンを使用して取得または初期化できます。

DLLENTRY マクロを使用してエントリ ポイントを指定することはできません。

NTSTATUS DllInitialize(
  _In_ PUNICODE_STRING RegistryPath
);

RegistryPath は、DLL のレジストリ キーである HKEY_LOCAL_MACHINE\CurrentControlSet\Services\DllName へのパスを指定するカウントされた Unicode 文字列へのポインターです。 DLL ルーチンでは、このキーを使用して DLL 固有の情報を格納できます。 DllInitialize が終了すると、RegistryPath が指すバッファーが解放されます。 したがって、DLL がキーを使用する場合、DllInitialize はキー名を複製する必要があります。

ビルド プロセスでは、.lib 拡張子を持つエクスポート ライブラリと、.sys 拡張子を持つエクスポート ドライバーが生成されます。

エクスポート ドライバーからの関数のインポート

エクスポート ドライバーによってエクスポートされた関数をインポートするには、ntdef.h で定義されている DECLSPEC_IMPORT マクロを使用して関数を宣言する必要があります。 次に例を示します。

DECLSPEC_IMPORT int LoadPrinterDriver (int arg1); 

このマクロは、必要な場合はそれらのプラットフォームで __declspec(dllimport) ストレージ クラス宣言に解決され、必要でないプラットフォームでは何も解決されません。

エクスポート ドライバーでは、エクスポートする関数を DECLSPEC_EXPORT マクロで宣言する必要があります。 このマクロは、必要な場合はそれらのプラットフォームで __declspec(dllexport) ストレージ クラス宣言に解決され、必要でないプラットフォームでは何も解決されません。 エクスポート ドライバーが標準ドライバーにディスパッチ ルーチンを提供する場合、そのルーチンをエクスポートする必要はありません。

エクスポート ドライバーの読み込みとアンロード

エクスポート ドライバーは、%Windir%\System32\Drivers ディレクトリにインストールする必要があります。 Windows 2000 以降、オペレーティング システムは、エクスポート ドライバーの関数が他のドライバーによってインポートされた回数を示す参照カウントを保持します。 システムは、インポート中のドライバーのいずれかがアンロードされるたびに、このカウントをデクリメントします。 参照カウントが 0 になると、システムはエクスポート ドライバーをアンロードします。 ただし、エクスポート ドライバーには、標準のエントリ ポイントとアンロード ルーチン、DllInitialize および DllUnload が含まれている必要があります。または、オペレーティング システムは、この参照カウント メカニズムをアクティブ化しません。

システムは、DLL をアンロードするときにカーネルモード DLL の DllUnload ルーチンを呼び出します。

NTSTATUS DllUnload(void);

エクスポート ドライバーは、DllUnload ルーチンを提供する必要があります。 DllUnload ルーチンを使用して、DLL 内のルーチンによって使用されるすべてのリソースを解放できます。