WIA ミニドライバーのロードとアンロード
WIA デバイス ドライバーがインストールされると、WIA サービスは初回のドライバー読み込みが試行されます。 WIA ミニドライバーの IStiUSD::Initialize メソッドが呼び出され、次のタスクを実行する必要があります。
転送モードを確認して、このデバイス ドライバーを初期化しようとしている呼び出し元の意図を判断します。 これを行うには、IStiDeviceControl::GetMyDeviceOpenMode メソッドを呼び出します。
このドライバーがデバイスにアクセスするために適切なポートに対して CreateFile (Microsoft Windows SDK で説明) を呼び出すことができるように、インストールされているデバイスのポート名を取得します。 これを行うには、IStiDeviceControl::GetMyDeviceOpenMode メソッドを呼び出します。
デバイスをインストールした際に書き込まれた、そのデバイス特有のレジストリ設定を読み取ります。 これは、IStiUSD::Initialize に渡される hParametersKey パラメーターを使用することで実現できます。
WIA サービスは、ドライバーが最初に読み込まれるときに IStiUSD::Initialize メソッドを呼び出します。 IStiUSD::Initialize メソッドは、クライアントが従来の STI DDI を使用し、IStillImage::CreateDevice メソッドを呼び出す際にも呼び出されます。
IStiUSD::Initialize メソッドは、WIA ドライバーとデバイスを初期化して使用できるようにする必要があります。 WIA ドライバーは、後で必要になった場合に備えて、IStiDeviceControl インターフェイスのポインターを保存できます。 このインターフェイスを保存する前に、IStiDeviceControl::AddRef メソッドを呼び出す必要があります。 インターフェイスを保存する必要がない場合は、無視します。 IStiDeviceControl::AddRef を最初に呼び出していない場合は、IStiDeviceControl インターフェイスを解放しないでください。 この操作は、予期せぬ結果を引き起こす可能性があります。 デバイスの ポートに関する情報を取得するには、IStiDeviceControl COM インターフェイスが必要です。 CreateFile 関数の呼び出しで使用するポート名は、IStiDeviceControl::GetMyDevicePortName メソッドを呼び出すことで取得できます。 シリアル ポート デバイスなどの共有ポート上のデバイスの場合、IStiUSD::Initialize でポートを開くことは推奨されません。 ポートを開くのは、IStiUSD::LockDevice を呼び出す場合のみです。 高速アクセスを実現するために、ポートの閉じ処理は内部で制御する必要があります。 (IStiUSD::LockDevice と IStiUSD::UnLockDevice でポートを開閉するのは非常に非効率です。CreateFile は遅延を引き起こす可能性があるため、デバイスの動作が遅く感じられる場合もあります。)
WIA ドライバーが同じデバイス ポートで複数の CreateFile 呼び出しをサポートできない場合は、IStiDeviceControl::GetMyDeviceOpenMode メソッドを呼び出す必要があります。
WIA ドライバーは、返されたモード値の STI_DEVICE_CREATE_DATA フラグをチェックし、それに応じてポートを開く必要があります。
デバイス ポートを開く必要がある場合は、CreateFile の呼び出しを使用する必要があります。 ポートを開く場合は、FILE_FLAG_OVERLAPPED フラグを使用する必要があります。 これにより、デバイスにアクセスするときに、(Windows SDK ドキュメントで説明されている) OVERLAPPED 構造を使用できます。 重複した I/O を使用すると、ハードウェアへの応答性のあるアクセスを制御するのに役立ちます。 問題が検出されると、WIA ドライバーは CancelIo (Windows SDK ドキュメントで説明されている) を呼び出して、現在実行中のすべてのハードウェア アクセスを停止することができます。
次のコードは、IStiUSD::GetStatus メソッドの実装例を示しています。
STDMETHODIMP CWIADevice::Initialize(
PSTIDEVICECONTROL pIStiDeviceControl,
DWORD dwStiVersion,
HKEY hParametersKey)
{
if (!pIStiDeviceControl) {
return STIERR_INVALID_PARAM;
}
HRESULT hr = S_OK;
//
// Get the mode of the device to check why we were created. status, data, or both...
//
DWORD dwMode = 0;
hr = pIStiDeviceControl->GetMyDeviceOpenMode(&dwMode);
if(FAILED(hr)){
return hr;
}
if(dwMode & STI_DEVICE_CREATE_DATA)
{
//
// device is being opened for data
//
}
if(dwMode & STI_DEVICE_CREATE_STATUS)
{
//
// device is being opened for status
//
}
if(dwMode & STI_DEVICE_CREATE_BOTH)
{
//
// device is being opened for both data and status
//
}
//
// Get the name of the device port to be used in a call to CreateFile().
//
WCHAR szDevicePortNameW[MAX_PATH];
memset(szDevicePortNameW,0,sizeof(szDevicePortNameW));
hr = pIStiDeviceControl->GetMyDevicePortName(szDevicePortNameW,
sizeof(szDevicePortNameW)/sizeof(WCHAR));
if(FAILED(hr)) {
return hr;
}
//
// Open kernel-mode device driver. Use the FILE_FLAG_OVERLAPPED flag
// for proper cancellation
// of kernel-mode operations and asynchronous file IO.
// The CancelIo() call will function properly if this flag is used.
// It is recommended to use this flag.
//
m_hDeviceDataHandle = CreateFileW(szDevicePortNameW,
GENERIC_READ | GENERIC_WRITE, // Access mask
0, // Share mode
NULL, // SA
OPEN_EXISTING, // Create disposition
FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,
NULL );
m_dwLastOperationError = ::GetLastError();
hr = (m_hDeviceDataHandle != INVALID_HANDLE_VALUE) ?
S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,m_dwLastOperationError);
if (FAILED(hr)) {
return hr;
}
//
// Open DeviceData section to read driver specific information
//
HKEY hKey = hParametersKey;
HKEY hOpenKey = NULL;
if (RegOpenKeyEx(hKey, // handle to open key
TEXT("DeviceData"), // address of name of subkey to open
0, // options (must be NULL)
KEY_QUERY_VALUE|KEY_READ, // just want to QUERY a value
&hOpenKey // address of handle to open key
) == ERROR_SUCCESS) {
//
// This is where you read registry entries for your device.
// The DeviceData section is the proper place to put this
// information. Information about your device should
// have been written using the WIA device's .INF installation
// file.
// You can access this information from this location in the
// Registry. The WIA service owns the hParameters HKEY.
// DO NOT CLOSE THIS KEY. Always close any HKEYS opened by
// this WIA driver after you are finished.
//
//
// close registry key when finished, reading DeviceData information.
//
RegCloseKey(hOpenKey);
} else {
return E_FAIL;
}
return hr;
}
WIA サービスは、IStiUSD::Initialize メソッドの呼び出しが成功した後に IStiUSD::GetCapabilities を呼び出します。 IStiUSD::GetCapabilities は、その後、STI_USD_CAPS 構造に、STI バージョン情報、WIA サポート フラグ (ドライバー機能を示すビット フラグ)、イベント要件を提供します。
次の例は、IStiUSD::GetCapabilities の実装例を示しています。
/********************************************************************\
* CWIADevice::GetCapabilities
* Remarks:
* This WIA driver sets the following capability flags:
* 1. STI_GENCAP_WIA - This driver supports WIA
* 2. STI_USD_GENCAP_NATIVE_PUSHSUPPORT - This driver supports push
* buttons
* 3. STI_GENCAP_NOTIFICATIONS - This driver requires the use of
* interrupt events.
*
\********************************************************************/
STDMETHODIMP CWIADevice::GetCapabilities(PSTI_USD_CAPS pUsdCaps)
{
//
// If the caller did not pass in the correct parameters,
// then fail the call with E_INVALIDARG.
//
if (!pUsdCaps) {
return E_INVALIDARG;
}
memset(pUsdCaps, 0, sizeof(STI_USD_CAPS));
pUsdCaps->dwVersion = STI_VERSION; // STI version
pUsdCaps->dwGenericCaps = STI_GENCAP_WIA| // WIA support
STI_USD_GENCAP_NATIVE_PUSHSUPPORT| // button support
STI_GENCAP_NOTIFICATIONS; // interrupt event support
return S_OK;
}