// This function enumerates items recursively starting from the root item and calls DownloadItem() on those items // after checking their item types. // DownloadItem() will only be called on file items. Folder items are recursively enumerated. HRESULT EnumerateAndDownloadItems( IWiaItem2 *pWiaItem2 ) { // Validate arguments if (NULL == pWiaItem2) { HRESULT hr = E_INVALIDARG; ReportError(TEXT("Invalid argument passed to EnumerateAndDownloadItems()"),hr); return hr; } // Get the item type for this item LONG lItemType = 0; HRESULT hr = pWiaItem2->GetItemType( &lItemType ); // Print the item name. PrintItemName( pWiaItem2 ); //Find the item category GUID itemCategory = GUID_NULL; ReadPropertyGuid(pWiaItem2,WIA_IPA_ITEM_CATEGORY,&itemCategory ); // If this is an transferrable file(except finished files) , download it. // We have deliberately left finished files for simplicity if ( (lItemType & WiaItemTypeFile) && (lItemType & WiaItemTypeTransfer) && (itemCategory != WIA_CATEGORY_FINISHED_FILE) ) { hr = DownloadItem( pWiaItem2 ); } // If it is a folder, enumerate its children if (lItemType & WiaItemTypeFolder) { // Get the child item enumerator for this item IEnumWiaItem2 *pEnumWiaItem2 = NULL; hr = pWiaItem2->EnumChildItems(0, &pEnumWiaItem2 ); if (SUCCEEDED(hr)) { // We will loop until we 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 IWiaItem2 *pChildWiaItem2 = NULL; hr = pEnumWiaItem2->Next( 1, &pChildWiaItem2, 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 EnumerateAndDownloadItems( pChildWiaItem2 ); // Release this item pChildWiaItem2->Release(); pChildWiaItem2 = NULL; } else if (FAILED(hr)) { // Report that an error occurred during enumeration ReportError( TEXT("Error calling pEnumWiaItem2->Next"), hr ); } } // If the result of the enumeration is S_FALSE, since this // is normal, we will change it to S_OK if (S_FALSE == hr) { hr = S_OK; } // Release the enumerator pEnumWiaItem2->Release(); pEnumWiaItem2 = NULL; } else { ReportError(TEXT("pWiaItem2->EnumChildItems() failed"),hr); } } return hr; }
HRESULT WiaGetImage( HWND hWndParent, LONG lDeviceType, LONG lFlags, LONG lIntent, IWiaDevMgr *pSuppliedWiaDevMgr, IWiaItem *pSuppliedItemRoot, PFNPROGRESSCALLBACK pfnProgressCallback, PVOID pProgressCallbackParam, GUID *pguidFormat, LONG *plCount, IStream ***pppStream ) { HRESULT hr; // Validate and initialize output parameters if (plCount == NULL) { return E_POINTER; } if (pppStream == NULL) { return E_POINTER; } *plCount = 0; *pppStream = NULL; // Initialize the local root item variable with the supplied value. // If no value is supplied, display the device selection common dialog. CComPtr<IWiaItem> pItemRoot = pSuppliedItemRoot; if (pItemRoot == NULL) { // Initialize the device manager pointer with the supplied value // If no value is supplied, connect to the local device manager CComPtr<IWiaDevMgr> pWiaDevMgr = pSuppliedWiaDevMgr; if (pWiaDevMgr == NULL) { hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr); if (FAILED(hr)) { return hr; } } // Display the device selection common dialog hr = pWiaDevMgr->SelectDeviceDlg( hWndParent, lDeviceType, lFlags, 0, &pItemRoot ); if (FAILED(hr) || hr == S_FALSE) { return hr; } } // Display the image selection common dialog CComPtrArray<IWiaItem> ppIWiaItem; hr = pItemRoot->DeviceDlg( hWndParent, lFlags, lIntent, &ppIWiaItem.Count(), &ppIWiaItem ); if (FAILED(hr) || hr == S_FALSE) { return hr; } // For ADF scanners, the common dialog explicitly sets the page count to one. // So in order to transfer multiple images, set the page count to ALL_PAGES // if the WIA_DEVICE_DIALOG_SINGLE_IMAGE flag is not specified, if (!(lFlags & WIA_DEVICE_DIALOG_SINGLE_IMAGE)) { // Get the property storage interface pointer for the root item CComQIPtr<IWiaPropertyStorage> pWiaRootPropertyStorage(pItemRoot); if (pWiaRootPropertyStorage == NULL) { return E_NOINTERFACE; } // Determine if the selected device is a scanner or not PROPSPEC specDevType; specDevType.ulKind = PRSPEC_PROPID; specDevType.propid = WIA_DIP_DEV_TYPE; LONG nDevType; hr = ReadPropertyLong( pWiaRootPropertyStorage, &specDevType, &nDevType ); if (SUCCEEDED(hr) && (GET_STIDEVICE_TYPE(nDevType) == StiDeviceTypeScanner)) { // Determine if the document feeder is selected or not PROPSPEC specDocumentHandlingSelect; specDocumentHandlingSelect.ulKind = PRSPEC_PROPID; specDocumentHandlingSelect.propid = WIA_DPS_DOCUMENT_HANDLING_SELECT; LONG nDocumentHandlingSelect; hr = ReadPropertyLong( pWiaRootPropertyStorage, &specDocumentHandlingSelect, &nDocumentHandlingSelect ); if (SUCCEEDED(hr) && (nDocumentHandlingSelect & FEEDER)) { PROPSPEC specPages; specPages.ulKind = PRSPEC_PROPID; specPages.propid = WIA_DPS_PAGES; PROPVARIANT varPages; varPages.vt = VT_I4; varPages.lVal = ALL_PAGES; pWiaRootPropertyStorage->WriteMultiple( 1, &specPages, &varPages, WIA_DPS_FIRST ); PropVariantClear(&varPages); } } } // If a status callback function is not supplied, use the default. // The default displays a simple dialog with a progress bar and cancel button. CComPtr<CProgressDlg> pProgressDlg; if (pfnProgressCallback == NULL) { pfnProgressCallback = DefaultProgressCallback; pProgressDlg = new CProgressDlg(hWndParent); pProgressCallbackParam = (CProgressDlg *) pProgressDlg; } // Create the data callback interface CComPtr<CDataCallback> pDataCallback = new CDataCallback( pfnProgressCallback, pProgressCallbackParam, plCount, pppStream ); if (pDataCallback == NULL) { return E_OUTOFMEMORY; } // Start the transfer of the selected items for (int i = 0; i < ppIWiaItem.Count(); ++i) { // Get the interface pointers CComQIPtr<IWiaPropertyStorage> pWiaPropertyStorage(ppIWiaItem[i]); if (pWiaPropertyStorage == NULL) { return E_NOINTERFACE; } CComQIPtr<IWiaDataTransfer> pIWiaDataTransfer(ppIWiaItem[i]); if (pIWiaDataTransfer == NULL) { return E_NOINTERFACE; } // Set the transfer type PROPSPEC specTymed; specTymed.ulKind = PRSPEC_PROPID; specTymed.propid = WIA_IPA_TYMED; PROPVARIANT varTymed; varTymed.vt = VT_I4; varTymed.lVal = TYMED_CALLBACK; hr = pWiaPropertyStorage->WriteMultiple( 1, &specTymed, &varTymed, WIA_IPA_FIRST ); PropVariantClear(&varTymed); if (FAILED(hr)) { return hr; } // If there is no transfer format specified, use the device default GUID guidFormat = GUID_NULL; if (pguidFormat == NULL) { pguidFormat = &guidFormat; } if (*pguidFormat == GUID_NULL) { PROPSPEC specPreferredFormat; specPreferredFormat.ulKind = PRSPEC_PROPID; specPreferredFormat.propid = WIA_IPA_PREFERRED_FORMAT; hr = ReadPropertyGuid( pWiaPropertyStorage, &specPreferredFormat, pguidFormat ); if (FAILED(hr)) { return hr; } } // Set the transfer format PROPSPEC specFormat; specFormat.ulKind = PRSPEC_PROPID; specFormat.propid = WIA_IPA_FORMAT; PROPVARIANT varFormat; varFormat.vt = VT_CLSID; varFormat.puuid = (CLSID *) CoTaskMemAlloc(sizeof(CLSID)); if (varFormat.puuid == NULL) { return E_OUTOFMEMORY; } *varFormat.puuid = *pguidFormat; hr = pWiaPropertyStorage->WriteMultiple( 1, &specFormat, &varFormat, WIA_IPA_FIRST ); PropVariantClear(&varFormat); if (FAILED(hr)) { return hr; } // Read the transfer buffer size from the device, default to 64K PROPSPEC specBufferSize; specBufferSize.ulKind = PRSPEC_PROPID; specBufferSize.propid = WIA_IPA_BUFFER_SIZE; LONG nBufferSize; hr = ReadPropertyLong( pWiaPropertyStorage, &specBufferSize, &nBufferSize ); if (FAILED(hr)) { nBufferSize = 64 * 1024; } // Choose double buffered transfer for better performance WIA_DATA_TRANSFER_INFO WiaDataTransferInfo = { 0 }; WiaDataTransferInfo.ulSize = sizeof(WIA_DATA_TRANSFER_INFO); WiaDataTransferInfo.ulBufferSize = 2 * nBufferSize; WiaDataTransferInfo.bDoubleBuffer = TRUE; // Start the transfer hr = pIWiaDataTransfer->idtGetBandedData( &WiaDataTransferInfo, pDataCallback ); if (FAILED(hr) || hr == S_FALSE) { return hr; } } return S_OK; }
// This function downloads item after setting the format for the item and initializing callback (depending on category,itemtype) // with the directory to download images to as well as the filename for the downloaded image. HRESULT DownloadItem(IWiaItem2* pWiaItem2) { if( (!pWiaItem2) ) { HRESULT hr = E_INVALIDARG; ReportError(TEXT("Invalid argument passed to DownloadItem()"),hr); return hr; } // Get the IWiaTransfer interface IWiaTransfer *pWiaTransfer = NULL; HRESULT hr = pWiaItem2->QueryInterface( IID_IWiaTransfer, (void**)&pWiaTransfer ); if (SUCCEEDED(hr)) { // Create our callback class CWiaTransferCallback *pWiaClassCallback = new CWiaTransferCallback; if (pWiaClassCallback) { // Get the IWiaTransferCallback interface from our callback class. IWiaTransferCallback *pWiaTransferCallback = NULL; hr = pWiaClassCallback->QueryInterface( IID_IWiaTransferCallback, (void**)&pWiaTransferCallback ); if (SUCCEEDED(hr)) { //Set the format for the item to BMP IWiaPropertyStorage* pWiaPropertyStorage = NULL; HRESULT hr = pWiaItem2->QueryInterface( IID_IWiaPropertyStorage, (void**)&pWiaPropertyStorage ); if(SUCCEEDED(hr)) { hr = WritePropertyGuid(pWiaPropertyStorage,WIA_IPA_FORMAT,WiaImgFmt_BMP); if(FAILED(hr)) { ReportError(TEXT("WritePropertyGuid() failed in DownloadItem().Format couldn't be set to BMP"),hr); } //Get the file extension and initialize callback with this extension and directory in which to transfer image //along with feeder flag. //This will result in m_szFileName member callback class being set on which GetNextStream() will create and return a stream BSTR bstrFileExtension = NULL; ReadPropertyBSTR(pWiaPropertyStorage,WIA_IPA_FILENAME_EXTENSION, &bstrFileExtension); //Get the temporary folder path which is the directory where we will download the images TCHAR bufferTempPath[MAX_TEMP_PATH]; GetTempPath(MAX_TEMP_PATH , bufferTempPath); // Find out item type GUID itemCategory = GUID_NULL; ReadPropertyGuid(pWiaItem2,WIA_IPA_ITEM_CATEGORY,&itemCategory ); BOOL bFeederTransfer = FALSE; if(IsEqualGUID(itemCategory,WIA_CATEGORY_FEEDER)) { //Set WIA_IPS_PAGES to ALL_PAGES will enable transfer of all pages in the document feeder (multi-page transfer). //If somebody wants to scan a specific number of pages say N, he should set WIA_IPS_PAGES to N. WritePropertyLong(pWiaPropertyStorage,WIA_IPS_PAGES,ALL_PAGES); bFeederTransfer = TRUE; } //Initialize the callback class with the directory, file extension and feeder flag pWiaClassCallback->InitializeCallback(bufferTempPath,bstrFileExtension,bFeederTransfer); //Now download file item hr = pWiaTransfer->Download(0,pWiaTransferCallback); if(S_OK == hr) { _tprintf(TEXT("\npWiaTransfer->Download() on file item SUCCEEDED")); } else if(S_FALSE == hr) { ReportError(TEXT("pWiaTransfer->Download() on file item returned S_FALSE. File may be empty"),hr); } else if(FAILED(hr)) { ReportError(TEXT("pWiaTransfer->Download() on file item failed"),hr); } //Release pWiaPropertyStorage interface pWiaPropertyStorage->Release(); pWiaPropertyStorage = NULL; } else { ReportError(TEXT("QueryInterface failed on IID_IWiaPropertyStorage"),hr); } // Release the callback interface pWiaTransferCallback->Release(); pWiaTransferCallback = NULL; } else { ReportError( TEXT("pWiaClassCallback->QueryInterface failed on IID_IWiaTransferCallback"), hr ); } // Release our callback. It should now delete itself. pWiaClassCallback->Release(); pWiaClassCallback = NULL; } else { ReportError( TEXT("Unable to create CWiaTransferCallback class instance") ); } // Release the IWiaTransfer pWiaTransfer->Release(); pWiaTransfer = NULL; } else { ReportError( TEXT("pIWiaItem2->QueryInterface failed on IID_IWiaTransfer"), hr ); } return hr; }
HRESULT WIACamera::DigitalCameraCapture(IWiaItem* pIWiaRoot, IplImage** ppIplImage) { HRESULT hr = S_OK; IWiaItem* pIWiaItem = NULL; hr = pIWiaRoot->DeviceCommand( 0, &WIA_CMD_TAKE_PICTURE, &pIWiaItem ); if (pIWiaItem==NULL) { cvReleaseImage(ppIplImage); (*ppIplImage) = NULL; return hr; } IStream **ppStream = NULL; LONG lCount = 0; // Create the data callback interface CDataCallback *pDataCallback = new CDataCallback( &lCount,&ppStream ); if (pDataCallback == NULL) { return E_OUTOFMEMORY; } { // Get the interface pointers IWiaPropertyStorage *pWiaPropertyStorage; hr = pIWiaItem->QueryInterface(IID_IWiaPropertyStorage,(void**)&pWiaPropertyStorage); if (hr != S_OK) { return E_NOINTERFACE; } IWiaDataTransfer *pIWiaDataTransfer; hr = pIWiaItem->QueryInterface(IID_IWiaDataTransfer, (void**)&pIWiaDataTransfer); if (hr != S_OK) { return E_NOINTERFACE; } // Set the transfer type PROPSPEC specTymed; specTymed.ulKind = PRSPEC_PROPID; specTymed.propid = WIA_IPA_TYMED; PROPVARIANT varTymed; varTymed.vt = VT_I4; varTymed.lVal = TYMED_CALLBACK; hr = pWiaPropertyStorage->WriteMultiple(1, &specTymed, &varTymed, WIA_IPA_FIRST ); PropVariantClear(&varTymed); if (FAILED(hr)) { return hr; } // If there is no transfer format specified, use the device default GUID guidFormat = GUID_NULL; GUID *pguidFormat = &guidFormat; PROPSPEC specPreferredFormat; specPreferredFormat.ulKind = PRSPEC_PROPID; specPreferredFormat.propid = WIA_IPA_PREFERRED_FORMAT; hr = ReadPropertyGuid( pWiaPropertyStorage, &specPreferredFormat, pguidFormat ); if (FAILED(hr)) { return hr; } // Set the transfer format PROPSPEC specFormat; PROPVARIANT varFormat; specFormat.ulKind = PRSPEC_PROPID; specFormat.propid = WIA_IPA_FORMAT; varFormat.vt = VT_CLSID; varFormat.puuid = (CLSID *) CoTaskMemAlloc(sizeof(CLSID)); if (varFormat.puuid == NULL) { return E_OUTOFMEMORY; } *varFormat.puuid = *pguidFormat; hr = pWiaPropertyStorage->WriteMultiple( 1, &specFormat, &varFormat, WIA_IPA_FIRST ); PropVariantClear(&varFormat); if (FAILED(hr)) { return hr; } // Read the transfer buffer size from the device, default to 64K PROPSPEC specBufferSize; specBufferSize.ulKind = PRSPEC_PROPID; specBufferSize.propid = WIA_IPA_BUFFER_SIZE; LONG nBufferSize; hr = ReadPropertyLong( pWiaPropertyStorage, &specBufferSize, &nBufferSize ); if (FAILED(hr)) { nBufferSize = 64 * 1024; } // Choose double buffered transfer for better performance WIA_DATA_TRANSFER_INFO WiaDataTransferInfo = { 0 }; WiaDataTransferInfo.ulSize = sizeof(WIA_DATA_TRANSFER_INFO); WiaDataTransferInfo.ulBufferSize = 2 * nBufferSize; WiaDataTransferInfo.bDoubleBuffer = TRUE; // Start the transfer hr = pIWiaDataTransfer->idtGetBandedData( &WiaDataTransferInfo, pDataCallback ); if (pWiaPropertyStorage) { pWiaPropertyStorage->Release(); pWiaPropertyStorage = NULL; } if (pIWiaDataTransfer) { pIWiaDataTransfer->Release(); pIWiaDataTransfer = NULL; } } if (pIWiaItem) { // Delete file from DigitalCamera storage pIWiaItem->DeleteItem(0); pIWiaItem->Release(); pIWiaItem = NULL; } if (lCount!=1) throw "Error.\n"; if ( SUCCEEDED(hr) ) { Gdiplus::Bitmap myBmp(ppStream[0]); int Width = myBmp.GetWidth(); int Height = myBmp.GetHeight(); Gdiplus::Rect rect(0, 0, Width, Height); Gdiplus::BitmapData myBitmapData; Gdiplus::Status res = myBmp.LockBits( &rect, Gdiplus::ImageLockModeRead, PixelFormat24bppRGB, &myBitmapData ); if ( (*ppIplImage)==NULL ) { (*ppIplImage) = cvCreateImage(cvSize(Width,Height),IPL_DEPTH_8U,3); } else { CvSize oldSize = cvGetSize((*ppIplImage)); if ( oldSize.width!=Width || oldSize.height!=Height ) { throw "Warning.\n"; cvReleaseImage(&(*ppIplImage)); (*ppIplImage) = cvCreateImage(cvSize(Width,Height),IPL_DEPTH_8U,3); } } unsigned char *pIplData = (unsigned char*)(*ppIplImage)->imageData; for ( int h=0; h < Height; h++) { unsigned char *pIplLine = &pIplData[(*ppIplImage)->widthStep*h]; unsigned char *pBitmapLine = &((unsigned char*)myBitmapData.Scan0)[myBitmapData.Stride*h]; memcpy( pIplLine, pBitmapLine, sizeof(unsigned char)*Width*3 ); /* for ( int w=0; w < Width; w++) { pIplLine[w*3+0] = pBitmapLine[w*3+2]; pIplLine[w*3+1] = pBitmapLine[w*3+1]; pIplLine[w*3+2] = pBitmapLine[w*3+0]; } */ } } else { delete (*ppIplImage); (*ppIplImage) = NULL; } ppStream[0]->Release(); return hr; }