加载和卸载 WIA 微型驱动程序 - Windows drivers
安装 WIA 设备驱动程序后,WIA 服务会首次尝试加载它。 调用 WIA 微型驱动程序的 IStiUSD::Initialize 方法,应执行以下任务:
检查传输模式以确定调用方初始化此设备驱动程序的意向。 这是通过调用 IStiDeviceControl::GetMyDeviceOpenMode 方法完成的。
获取已安装设备的端口名称,以便此驱动程序可以在正确的端口上调用 CreateFile (Microsoft Windows SDK 中记录),以访问设备。 这是通过调用 IStiDeviceControl::GetMyDevicePortName 方法完成的。
读取设备安装期间写入的设备特定的注册表设置。 这可以通过使用传递给 IStiUSD::Initialize 的 hParametersKey 参数来完成。
首次加载驱动程序时,WIA 服务将调用 IStiUSD::Initialize 方法。 客户端使用旧 STI DDI 并调用 IStillImage::CreateDevice 方法时,也会调用 IStiUSD::Initialize 方法。
IStiUSD::Initialize 方法应初始化 WIA 驱动程序和设备以供使用。 如果 WIA 驱动程序稍后需要,WIA 驱动程序可以存储 IStiDeviceControl 接口指针。 在存储此接口之前,必须调用 IStiDeviceControl::AddRef 方法。 如果不需要存储接口,则忽略它。 如果尚未先调用 IStiDeviceControl::AddRef,请不要释放 IStiDeviceControl 接口。 这可能会导致不可预知的结果。 需要 IStiDeviceControl COM 接口 才能获取有关设备端口的信息。 可以通过调用 IStiDeviceControl::GetMyDevicePortName 方法获取对 CreateFile 函数的调用中使用的端口名称。 对于共享端口上的设备(例如串行端口设备),不建议在 IStiUSD::Initialize 中打开端口。 端口应仅在对 IStiUSD::LockDevice 的调用中打开。 应在内部控制端口关闭以提供快速访问。 (在 IStiUSD::LockDevice 和 IStiUSD::UnLockDevice 中打开和关闭是非常低效的。 CreateFile 可能会导致延迟,使设备对用户显示缓慢且无响应。
如果 WIA 驱动程序不能在同一设备端口上支持多个 CreateFile 调用,则应调用 IStiDeviceControl::GetMyDeviceOpenMode 方法。
WIA 驱动程序应检查返回的STI_DEVICE_CREATE_DATA标志模式值,并相应地打开端口。
如果必须打开设备端口,则应使用 对 CreateFile 的 调用。 打开端口时,应使用FILE_FLAG_OVERLAPPED标志。 这允许访问设备时使用 OVERLAPPED 结构(在 Windows SDK 文档中介绍)。 使用重叠的 I/O 有助于控制对硬件的响应式访问。 检测到问题后,WIA 驱动程序可以调用 CancelIo (Windows SDK 文档中所述)以停止所有当前硬件访问。
以下示例演示 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_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;
}