基于WIA的扫描仪程序,QT编写的,调用WIA api获取扫描仪属性,控制扫描仪,WIA提供了自带界面的方法,因为要嵌入自己的程序,所以我没有使用WIA自带的界面,Demo在Github上面,Github自取。详细资料请看官方文档。
Windows图像采集(WIA)是Windows操作系统家族中的静止图像采集平台,从Windows Millennium Edition(Windows Me)和Windows XP开始。WIA平台使成像/图形应用程序可以与成像硬件进行交互,并标准化不同应用程序和扫描仪之间的交互。这允许那些不同的应用程序与这些不同的扫描仪进行对话并交互,而无需应用程序编写器和扫描仪制造商针对每种应用程序-设备组合自定义其应用程序或驱动程序。
使用Windows Image Acquisition(WIA)服务的第一步是获取IWiaDevMgr接口指针,CLSID_WiaDevMgr和IID_IWiaDevMgr是WIA常数表示类ID和的接口ID IWiaDevMgr分别。CoCreateInstance调用的dwClsContext参数的值必须为CLSCTX_LOCAL_SERVER。
IWiaDevMgr *pWiaDevMgr = nullptr;
HRESULT hr = CoCreateInstance( CLSID_WiaDevMgr, NULL, CLSCTX_LOCAL_SERVER, IID_IWiaDevMgr, (void**)&pWiaDevMgr );
使用IWiaDevMgr :: EnumDeviceInfo方法来枚举系统上安装的Windows Image Acquisition(WIA)设备。此方法为设备的属性创建一个枚举对象,并返回一个指向该枚举对象支持的IEnumWIA_DEV_INFO接口的指针。然后,可以使用IEnumWIA_DEV_INFO接口的方法来获取系统上安装的每个设备的IWiaPropertyStorage接口指针。
IEnumWIA_DEV_INFO *pWiaEnumDevInfo = NULL;
HRESULT hr = pWiaDevMgr->EnumDeviceInfo( WIA_DEVINFO_ENUM_ALL, &pWiaEnumDevInfo );
if (SUCCEEDED(hr))
{
// Loop until you get an error or pWiaEnumDevInfo->Next returns
// S_FALSE to signal the end of the list.
while (S_OK == hr)
{
// Get the next device's property storage interface pointer
IWiaPropertyStorage *pWiaPropertyStorage = NULL;
hr = pWiaEnumDevInfo->Next( 1, &pWiaPropertyStorage, NULL );
//..................接下来是获取设备信息并且创建设备,见第4节与第5节
}
}
IWiaPropertyStorage接口读取和写入设备属性,设备属性包括有关设备的信息,这些信息描述了设备的功能和设置。有关这些属性的列表,请参见设备属性。
PROPSPEC PropSpec[3] = {0};
PROPVARIANT PropVar[3] = {0};
//
// How many properties are you querying for?
//
const ULONG c_nPropertyCount = sizeof(PropSpec)/sizeof(PropSpec[0]);
//
// Define which properties you want to read:
// Device ID. This is what you would use to create
// the device.
//
PropSpec[0].ulKind = PRSPEC_PROPID;
PropSpec[0].propid = WIA_DIP_DEV_ID;
//
// Device Name
//
PropSpec[1].ulKind = PRSPEC_PROPID;
PropSpec[1].propid = WIA_DIP_DEV_NAME;
//
// Device description
//
PropSpec[2].ulKind = PRSPEC_PROPID;
PropSpec[2].propid = WIA_DIP_DEV_DESC;
//
// Ask for the property values
//
HRESULT hr = pWiaPropertyStorage->ReadMultiple( c_nPropertyCount, PropSpec, PropVar );
if (SUCCEEDED(hr))
{
//
// IWiaPropertyStorage::ReadMultiple will return S_FALSE if some
// properties could not be read, so you have to check the return
// types for each requested item.
//
//
// Check the return type for the device ID
//
if (VT_BSTR == PropVar[0].vt)
{
//
// Do something with the device ID
//
_tprintf( TEXT("WIA_DIP_DEV_ID: %ws\n"), PropVar[0].bstrVal );
}
//
// Check the return type for the device name
//
if (VT_BSTR == PropVar[1].vt)
{
//
// Do something with the device name
//
_tprintf( TEXT("WIA_DIP_DEV_NAME: %ws\n"), PropVar[1].bstrVal );
}
//
// Check the return type for the device description
//
if (VT_BSTR == PropVar[2].vt)
{
//
// Do something with the device description
//
_tprintf( TEXT("WIA_DIP_DEV_DESC: %ws\n"), PropVar[2].bstrVal );
}
//
// Free the returned PROPVARIANTs
//
FreePropVariantArray( c_nPropertyCount, PropVar );
}
应用程序设置PROPVARIANT数组(分别为PropSpec和PropVar)来保存属性信息。这些数组作为参数传递给IWiaPropertyStorage指针pIWiaPropStg的IPropertyStorage :: ReadMultiple方法的调用。PropSpec数组的每个元素都包含设备属性的类型和名称。返回时,PropVar的每个元素都包含由PropSpec数组的相应元素表示的设备属性的值。然后,该应用程序调用IWiaPropertyStorage指针pWiaPropertyStorage的IPropertyStorage :: ReadMultiple属性以检索属性信息。
一旦应用程序具有给定设备的设备ID,它就可以调用IWiaDevMgr :: CreateDevice,该方法将创建代表成像设备以及图像扫描床和文件夹的IWiaItem。
//
// Create the WIA Device
//bstrDeviceID为上一节获取的设备ID
IWiaItem *pWiaDevice=NULL;
HRESULT hr = pWiaDevMgr->CreateDevice( bstrDeviceID, &pWiaDevice );
传输图像数据是最复杂的,需要创建一个类实现IWiaDataCallback接口,主要方法如下代码。
// The IWiaDataTransfer::idtGetBandedData method periodically
// calls the IWiaDataCallback::BandedDataCallback method with
// status messages. It sends the callback method a data header
// message followed by one or more data messages to transfer
// data. It concludes by sending a termination message.
HRESULT _stdcall DeviceModel::BandedDataCallback(
LONG lMessage,
LONG lStatus,
LONG lPercentComplete,
LONG lOffset,
LONG lLength,
LONG lReserved,
LONG lResLength,
BYTE* pbData)
{
UNREFERENCED_PARAMETER(lReserved);
UNREFERENCED_PARAMETER(lResLength);
switch (lMessage)
{
case IT_MSG_DATA_HEADER:
{
//
// The data header contains the image's final size.
//
PWIA_DATA_CALLBACK_HEADER pHeader = reinterpret_cast(pbData);
if (pHeader && pHeader->lBufferSize)
{
//
// Allocate a block of memory to hold the image
//
m_pBuffer = reinterpret_cast(LocalAlloc(LPTR, pHeader->lBufferSize));
if (m_pBuffer)
{
//
// Save the buffer size.
//
m_nBufferLength = pHeader->lBufferSize;
//
// Initialize the bytes transferred count.
//
m_nBytesTransfered = 0;
//
// Save the file format.
//
m_guidFormat = pHeader->guidFormatID;
}
}
}
break;
case IT_MSG_DATA:
{
//
// Make sure a block of memory has been created.
//
if (NULL != m_pBuffer)
{
//
// Copy the new band.
//
CopyMemory(m_pBuffer + lOffset, pbData, lLength);
//
// Increment the byte count.
//
m_nBytesTransfered += lLength;
}
}
break;
case IT_MSG_STATUS:
{
//
// Display transfer phase
//
if (lStatus & IT_STATUS_TRANSFER_FROM_DEVICE)
{
//_tprintf(TEXT("Transfer from device\n"));
}
else if (lStatus & IT_STATUS_PROCESSING_DATA)
{
//_tprintf(TEXT("Processing Data\n"));
}
else if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT)
{
//_tprintf(TEXT("Transfer to Client\n"));
}
//
// Display percent complete
//
//_tprintf(TEXT("lPercentComplete: %d\n"), lPercentComplete);
}
break;
}
return S_OK;
}
HRESULT DeviceModel::EnumerateItems(IWiaItem* pWiaItem, vector* pItems)
{
//
// Validate arguments
//
if (NULL == pWiaItem)
{
return E_INVALIDARG;
}
//
// Get the item type for this item.
//
LONG lItemType = 0;
HRESULT hr = pWiaItem->GetItemType(&lItemType);
if (SUCCEEDED(hr))
{
//
// If it is a folder, or it has attachments, enumerate its children.
//
if (lItemType & WiaItemTypeFolder || lItemType & WiaItemTypeHasAttachments)
{
//
// Get the child item enumerator for this item.
//
IEnumWiaItem* pEnumWiaItem = NULL; //vista and later
hr = pWiaItem->EnumChildItems(&pEnumWiaItem);
if (SUCCEEDED(hr))
{
//
// Loop until you get an error or pEnumWiaItem->Next returns
// S_FALSE to signal the end of the list.
//
while (S_OK == hr)
{
//
// Get the next child item.
//
IWiaItem* pChildWiaItem = NULL; //vista and laster
hr = pEnumWiaItem->Next(1, &pChildWiaItem, NULL);
//
// pEnumWiaItem->Next will return S_FALSE when the list is
// exhausted, so check for S_OK before using the returned
// value.
//
if (S_OK == hr)
{
//
// Recurse into this item.
//
hr = EnumerateItems(pChildWiaItem, pItems);
//
// Release this item.
//
//pChildWiaItem->Release();
//pChildWiaItem = NULL;
}
}
//
// If the result of the enumeration is S_FALSE (which
// is normal), change it to S_OK.
//
if (S_FALSE == hr)
{
hr = S_OK;
}
//
// Release the enumerator.
//
//pEnumWiaItem->Release();
//pEnumWiaItem = NULL;
}
}
else pItems->push_back(pWiaItem);
}
return hr;
}
void DeviceModel::ScanningSlot(int source, int pictrueType, int brightness, int contrast, int dpi, int size)
{
//CoInitialize(NULL);
vector imageWiaItems;
m_pWiaItemRoot->AnalyzeItem(0);
HRESULT hr = EnumerateItems(m_pWiaItemRoot, &imageWiaItems);
if (hr == S_OK)
{
for (int i = 0; i < imageWiaItems.size(); ++i)
{
IWiaPropertyStorage* pGetWiaProperty = nullptr;
hr = imageWiaItems[i]->QueryInterface(IID_IWiaPropertyStorage, (void**)&pGetWiaProperty);
if (hr != S_OK) continue;
PROPSPEC propSpec[9];
PROPVARIANT propVar[9];
propSpec[0].ulKind = PRSPEC_PROPID;
propSpec[0].propid = WIA_IPA_TYMED;
propSpec[1].ulKind = PRSPEC_PROPID;
propSpec[1].propid = WIA_IPA_FORMAT;
propSpec[2].ulKind = PRSPEC_PROPID;
propSpec[2].propid = WIA_DPS_PREVIEW;
//propSpec[3].ulKind = PRSPEC_PROPID;
//propSpec[3].propid = WIA_DPS_DOCUMENT_HANDLING_SELECT;
propSpec[3].ulKind = PRSPEC_PROPID;
propSpec[3].propid = WIA_IPS_CUR_INTENT;
propSpec[4].ulKind = PRSPEC_PROPID;
propSpec[4].propid = WIA_IPS_BRIGHTNESS;
propSpec[5].ulKind = PRSPEC_PROPID;
propSpec[5].propid = WIA_IPS_CONTRAST;
propSpec[6].ulKind = PRSPEC_PROPID;
propSpec[6].propid = WIA_IPS_XRES;
propSpec[7].ulKind = PRSPEC_PROPID;
propSpec[7].propid = WIA_IPS_YRES;
propSpec[8].ulKind = PRSPEC_PROPID;
propSpec[8].propid = WIA_IPS_PAGE_SIZE;
CLSID guidOutputFormat1 = WiaImgFmt_MEMORYBMP;
propVar[0].vt = VT_I4;
propVar[0].lVal = TYMED_CALLBACK;
propVar[1].vt = VT_CLSID;
propVar[1].puuid = &guidOutputFormat1;
propVar[2].vt = VT_I4;
propVar[2].lVal = 0;
//propVar[3].vt = VT_I4;
//if (source == 0) propVar[3].lVal = FLATBED;
//else propVar[3].lVal = FEEDER;
propVar[3].vt = VT_I4;
if (pictrueType == 0) propVar[3].lVal = WIA_INTENT_IMAGE_TYPE_COLOR;
else if (pictrueType == 1) propVar[3].lVal = WIA_INTENT_IMAGE_TYPE_GRAYSCALE;
else propVar[3].lVal = WIA_INTENT_IMAGE_TYPE_TEXT;
propVar[4].vt = VT_I4;
propVar[4].lVal = brightness;
propVar[5].vt = VT_I4;
propVar[5].lVal = contrast;
propVar[6].vt = VT_I4;
propVar[6].lVal = dpi;
propVar[7].vt = VT_I4;
propVar[7].lVal = dpi;
propVar[8].vt = VT_I4;
if (size == 0) propVar[8].lVal = WIA_PAGE_A4;
else if (size == 1) propVar[8].lVal = WIA_PAGE_ISO_A5;
else propVar[8].lVal = WIA_PAGE_ISO_A6;
hr = pGetWiaProperty->WriteMultiple(sizeof(propSpec) / sizeof(propSpec[0]), propSpec, propVar, WIA_IPA_FIRST);
if (hr != S_OK) continue;
IWiaDataTransfer* pIWiaDataTransfer = nullptr;
hr = imageWiaItems[i]->QueryInterface(IID_IWiaDataTransfer, (void**)&pIWiaDataTransfer);
if (hr != S_OK) continue;
PWIA_DATA_TRANSFER_INFO pdti = new WIA_DATA_TRANSFER_INFO;
pdti->ulSize = sizeof(WIA_DATA_TRANSFER_INFO);
pdti->ulBufferSize = 1024 * 1024;
pdti->ulSection = 0;
pdti->bDoubleBuffer = true;
pdti->ulReserved1 = 0;
pdti->ulReserved2 = 0;
pdti->ulReserved3 = 0;
while (true)
{
hr = pIWiaDataTransfer->idtGetBandedData(pdti, this);
if (hr == S_OK) WriteFile();
else break;
}
if (pGetWiaProperty) pGetWiaProperty->Release();
if (pIWiaDataTransfer) pIWiaDataTransfer->Release();
imageWiaItems[i]->Release();
}
}
}