2 #define WIN32_LEAN_AND_MEAN
17 #define __LPGUID_DEFINED__
26 WINOLEAPI PropVariantClear ( PROPVARIANT * pvar );
35 #if defined(ECERE_STATIC)
36 public import static "ecere"
43 __on_register_module()
45 class(MSCOM_Base).vTblSize = 0;
46 delete class(MSCOM_Base)._vTbl;
49 class MSCOM_IUnknown : MSCOM_Base
52 virtual uint stdcall QueryInterface(REFIID iid, void ** ppvObj)
56 if(IsEqualGUID(iid, &IID_IUnknown))
58 if(!_refCount) _refCount = 1;
70 virtual uint stdcall AddRef()
72 return (uint)InterlockedIncrement((void *)&_refCount);
75 virtual uint stdcall Release()
77 uint cRef = InterlockedDecrement((void *)&_refCount);
84 class WiaDataCallback : MSCOM_IUnknown
86 uint stdcall QueryInterface(REFIID iid, void ** ppvObj)
90 if(IsEqualGUID(iid, &IID_IWiaDataCallback))
93 if(!_refCount) _refCount = 1;
97 return MSCOM_IUnknown::QueryInterface(iid, ppvObj);
100 virtual uint stdcall BandedDataCallback(uint lReason, uint lStatus, uint lPercentComplete, uint lOffset, uint lLength,
101 uint lReserved, uint lResLength, byte * pbBuffer);
104 class WiaDataTransfer
106 IWiaDataTransfer * pWiaDataTransfer;
108 HRESULT idtGetBandedData(PWIA_DATA_TRANSFER_INFO pWiaDataTransInfo, WiaDataCallback wiaDataCallback)
110 return (HRESULT)IWiaDataTransfer_idtGetBandedData(pWiaDataTransfer, pWiaDataTransInfo, (IWiaDataCallback *)wiaDataCallback);
114 class WiaPropertyStorage
116 IWiaPropertyStorage *pWiaPropertyStorage;
118 bool ReadLong(const PROPSPEC *pPropSpec, uint *plResult)
121 PROPVARIANT propVariant;
122 HRESULT hr = ReadMultiple(1, pPropSpec, &propVariant);
125 switch(propVariant.vt)
127 case VT_I1: *plResult = (uint)propVariant.cVal; break;
128 case VT_UI1: *plResult = (uint) propVariant.bVal; break;
129 case VT_I2: *plResult = (uint) propVariant.iVal; break;
130 case VT_UI2: *plResult = (uint) propVariant.uiVal; break;
131 case VT_I4: *plResult = (uint) propVariant.lVal; break;
132 case VT_UI4: *plResult = (uint) propVariant.ulVal; break;
134 case VT_INT: *plResult = (uint) propVariant.intVal; break;
135 case VT_UINT: *plResult = (uint) propVariant.uintVal; break;
137 case VT_R4: *plResult = (uint) (propVariant.fltVal + 0.5); break;
138 case VT_R8: *plResult = (uint) (propVariant.dblVal + 0.5); break;
139 default: hr = E_FAIL; result = false; break;
144 PropVariantClear(&propVariant);
148 HRESULT WriteMultiple(ULONG cpspec, const PROPSPEC *rgpspec, const PROPVARIANT * rgpropvar,PROPID propidNameFirst)
150 return (HRESULT)IWiaPropertyStorage_WriteMultiple(pWiaPropertyStorage, cpspec, rgpspec, rgpropvar, propidNameFirst);
153 HRESULT ReadMultiple(ULONG cpspec, const PROPSPEC * rgpspec, PROPVARIANT * rgpropvar)
155 return (HRESULT)IWiaPropertyStorage_ReadMultiple(pWiaPropertyStorage, cpspec, rgpspec, rgpropvar);
158 ~WiaPropertyStorage()
160 if(pWiaPropertyStorage)
162 IWiaPropertyStorage_Release(pWiaPropertyStorage);
163 pWiaPropertyStorage = null;
168 class ScanningProgress : Window
171 text = "Scanning in progress. Please wait.";
174 ProgressBar progressBar { this, anchor = { 4, 4, 4, 4 }, range = 100 };
177 ScanningProgress scanProgress { };
179 bool nextPage = false;
181 class MyWiaDataCallback : WiaDataCallback
185 uint stdcall BandedDataCallback(uint lReason, uint lStatus, uint lPercentComplete, uint lOffset, uint lLength,
186 uint lReserved, uint lResLength, byte * pbBuffer)
190 case IT_MSG_DATA_HEADER:
192 ((GuiApplication)__thisModule.application).Lock();
193 scanProgress.progressBar.progress = lPercentComplete;
194 ((GuiApplication)__thisModule.application).Unlock();
195 f.Seek(lOffset, start);
196 f.WriteData(pbBuffer, lLength);
199 ((GuiApplication)__thisModule.application).Lock();
200 scanProgress.progressBar.progress = lPercentComplete;
201 ((GuiApplication)__thisModule.application).Unlock();
203 case IT_MSG_TERMINATION:
205 case IT_MSG_NEW_PAGE:
209 ((GuiApplication)__thisModule.application).Lock();
210 ((GuiApplication)__thisModule.application).ProcessInput(true);
211 ((GuiApplication)__thisModule.application).UpdateDisplay();
212 ((GuiApplication)__thisModule.application).Unlock();
222 HRESULT DeviceDlg(HWND hWndParent, uint lFlags, uint lIntent, LONG * count, void * images)
224 return (HRESULT)IWiaItem_DeviceDlg(pWiaItem, hWndParent, lFlags, lIntent, count, images);
227 property WiaPropertyStorage propertyStorage
231 WiaPropertyStorage ps { };
232 HRESULT hr = IWiaItem_QueryInterface(pWiaItem, &IID_IWiaPropertyStorage, &ps.pWiaPropertyStorage);
236 printf("Error for WiaItem::propertyStorage (IWiaItem_QueryInterface)\n");
242 property WiaDataTransfer dataTransfer
246 WiaDataTransfer dt { };
247 HRESULT hr = IWiaItem_QueryInterface(pWiaItem, &IID_IWiaDataTransfer, &dt.pWiaDataTransfer);
251 printf("Error for WiaItem::dataTransfer (IWiaItem_QueryInterface)\n");
261 IWiaItem_Release(pWiaItem);
267 List<Bitmap> GetBitmaps(/*File * file*/)
269 List<Bitmap> result = null;
270 IWiaItem ** ppIWiaItem;
272 Window window = ((GuiApplication)__thisModule.application).desktop.activeChild;
273 if(window) window = window.rootWindow;
275 if(!DeviceDlg(window ? window.systemHandle : 0, 0, WIA_INTENT_NONE, &count, &ppIWiaItem))
278 // if (!(lFlags & WIA_DEVICE_DIALOG_SINGLE_IMAGE))
279 WiaPropertyStorage scannerProp = propertyStorage;
280 PROPSPEC specDevType;
282 specDevType.ulKind = PRSPEC_PROPID;
283 specDevType.propid = WIA_DIP_DEV_TYPE;
285 if(scannerProp.ReadLong(&specDevType, &nDevType) &&
286 GET_STIDEVICE_TYPE(nDevType) == StiDeviceTypeScanner)
288 PROPSPEC specDocumentHandlingSelect;
289 uint nDocumentHandlingSelect;
291 specDocumentHandlingSelect.ulKind = PRSPEC_PROPID;
292 specDocumentHandlingSelect.propid = WIA_DPS_DOCUMENT_HANDLING_SELECT;
294 if(scannerProp.ReadLong(&specDocumentHandlingSelect, &nDocumentHandlingSelect) &&
295 (nDocumentHandlingSelect & FEEDER))
298 PROPVARIANT varPages;
300 specPages.ulKind = PRSPEC_PROPID;
301 specPages.propid = WIA_DPS_PAGES;
304 varPages.lVal = ALL_PAGES;
306 scannerProp.WriteMultiple(1, &specPages, &varPages, WIA_DPS_FIRST);
308 PropVariantClear(&varPages);
318 for(i = 0; i < count; i++)
320 WiaItem wiaItem { pWiaItem = ppIWiaItem[i] };
321 WiaPropertyStorage wiaPropertyStorage = wiaItem.propertyStorage;
322 WiaDataTransfer wiaDataTransfer = wiaItem.dataTransfer;
324 if(wiaPropertyStorage && wiaDataTransfer)
327 PROPVARIANT varTymed;
329 specTymed.ulKind = PRSPEC_PROPID;
330 specTymed.propid = WIA_IPA_TYMED;
333 varTymed.lVal = TYMED_CALLBACK;
335 if(!wiaPropertyStorage.WriteMultiple(1, &specTymed, &varTymed, WIA_IPA_FIRST))
337 GUID guidFormat = WiaImgFmt_BMP;
338 GUID preferredFormat;
339 const String format = "bmp";
340 PROPSPEC specPreferredFormat;
342 specPreferredFormat.ulKind = PRSPEC_PROPID;
343 specPreferredFormat.propid = WIA_IPA_PREFERRED_FORMAT;
345 if(ReadPropertyGuid(wiaPropertyStorage, &specPreferredFormat, &preferredFormat))
347 if(!memcmp(&preferredFormat, &WiaImgFmt_MEMORYBMP, sizeof(preferredFormat)))
349 guidFormat = WiaImgFmt_MEMORYBMP;
350 format = "memorybmp";
355 bool suitableFormat = false;
357 PROPVARIANT varFormat;
359 specFormat.ulKind = PRSPEC_PROPID;
360 specFormat.propid = WIA_IPA_FORMAT;
362 varFormat.vt = VT_CLSID;
363 varFormat.puuid = &guidFormat;
365 if(!wiaPropertyStorage.WriteMultiple(1, &specFormat, &varFormat, WIA_IPA_FIRST))
366 suitableFormat = true;
369 guidFormat = WiaImgFmt_MEMORYBMP;
370 if(!wiaPropertyStorage.WriteMultiple(1, &specFormat, &varFormat, WIA_IPA_FIRST))
372 format = "memorybmp";
373 suitableFormat = true;
379 PROPSPEC specBufferSize;
381 WIA_DATA_TRANSFER_INFO WiaDataTransferInfo = { 0 };
382 MyWiaDataCallback dataCallback { };
384 specBufferSize.ulKind = PRSPEC_PROPID;
385 specBufferSize.propid = WIA_IPA_BUFFER_SIZE;
387 if(!wiaPropertyStorage.ReadLong(&specBufferSize, &nBufferSize))
388 nBufferSize = 64 * 1024;
389 WiaDataTransferInfo.ulSize = sizeof(WIA_DATA_TRANSFER_INFO);
390 WiaDataTransferInfo.ulBufferSize = 2 * nBufferSize;
391 WiaDataTransferInfo.bDoubleBuffer = TRUE;
393 ((GuiApplication)__thisModule).Lock();
394 scanProgress.progressBar.progress = 0;
395 scanProgress.Create();
396 ((GuiApplication)__thisModule).Unlock();
398 uint errorCode = wiaDataTransfer.idtGetBandedData(&WiaDataTransferInfo, dataCallback);
399 //if(!wiaDataTransfer.idtGetBandedData(&WiaDataTransferInfo, dataCallback))
402 File source = dataCallback.f;
404 //source.MakeACopy("output.bmp");
405 source.Seek(0, start);
406 if(bitmap.LoadFromFile(source, format, null))
411 dataCallback.f = null;
414 if(!result) result = { };
421 ((GuiApplication)__thisModule).Lock();
422 scanProgress.Destroy(0);
423 ((GuiApplication)__thisModule).Unlock();
427 varFormat.puuid = null;
428 PropVariantClear(&varFormat);
431 PropVariantClear(&varTymed);
433 delete wiaPropertyStorage;
434 delete wiaDataTransfer;
443 class WiaDeviceManager
445 IWiaDevMgr *pWiaDevMgr;
449 if(CoCreateInstance(&CLSID_WiaDevMgr, null, /*CLSCTX_INPROC_SERVER*/CLSCTX_LOCAL_SERVER, &IID_IWiaDevMgr, (void*)&pWiaDevMgr))
450 printf("Error for CoCreateInstance with CLSID_WiaDevMgr\n");
457 IWiaDevMgr_Release(pWiaDevMgr);
463 define MAX_GUID_STRING_LEN = 39;
465 bool ReadPropertyGuid(WiaPropertyStorage pWiaPropertyStorage, const PROPSPEC *pPropSpec, GUID *pguidResult)
468 PROPVARIANT propVariant;
469 if(!pWiaPropertyStorage.ReadMultiple(1, pPropSpec, &propVariant))
471 switch (propVariant.vt)
473 case VT_CLSID: *pguidResult = *propVariant.puuid; result = true; break;
474 case VT_BSTR: result = CLSIDFromString(propVariant.bstrVal, pguidResult) == 0; break;
475 case VT_LPWSTR: result = CLSIDFromString(propVariant.pwszVal, pguidResult) == 0; break;
478 uint16 wszGuid[MAX_GUID_STRING_LEN];
479 UTF8toUTF16Buffer(propVariant.pszVal, wszGuid, MAX_GUID_STRING_LEN-1);
480 result = CLSIDFromString(wszGuid, pguidResult) == 0;
485 PropVariantClear(&propVariant);
489 static bool comInited = false;
493 if(!comInited && CoInitialize(null) == 0)
507 WiaItem GetScanner(bool alwaysAsk)
509 WiaItem result = null;
512 WiaDeviceManager devMan { };
514 Window window = ((GuiApplication)__thisModule.application).desktop.activeChild;
515 if(window) window = window.rootWindow;
516 if(!IWiaDevMgr_SelectDeviceDlg(devMan.pWiaDevMgr, window ? window.systemHandle : 0,
517 StiDeviceTypeScanner /*StiDeviceTypeDefault*/, alwaysAsk ? WIA_SELECT_DEVICE_NODEFAULT : 0, 0, &pItemRoot))
519 result = { pWiaItem = pItemRoot };