載入和卸載 WIA Minidriver
安裝 WIA 設備磁碟機之後,WIA 服務會嘗試第一次載入它。 會呼叫 WIA minidriver 的 IStiUSD::Initialize 方法,而且應該執行下列工作:
檢查傳輸模式,以判斷呼叫端初始化此設備磁碟機的意圖。 這是藉由呼叫 IStiDeviceControl::GetMyDeviceOpenMode 方法來完成。
取得已安裝裝置的埠名稱,讓此驅動程式呼叫CreateFile (記載于適當埠上的 Microsoft Windows SDK) ,以存取裝置。 這是藉由呼叫 IStiDeviceControl::GetMyDevicePortName 方法來完成。
讀取裝置安裝期間寫入的裝置特定登錄設定。 這可以使用傳遞至IStiUSD::Initialize 的hParametersKey參數來完成。
WIA 服務會在驅動程式第一次載入時呼叫 IStiUSD::Initialize 方法。 當用戶端使用舊版 STI DIS 並呼叫IStillImage::CreateDevice方法時,也會呼叫IStiUSD::Initialize 方法。
IStiUSD::Initialize方法應該初始化 WIA 驅動程式和裝置以供使用。 WIA 驅動程式可以在稍後需要 時儲存 IStiDeviceControl 介面指標。 必須先呼叫 IStiDeviceControl::AddRef 方法,才能儲存此介面。 如果您不需要儲存介面,請忽略它。 如果您尚未呼叫IStiDeviceControl::AddRef,請勿釋放 IStiDeviceControl::AddRef。 這可能會造成無法預期的結果。 需要 IStiDeviceControl COM 介面 ,才能取得裝置埠的相關資訊。 呼叫 CreateFile 函式時所使用的埠名稱,可以藉由呼叫 IStiDeviceControl::GetMyDevicePortName 方法取得。 對於共用埠上的裝置,例如序列埠裝置,不建議在 IStiUSD::Initialize 中開啟埠。 埠應該只在 IStiUSD::LockDevice的呼叫中開啟。 應該在內部控制埠的關閉,以提供快速存取。 (在 IStiUSD::LockDevice 和 IStiUSD::UnLockDevice 中開啟和關閉非常沒有效率。 CreateFile 可能會導致裝置顯示緩慢且沒有回應 user.)
如果 WIA 驅動程式無法在相同的裝置埠上支援多個 CreateFile 呼叫,則應該呼叫 IStiDeviceControl::GetMyDeviceOpenMode 方法。
WIA 驅動程式應該檢查STI_DEVICE_CREATE_DATA旗標的傳回模式值,並據以開啟埠。
如果必須開啟裝置埠,應該使用 CreateFile 的呼叫。 開啟埠時,應該使用FILE_FLAG_OVERLAPPED旗標。 這可讓 Windows SDK 檔中描述的重迭結構 () 在存取裝置時使用。 使用重迭的 I/O 有助於控制對硬體的回應式存取。 偵測到問題時,WIA 驅動程式可以呼叫 Windows SDK 檔中所述的 CancelIo (,) 停止所有目前的硬體存取。
下列範例示範 IStiUSD::Initialize 方法的實作。
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 版本資訊STI_USD_CAPS結構、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;
}