プロバイダー モジュールの初期化と登録

プロバイダー モジュールは、ネットワーク モジュール レジストラー (NMR) に登録する前に、多数のデータ構造を初期化する必要があります。 これらの構造体には、NPI_MODULEID 構造体、NPI_PROVIDER_CHARACTERISTICS 構造体、NPI_REGISTRATION_INSTANCE 構造体 (NPI_PROVIDER_CHARACTERISTICS 構造体内に含まれます)、プロバイダー モジュールの登録コンテキストに使用されるプロバイダー モジュールによって定義された構造体が含まれます。

プロバイダー モジュールが、NPI 固有のプロバイダー特性を定義するネットワーク プログラミング インターフェイス (NPI) のプロバイダーとして自身を NMR に登録する場合、プロバイダー モジュールは、NPI によって定義されるプロバイダー特性構造のインスタンスも初期化する必要があります。

プロバイダー モジュールが NMR に登録されている限り、これらのデータ構造は現在でもすべて有効でメモリ内に常駐している必要があります。

たとえば、"EXNPI" NPI がヘッダー ファイル Exnpi.h で次のように定義するとします。

// EXNPI NPI identifier
const NPIID EXNPI_NPIID = { ... };

// EXNPI provider characteristics structure
typedef struct EXNPI_PROVIDER_CHARACTERISTICS_
{
  .
  . // NPI-specific members
  .
} EXNPI_PROVIDER_CHARACTERISTICS, *PEXNPI_PROVIDER_CHARACTERISTICS;

次に示すのは、EXNPI NPI のプロバイダーとして自身を登録するプロバイダー モジュールが、これらのすべてのデータ構造を初期化する方法です。

// Include the NPI specific header file
#include "exnpi.h"

// Structure for the provider module's NPI-specific characteristics
const EXNPI_PROVIDER_CHARACTERISTICS NpiSpecificCharacteristics =
{
  .
  . // The NPI-specific characteristics of the provider module
  .
};

// Structure for the provider module's identification
const NPI_MODULEID ProviderModuleId =
{
  sizeof(NPI_MODULEID),
  MIT_GUID,
  { ... }  // A GUID that uniquely identifies the provider module
};

// Prototypes for the provider module's callback functions
NTSTATUS
  ProviderAttachClient(
    IN HANDLE NmrBindingHandle,
    IN PVOID ProviderContext,
    IN PNPI_REGISTRATION_INSTANCE ClientRegistrationInstance,
    IN PVOID ClientBindingContext,
    IN CONST VOID *ClientDispatch,
    OUT PVOID *ProviderBindingContext,
    OUT PVOID *ProviderDispatch
    );

NTSTATUS
  ProviderDetachClient(
    IN PVOID ProviderBindingContext
    );

VOID
  ProviderCleanupBindingContext(
    IN PVOID ProviderBindingContext
    );

// Structure for the provider module's characteristics
const NPI_PROVIDER_CHARACTERISTICS ProviderCharacteristics =
{
  0,
  sizeof(NPI_PROVIDER_CHARACTERISTICS),
  ProviderAttachClient,
  ProviderDetachClient,
  ProviderCleanupBindingContext,
  {
    0,
    sizeof(NPI_REGISTRATION_INSTANCE),
    &EXNPI_NPIID,
    &ProviderModuleId,
    0,
    &NpiSpecificCharacteristics
  }
};

// Context structure for the provider module's registration
typedef struct PROVIDER_REGISTRATION_CONTEXT_ {
  .
  . // Provider-specific members
  .
} PROVIDER_REGISTRATION_CONTEXT, *PPROVIDER_REGISTRATION_CONTEXT;

// Structure for the provider's registration context
PROVIDER_REGISTRATION_CONTEXT ProviderRegistrationContext =
{
  .
  . // Initial values for the registration context
  .
};

通常、プロバイダー モジュールは DriverEntry 関数内で自身を初期化します。 プロバイダー モジュールの主な初期化タスクは次のとおりです。

  • Unload 関数を指定します。 オペレーティング システムは、プロバイダー モジュールがシステムからアンロードされるときに、この関数を呼び出します。 プロバイダー モジュールがアンロード関数を提供しない場合、プロバイダー モジュールをシステムからアンロードすることはできません。

  • NmrRegisterProvider 関数を呼び出して、プロバイダー モジュールを NMR に登録します。

次に例を示します。

// Prototype for the provider module's unload function
VOID
  Unload(
    PDRIVER_OBJECT DriverObject
   );

// Variable to contain the handle for the registration
HANDLE ProviderHandle;

// DriverEntry function
NTSTATUS
  DriverEntry(
    PDRIVER_OBJECT DriverObject,
    PUNICODE_STRING RegistryPath
    )
{
  NTSTATUS Status;

  // Specify the unload function
  DriverObject->DriverUnload = Unload;

  .
  . // Other initialization tasks
  .

  // Register the provider module with the NMR
  Status = NmrRegisterProvider(
    &ProviderCharacteristics,
    &ProviderRegistrationContext,
    &ProviderHandle
    );

  // Return the result of the registration
  return Status;
}

プロバイダー モジュールが複数の NPI のプロバイダーである場合は、データ構造の独立したセットを初期化し、それをサポートする各 NPI に対して NmrRegisterProvider を呼び出す必要があります。 ネットワーク モジュールがプロバイダー モジュールとクライアント モジュールの両方 (つまり、1 つの NPI のプロバイダーであり、別の NPI のクライアント) である場合は、プロバイダー インターフェイス用とクライアント インターフェイス用の 2 つの独立したデータ構造セットを初期化し、NmrRegisterProviderNmrRegisterClient の両方を呼び出す必要があります。

プロバイダー モジュールは、DriverEntry 関数内から NmrRegisterProvider を呼び出す必要はありません。 たとえば、プロバイダー モジュールが複雑なドライバーのサブコンポーネントである場合、プロバイダー モジュールの登録は、プロバイダー モジュールのサブコンポーネントがアクティブ化される際にのみ発生する可能性があります。

プロバイダー モジュールの Unload 関数の実装に関する詳細については、「プロバイダー モジュールのアンロード」を参照してください。