Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

469 lines
18 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: SCANPROC.CPP
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 10/7/1999
  12. *
  13. * DESCRIPTION: Scan Thread
  14. *
  15. *******************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. // Constructor
  19. CScanPreviewThread::CScanPreviewThread(
  20. DWORD dwIWiaItemCookie, // specifies the entry in the global interface table
  21. HWND hwndPreview, // handle to the preview window
  22. HWND hwndNotify, // handle to the window that receives notifications
  23. const POINT &ptOrigin, // Origin
  24. const SIZE &sizeResolution, // Resolution
  25. const SIZE &sizeExtent, // Extent
  26. const CSimpleEvent &CancelEvent // Cancel event name
  27. )
  28. : m_dwIWiaItemCookie(dwIWiaItemCookie),
  29. m_hwndPreview(hwndPreview),
  30. m_hwndNotify(hwndNotify),
  31. m_ptOrigin(ptOrigin),
  32. m_sizeResolution(sizeResolution),
  33. m_sizeExtent(sizeExtent),
  34. m_nMsgBegin(RegisterWindowMessage(SCAN_NOTIFYBEGINSCAN)),
  35. m_nMsgEnd(RegisterWindowMessage(SCAN_NOTIFYENDSCAN)),
  36. m_nMsgProgress(RegisterWindowMessage(SCAN_NOTIFYPROGRESS)),
  37. m_sCancelEvent(CancelEvent),
  38. m_bFirstTransfer(true),
  39. m_nImageSize(0)
  40. {
  41. }
  42. // Destructor
  43. CScanPreviewThread::~CScanPreviewThread(void)
  44. {
  45. }
  46. HRESULT _stdcall CScanPreviewThread::BandedDataCallback( LONG lMessage,
  47. LONG lStatus,
  48. LONG lPercentComplete,
  49. LONG lOffset,
  50. LONG lLength,
  51. LONG lReserved,
  52. LONG lResLength,
  53. BYTE *pbBuffer )
  54. {
  55. WIA_TRACE((TEXT("ImageDataCallback: lMessage: %d, lStatus: %d, lPercentComplete: %d, lOffset: %d, lLength: %d, lReserved: %d"), lMessage, lStatus, lPercentComplete, lOffset, lLength, lReserved ));
  56. HRESULT hr = S_OK;
  57. if (!m_sCancelEvent.Signalled())
  58. {
  59. switch (lMessage)
  60. {
  61. case IT_MSG_DATA_HEADER:
  62. {
  63. m_bFirstTransfer = true;
  64. break;
  65. } // IT_MSG_DATA_HEADER
  66. case IT_MSG_DATA:
  67. if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT)
  68. {
  69. if (m_bFirstTransfer)
  70. {
  71. // Assuming there is no way we could get a lLength smaller than the image header size
  72. m_bFirstTransfer = false;
  73. m_sImageData.Initialize( reinterpret_cast<PBITMAPINFO>(pbBuffer) );
  74. lLength -= WiaUiUtil::GetBmiSize(reinterpret_cast<PBITMAPINFO>(pbBuffer));
  75. lOffset += WiaUiUtil::GetBmiSize(reinterpret_cast<PBITMAPINFO>(pbBuffer));
  76. }
  77. if (SUCCEEDED(hr))
  78. {
  79. if (lLength)
  80. {
  81. // Figure out which line we are on
  82. int nCurrentLine = (lOffset - m_sImageData.GetHeaderLength())/m_sImageData.GetUnpackedWidthInBytes();
  83. // BUGBUG: This should be an even number of lines. If it isn't, things are going to get messed up
  84. int nLineCount = lLength / m_sImageData.GetUnpackedWidthInBytes();
  85. // Copy the data to our bitmap
  86. m_sImageData.SetUnpackedData( pbBuffer, nCurrentLine, nLineCount );
  87. // Tell the preview window to repaint the DIB
  88. if (IsWindow(m_hwndPreview))
  89. {
  90. PostMessage( m_hwndPreview, PWM_SETBITMAP, MAKEWPARAM(1,1), (LPARAM)m_sImageData.Bitmap() );
  91. }
  92. // Tell the notify window we've made progress
  93. if (IsWindow(m_hwndNotify))
  94. {
  95. PostMessage( m_hwndNotify, m_nMsgProgress, SCAN_PROGRESS_SCANNING, lPercentComplete );
  96. }
  97. }
  98. }
  99. } // IT_STATUS_TRANSFER_TO_CLIENT
  100. break;
  101. case IT_MSG_STATUS:
  102. {
  103. } // IT_MSG_STATUS
  104. break;
  105. case IT_MSG_TERMINATION:
  106. {
  107. } // IT_MSG_TERMINATION
  108. break;
  109. default:
  110. WIA_ERROR((TEXT("ImageDataCallback, unknown lMessage: %d"), lMessage ));
  111. break;
  112. }
  113. }
  114. else hr = S_FALSE;
  115. return(hr);
  116. }
  117. // The actual thread proc for this thread
  118. DWORD CScanPreviewThread::ThreadProc( LPVOID pParam )
  119. {
  120. DWORD dwResult = 0;
  121. CScanPreviewThread *This = (CScanPreviewThread *)pParam;
  122. if (This)
  123. {
  124. WIA_TRACE((TEXT("Beginning scan")));
  125. dwResult = (DWORD)This->Scan();
  126. WIA_TRACE((TEXT("Ending scan")));
  127. delete This;
  128. }
  129. return(dwResult);
  130. }
  131. // Returns a handle to the created thread
  132. HANDLE CScanPreviewThread::Scan(
  133. DWORD dwIWiaItemCookie, // specifies the entry in the global interface table
  134. HWND hwndPreview, // handle to the preview window
  135. HWND hwndNotify, // handle to the window that receives notifications
  136. const POINT &ptOrigin, // Origin
  137. const SIZE &sizeResolution, // Resolution
  138. const SIZE &sizeExtent, // Extent
  139. const CSimpleEvent &CancelEvent // Cancel event name
  140. )
  141. {
  142. CScanPreviewThread *scanThread = new CScanPreviewThread( dwIWiaItemCookie, hwndPreview, hwndNotify, ptOrigin, sizeResolution, sizeExtent, CancelEvent );
  143. if (scanThread)
  144. {
  145. DWORD dwThreadId;
  146. return CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, scanThread, 0, &dwThreadId );
  147. }
  148. return NULL;
  149. }
  150. HRESULT CScanPreviewThread::ScanBandedTransfer( IWiaItem *pIWiaItem )
  151. {
  152. WIA_PUSHFUNCTION(TEXT("CScanPreviewThread::ScanBandedTransfer"));
  153. CComPtr<IWiaDataTransfer> pWiaDataTransfer;
  154. WIA_DATA_TRANSFER_INFO wiaDataTransInfo;
  155. HRESULT hr = pIWiaItem->QueryInterface(IID_IWiaDataTransfer, (void**)&pWiaDataTransfer);
  156. if (SUCCEEDED(hr))
  157. {
  158. CComPtr<IWiaDataCallback> pWiaDataCallback;
  159. hr = this->QueryInterface(IID_IWiaDataCallback,(void **)&pWiaDataCallback);
  160. if (SUCCEEDED(hr))
  161. {
  162. LONG nItemSize = 0;
  163. if (PropStorageHelpers::GetProperty( pIWiaItem, WIA_IPA_ITEM_SIZE, nItemSize ))
  164. {
  165. ZeroMemory(&wiaDataTransInfo, sizeof(WIA_DATA_TRANSFER_INFO));
  166. wiaDataTransInfo.ulSize = sizeof(WIA_DATA_TRANSFER_INFO);
  167. wiaDataTransInfo.ulBufferSize = WiaUiUtil::Max<ULONG>( nItemSize / 8, (sizeof(BITMAPINFO)+sizeof(RGBQUAD)*255) );
  168. hr = pWiaDataTransfer->idtGetBandedData( &wiaDataTransInfo, pWiaDataCallback );
  169. if (FAILED(hr))
  170. {
  171. WIA_PRINTHRESULT((hr,TEXT("CScanPreviewThread::Scan, itGetImage failed")));
  172. }
  173. }
  174. else
  175. {
  176. WIA_PRINTHRESULT((hr,TEXT("CScanPreviewThread::Scan, unable to get image size")));
  177. hr = E_FAIL;
  178. }
  179. }
  180. }
  181. else
  182. {
  183. WIA_PRINTHRESULT((hr,TEXT("CScanPreviewThread::Scan, QI of IID_IImageTransfer failed")));
  184. }
  185. WIA_TRACE((TEXT("End CScanPreviewThread::ScanBandedTransfer")));
  186. return(hr);
  187. }
  188. /*
  189. * The worker which does the actual scan
  190. */
  191. bool CScanPreviewThread::Scan(void)
  192. {
  193. WIA_PUSHFUNCTION(TEXT("CScanPreviewThread::Scan"));
  194. if (IsWindow(m_hwndNotify))
  195. {
  196. PostMessage( m_hwndNotify, m_nMsgBegin, 0, 0 );
  197. }
  198. if (IsWindow(m_hwndNotify))
  199. {
  200. PostMessage( m_hwndNotify, m_nMsgProgress, SCAN_PROGRESS_INITIALIZING, 0 );
  201. }
  202. HRESULT hr = CoInitialize( NULL );
  203. if (SUCCEEDED(hr))
  204. {
  205. CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
  206. hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pGlobalInterfaceTable );
  207. if (SUCCEEDED(hr))
  208. {
  209. CComPtr<IWiaItem> pIWiaItem;
  210. pGlobalInterfaceTable->GetInterfaceFromGlobal( m_dwIWiaItemCookie, IID_IWiaItem, (LPVOID*)&pIWiaItem );
  211. if (SUCCEEDED(hr))
  212. {
  213. if (PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPS_CUR_INTENT, (LONG)WIA_INTENT_NONE))
  214. {
  215. CPropertyStream SavedProperties;
  216. hr = SavedProperties.AssignFromWiaItem(pIWiaItem);
  217. if (SUCCEEDED(hr))
  218. {
  219. //
  220. // Set the new properties
  221. //
  222. if (PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPS_XRES, m_sizeResolution.cx ) &&
  223. PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPS_YRES, m_sizeResolution.cy ) &&
  224. PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPS_XPOS, m_ptOrigin.x) &&
  225. PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPS_YPOS, m_ptOrigin.y) &&
  226. PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPS_XEXTENT, m_sizeExtent.cx ) &&
  227. PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPS_YEXTENT, m_sizeExtent.cy ) &&
  228. PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPA_FORMAT, WiaImgFmt_MEMORYBMP ) &&
  229. PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPA_TYMED, (LONG)TYMED_CALLBACK ))
  230. {
  231. //
  232. // Set the preview property. Ignore failure (it is an optional property)
  233. //
  234. PropStorageHelpers::SetProperty( pIWiaItem, WIA_DPS_PREVIEW, 1 );
  235. CPropertyStorageArray(pIWiaItem).Dump();
  236. WIA_TRACE((TEXT("SCANPROC.CPP: Making sure pIWiaItem is not NULL")));
  237. // Make sure pIWiaItem is not NULL
  238. if (pIWiaItem)
  239. {
  240. WIA_TRACE((TEXT("SCANPROC.CPP: Attempting banded transfer")));
  241. hr = ScanBandedTransfer( pIWiaItem );
  242. if (SUCCEEDED(hr))
  243. {
  244. if (IsWindow(m_hwndNotify))
  245. PostMessage( m_hwndNotify, m_nMsgProgress, SCAN_PROGRESS_SCANNING, 100 );
  246. if (IsWindow(m_hwndPreview))
  247. PostMessage( m_hwndPreview, PWM_SETBITMAP, MAKEWPARAM(1,0), (LPARAM)m_sImageData.DetachBitmap() );
  248. }
  249. else
  250. {
  251. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: ScanBandedTransfer failed, attempting IDataObject transfer")));
  252. }
  253. }
  254. else
  255. {
  256. WIA_ERROR((TEXT("SCANPROC.CPP: pIWiaItem was null")));
  257. hr = MAKE_HRESULT(3,FACILITY_WIN32,ERROR_INVALID_FUNCTION);
  258. }
  259. }
  260. else
  261. {
  262. WIA_ERROR((TEXT("SCANPROC.CPP: Error setting scanner properties")));
  263. hr = MAKE_HRESULT(3,FACILITY_WIN32,ERROR_INVALID_FUNCTION);
  264. }
  265. // Restore the saved properties
  266. SavedProperties.ApplyToWiaItem(pIWiaItem);
  267. }
  268. else
  269. {
  270. WIA_ERROR((TEXT("SCANPROC.CPP: Error saving scanner properties")));
  271. }
  272. }
  273. else
  274. {
  275. WIA_ERROR((TEXT("SCANPROC.CPP: Unable to clear intent")));
  276. }
  277. }
  278. else
  279. {
  280. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: Unable to unmarshall IWiaItem * from global interface table" )));
  281. }
  282. }
  283. else
  284. {
  285. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: Unable to QI global interface table" )));
  286. }
  287. CoUninitialize();
  288. }
  289. else
  290. {
  291. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: CoInitialize failed" )));
  292. }
  293. if (IsWindow(m_hwndNotify))
  294. PostMessage( m_hwndNotify, m_nMsgEnd, hr, 0 );
  295. if (IsWindow(m_hwndNotify))
  296. PostMessage( m_hwndNotify, m_nMsgProgress, SCAN_PROGRESS_COMPLETE, 0 );
  297. return(SUCCEEDED(hr));
  298. }
  299. // COM stuff
  300. HRESULT _stdcall CScanPreviewThread::QueryInterface( const IID& riid, void** ppvObject )
  301. {
  302. if (IsEqualIID( riid, IID_IUnknown ))
  303. {
  304. *ppvObject = static_cast<IWiaDataCallback*>(this);
  305. }
  306. else if (IsEqualIID( riid, IID_IWiaDataCallback ))
  307. {
  308. *ppvObject = static_cast<IWiaDataCallback*>(this);
  309. }
  310. else
  311. {
  312. *ppvObject = NULL;
  313. return(E_NOINTERFACE);
  314. }
  315. reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
  316. return(S_OK);
  317. }
  318. ULONG _stdcall CScanPreviewThread::AddRef()
  319. {
  320. return(1);
  321. }
  322. ULONG _stdcall CScanPreviewThread::Release()
  323. {
  324. return(1);
  325. }
  326. /*************************************************************************************************************************
  327. CScanToFileThread
  328. Scans to a file
  329. **************************************************************************************************************************/
  330. CScanToFileThread::CScanToFileThread(
  331. DWORD dwIWiaItemCookie, // specifies the entry in the global interface table
  332. HWND hwndNotify, // handle to the window that receives notifications
  333. GUID guidFormat,
  334. const CSimpleStringWide &strFilename // Filename to scan to
  335. )
  336. : m_dwIWiaItemCookie(dwIWiaItemCookie),
  337. m_hwndNotify(hwndNotify),
  338. m_nMsgBegin(RegisterWindowMessage(SCAN_NOTIFYBEGINSCAN)),
  339. m_nMsgEnd(RegisterWindowMessage(SCAN_NOTIFYENDSCAN)),
  340. m_nMsgProgress(RegisterWindowMessage(SCAN_NOTIFYPROGRESS)),
  341. m_guidFormat(guidFormat),
  342. m_strFilename(strFilename)
  343. {
  344. }
  345. // The actual thread proc for this thread
  346. DWORD CScanToFileThread::ThreadProc( LPVOID pParam )
  347. {
  348. DWORD dwResult = 0;
  349. CScanToFileThread *This = (CScanToFileThread *)pParam;
  350. if (This)
  351. {
  352. WIA_TRACE((TEXT("Beginning scan")));
  353. dwResult = (DWORD)This->Scan();
  354. WIA_TRACE((TEXT("Ending scan")));
  355. delete This;
  356. }
  357. return(dwResult);
  358. }
  359. // Returns a handle to the created thread
  360. HANDLE CScanToFileThread::Scan(
  361. DWORD dwIWiaItemCookie, // specifies the entry in the global interface table
  362. HWND hwndNotify, // handle to the window that receives notifications
  363. GUID guidFormat,
  364. const CSimpleStringWide &strFilename // Filename to save to
  365. )
  366. {
  367. CScanToFileThread *scanThread = new CScanToFileThread( dwIWiaItemCookie, hwndNotify, guidFormat, strFilename );
  368. if (scanThread)
  369. {
  370. DWORD dwThreadId;
  371. return(::CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, scanThread, 0, &dwThreadId ));
  372. }
  373. return(NULL);
  374. }
  375. CScanToFileThread::~CScanToFileThread(void)
  376. {
  377. }
  378. /*
  379. * The worker which does the actual scan
  380. */
  381. bool CScanToFileThread::Scan(void)
  382. {
  383. WIA_PUSHFUNCTION(TEXT("CScanToFileThread::Scan"));
  384. if (IsWindow(m_hwndNotify))
  385. PostMessage( m_hwndNotify, m_nMsgBegin, 0, 0 );
  386. HRESULT hr = CoInitialize( NULL );
  387. if (SUCCEEDED(hr))
  388. {
  389. CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
  390. hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pGlobalInterfaceTable );
  391. if (SUCCEEDED(hr))
  392. {
  393. CComPtr<IWiaItem> pIWiaItem;
  394. WIA_TRACE((TEXT("SCANPROC.CPP: Calling GetInterfaceFromGlobal(%08X) for IID_IWiaItem"),m_dwIWiaItemCookie));
  395. pGlobalInterfaceTable->GetInterfaceFromGlobal( m_dwIWiaItemCookie, IID_IWiaItem, (LPVOID*)&pIWiaItem );
  396. if (SUCCEEDED(hr))
  397. {
  398. CComPtr<IWiaTransferHelper> pWiaTransferHelper;
  399. hr = CoCreateInstance( CLSID_WiaDefaultUi, NULL, CLSCTX_INPROC_SERVER, IID_IWiaTransferHelper, (void**)&pWiaTransferHelper );
  400. if (SUCCEEDED(hr))
  401. {
  402. hr = pWiaTransferHelper->TransferItemFile( pIWiaItem, m_hwndNotify, 0, m_guidFormat, m_strFilename.String(), NULL, TYMED_FILE );
  403. if (!SUCCEEDED(hr))
  404. {
  405. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: pWiaTransferHelper->TransferItemFile failed")));
  406. }
  407. }
  408. else
  409. {
  410. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: CoCreateInstance on IID_IWiaTransferHelper failed")));
  411. }
  412. }
  413. else
  414. {
  415. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: Unable to unmarshall IWiaItem * from global interface table" )));
  416. }
  417. }
  418. else
  419. {
  420. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: Unable to QI global interface table" )));
  421. }
  422. CoUninitialize();
  423. }
  424. else
  425. {
  426. WIA_PRINTHRESULT((hr,TEXT("SCANPROC.CPP: CoInitialize failed" )));
  427. }
  428. if (IsWindow(m_hwndNotify))
  429. PostMessage( m_hwndNotify, m_nMsgEnd, hr, 0 );
  430. return(SUCCEEDED(hr));
  431. }