Leaked source code of windows server 2003
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.

2524 lines
58 KiB

  1. #include "stdafx.h"
  2. #include "resource.h"
  3. #include <process.h>
  4. #include "bar.h"
  5. #include "pbrush.h"
  6. #include "imaging.h"
  7. //////////////////////////////////////////////////////////////////////////
  8. //
  9. // Trace
  10. //
  11. #ifdef DBG
  12. void AFX_CDECL Trace(PCTSTR pszFormat, ...)
  13. {
  14. va_list argList;
  15. va_start(argList, pszFormat);
  16. CString strMessage;
  17. strMessage.FormatV(pszFormat, argList);
  18. OutputDebugString(strMessage);
  19. va_end(argList);
  20. }
  21. #else //DBG
  22. inline void AFX_CDECL Trace(PCTSTR pszFormat, ...)
  23. {
  24. }
  25. #endif DBG
  26. //////////////////////////////////////////////////////////////////////////
  27. //
  28. //
  29. //
  30. CImagingMgr::~CImagingMgr()
  31. {
  32. }
  33. //////////////////////////////////////////////////////////////////////////
  34. //
  35. //
  36. //
  37. CWIAMgr::CWIAMgr()
  38. {
  39. HRESULT hr;
  40. m_pEventCallback = new CEventCallback();
  41. if (m_pEventCallback)
  42. {
  43. hr = m_pEventCallback->Register();
  44. if (hr != S_OK)
  45. {
  46. m_pEventCallback.Release();
  47. }
  48. }
  49. }
  50. //////////////////////////////////////////////////////////////////////////
  51. //
  52. //
  53. //
  54. HRESULT
  55. CWIAMgr::SelectSource(
  56. HWND hWndParent,
  57. LONG lFlags
  58. )
  59. {
  60. HRESULT hr = S_FALSE;
  61. // Create a connection to the local WIA device manager
  62. CComPtr<IWiaDevMgr> pWiaDevMgr;
  63. hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
  64. if (!SUCCEEDED(hr))
  65. {
  66. return hr;
  67. }
  68. // clear the current selection (if any)
  69. m_bstrDeviceID.Empty();
  70. // display the device selection dialog
  71. hr = pWiaDevMgr->SelectDeviceDlgID(
  72. hWndParent,
  73. StiDeviceTypeDefault,
  74. lFlags,
  75. &m_bstrDeviceID
  76. );
  77. theApp.RestoreWaitCursor();
  78. if (hr != S_OK)
  79. {
  80. Trace(_T("SelectDeviceDlgID HRESULT=%08x\n"), hr);
  81. return hr;
  82. }
  83. return S_OK;
  84. }
  85. //////////////////////////////////////////////////////////////////////////
  86. //
  87. //
  88. //
  89. HRESULT
  90. CWIAMgr::Select(
  91. LPCTSTR pDeviceId
  92. )
  93. {
  94. m_bstrDeviceID = pDeviceId;
  95. return S_OK;
  96. }
  97. //////////////////////////////////////////////////////////////////////////
  98. //
  99. //
  100. //
  101. HRESULT ReadPropertyLong(IWiaItem *pWiaItem, PROPID propid, LONG *lResult)
  102. {
  103. if (!lResult)
  104. {
  105. return E_POINTER;
  106. }
  107. HRESULT hr = S_FALSE;
  108. CComQIPtr<IWiaPropertyStorage> pWiaPropertyStorage(pWiaItem);
  109. if (pWiaPropertyStorage == 0)
  110. {
  111. return E_NOINTERFACE;
  112. }
  113. PROPSPEC PropSpec;
  114. PropSpec.ulKind = PRSPEC_PROPID;
  115. PropSpec.propid = propid;
  116. PROPVARIANT PropVariant;
  117. PropVariantInit(&PropVariant);
  118. hr = pWiaPropertyStorage->ReadMultiple(1, &PropSpec, &PropVariant);
  119. if (hr != S_OK)
  120. {
  121. Trace(_T("ReadMultiple HRESULT=%08x\n"), hr);
  122. return hr;
  123. }
  124. switch (PropVariant.vt)
  125. {
  126. case VT_I1: *lResult = (LONG) PropVariant.cVal; break;
  127. case VT_UI1: *lResult = (LONG) PropVariant.bVal; break;
  128. case VT_I2: *lResult = (LONG) PropVariant.iVal; break;
  129. case VT_UI2: *lResult = (LONG) PropVariant.uiVal; break;
  130. case VT_I4: *lResult = (LONG) PropVariant.lVal; break;
  131. case VT_UI4: *lResult = (LONG) PropVariant.ulVal; break;
  132. case VT_INT: *lResult = (LONG) PropVariant.intVal; break;
  133. case VT_UINT: *lResult = (LONG) PropVariant.uintVal; break;
  134. case VT_R4: *lResult = (LONG) (PropVariant.fltVal + 0.5); break;
  135. case VT_R8: *lResult = (LONG) (PropVariant.dblVal + 0.5); break;
  136. default: hr = S_FALSE; break;
  137. }
  138. PropVariantClear(&PropVariant);
  139. return hr;
  140. }
  141. //////////////////////////////////////////////////////////////////////////
  142. //
  143. //
  144. //
  145. HRESULT
  146. CWIAMgr::Acquire(
  147. HWND hWndParent,
  148. HGLOBAL *phDib
  149. )
  150. {
  151. ASSERT(phDib != 0);
  152. HRESULT hr;
  153. // Create a connection to the local WIA device manager
  154. CComPtr<IWiaDevMgr> pWiaDevMgr;
  155. hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
  156. if (!SUCCEEDED(hr))
  157. {
  158. return hr;
  159. }
  160. // Create the device object.
  161. // Select the device first if
  162. // no device has been selected before or
  163. // we fail to create the device with the selected ID
  164. CComPtr<IWiaItem> pRootItem;
  165. if (!m_bstrDeviceID ||
  166. !SUCCEEDED(pWiaDevMgr->CreateDevice(m_bstrDeviceID, &pRootItem)))
  167. {
  168. // clear the current selection (if any)
  169. m_bstrDeviceID.Empty();
  170. // display the device selection dialog
  171. hr = pWiaDevMgr->SelectDeviceDlg(
  172. hWndParent,
  173. StiDeviceTypeDefault,
  174. 0,
  175. &m_bstrDeviceID,
  176. &pRootItem
  177. );
  178. theApp.RestoreWaitCursor();
  179. if (hr != S_OK)
  180. {
  181. Trace(_T("SelectDeviceDlg HRESULT=%08x\n"), hr);
  182. return hr;
  183. }
  184. #ifndef USE_SELECTSOURCE_MENUITEM
  185. // forget the current selection
  186. m_bstrDeviceID.Empty();
  187. #endif //!USE_SELECTSOURCE_MENUITEM
  188. if (!SUCCEEDED(hr))
  189. {
  190. Trace(_T("CreateDevice HRESULT=%08x\n"), hr);
  191. return hr;
  192. }
  193. }
  194. // display the image selection dialog and let the user
  195. // select the item to be transferred
  196. CComPtrArray<IWiaItem> ppIWiaItem;
  197. hr = pRootItem->DeviceDlg(
  198. hWndParent,
  199. WIA_DEVICE_DIALOG_SINGLE_IMAGE,
  200. WIA_INTENT_NONE,
  201. &ppIWiaItem.ItemCount(),
  202. &ppIWiaItem
  203. );
  204. theApp.RestoreWaitCursor();
  205. if (hr != S_OK)
  206. {
  207. Trace(_T("DeviceDlg HRESULT=%08x\n"), hr);
  208. return hr;
  209. }
  210. if (ppIWiaItem.ItemCount() == 0)
  211. {
  212. Trace(_T("DeviceDlg returned 0 items\n"));
  213. return E_FAIL;
  214. }
  215. // set the image transfer properties; we want a DIB memory transfer
  216. TYMED tymed = (TYMED) TYMED_CALLBACK;
  217. GUID guidFormat = WiaImgFmt_MEMORYBMP;
  218. PROPSPEC PropSpec[2] = { 0 };
  219. PROPVARIANT PropVariant[2] = { 0 };
  220. PropSpec[0].ulKind = PRSPEC_PROPID;
  221. PropSpec[0].propid = WIA_IPA_TYMED;
  222. PropVariant[0].vt = VT_I4;
  223. PropVariant[0].lVal = tymed;
  224. PropSpec[1].ulKind = PRSPEC_PROPID;
  225. PropSpec[1].propid = WIA_IPA_FORMAT;
  226. PropVariant[1].vt = VT_CLSID;
  227. PropVariant[1].puuid = &guidFormat;
  228. CComQIPtr<IWiaPropertyStorage> pWiaPropertyStorage(ppIWiaItem[0]);
  229. if (pWiaPropertyStorage == 0)
  230. {
  231. return E_NOINTERFACE;
  232. }
  233. hr = pWiaPropertyStorage->WriteMultiple(
  234. 1,
  235. &(PropSpec[0]),
  236. &(PropVariant[0]),
  237. WIA_IPA_FIRST
  238. );
  239. if (hr != S_OK)
  240. {
  241. Trace(_T("WriteMultiple HRESULT=%08x\n"), hr);
  242. return hr;
  243. }
  244. hr = pWiaPropertyStorage->WriteMultiple(
  245. 1,
  246. &(PropSpec[1]),
  247. &(PropVariant[1]),
  248. WIA_IPA_FIRST
  249. );
  250. if (hr != S_OK)
  251. {
  252. Trace(_T("WriteMultiple HRESULT=%08x\n"), hr);
  253. return hr;
  254. }
  255. // now, determine the transfer buffer size
  256. // 64k transfer size and double buffering seem to work fine;
  257. // a smaller buffer considerably slows down the memory transfer
  258. // and a larger buffer doesn't give much speed increase.
  259. // If the device minimum is larger than 64k though, use that size...
  260. LONG lBufferSize;
  261. hr = ReadPropertyLong(ppIWiaItem[0], WIA_IPA_MIN_BUFFER_SIZE, &lBufferSize);
  262. if (hr != S_OK || lBufferSize < 64*1024)
  263. {
  264. lBufferSize = 64*1024;
  265. }
  266. // setup the progress dialog
  267. CComPtr<IWiaProgressDialog> pProgress;
  268. hr = CoCreateInstance(
  269. CLSID_WiaDefaultUi,
  270. 0,
  271. CLSCTX_INPROC_SERVER,
  272. IID_IWiaProgressDialog,
  273. (void**) &pProgress
  274. );
  275. if (hr != S_OK)
  276. {
  277. pProgress = new CProgressDialog;
  278. }
  279. LONG nDeviceType;
  280. hr = ReadPropertyLong(pRootItem, WIA_DIP_DEV_TYPE, &nDeviceType);
  281. if (hr != S_OK)
  282. {
  283. nDeviceType = 0;
  284. }
  285. LONG lAnimFlag;
  286. switch (GET_STIDEVICE_TYPE(nDeviceType))
  287. {
  288. case StiDeviceTypeScanner:
  289. lAnimFlag = WIA_PROGRESSDLG_ANIM_SCANNER_ACQUIRE;
  290. break;
  291. case StiDeviceTypeDigitalCamera:
  292. lAnimFlag = WIA_PROGRESSDLG_ANIM_CAMERA_ACQUIRE;
  293. break;
  294. case StiDeviceTypeStreamingVideo:
  295. lAnimFlag = WIA_PROGRESSDLG_ANIM_VIDEO_ACQUIRE;
  296. break;
  297. default:
  298. lAnimFlag = WIA_PROGRESSDLG_NO_ANIM;
  299. break;
  300. }
  301. pProgress->Create(hWndParent, lAnimFlag);
  302. CString strDownloading;
  303. strDownloading.LoadString(IDS_DOWNLOAD_IMAGE);
  304. USES_CONVERSION;
  305. pProgress->SetTitle(T2CW(strDownloading));
  306. pProgress->SetMessage(L"");
  307. pProgress->Show();
  308. // init the data callback interface
  309. CDataCallback *pDataCallback = new CDataCallback(pProgress);
  310. if (!pDataCallback)
  311. {
  312. theApp.SetMemoryEmergency(TRUE);
  313. return E_OUTOFMEMORY;
  314. }
  315. CComQIPtr<IWiaDataCallback> pIWiaDataCallback(pDataCallback);
  316. ASSERT(pIWiaDataCallback != 0);
  317. // initiate the transfer
  318. CComQIPtr<IWiaDataTransfer> pIWiaDataTransfer(ppIWiaItem[0]);
  319. if (pIWiaDataTransfer == 0)
  320. {
  321. return E_NOINTERFACE;
  322. }
  323. WIA_DATA_TRANSFER_INFO WiaDataTransferInfo = { 0 };
  324. WiaDataTransferInfo.ulSize = sizeof(WIA_DATA_TRANSFER_INFO);
  325. WiaDataTransferInfo.ulBufferSize = 2 * lBufferSize;
  326. WiaDataTransferInfo.bDoubleBuffer = TRUE;
  327. // This *easy* solution will cause the mspaint UI to freeze during
  328. // image transfer; this is possibly too long time to remain frozen.
  329. // So we will create a worker thread to do the data transfer.
  330. //
  331. //hr = pIWiaDataTransfer->idtGetBandedData(
  332. // &WiaDataTransferInfo,
  333. // pIWiaDataCallback
  334. //);
  335. EnableWindow(hWndParent, FALSE);
  336. hr = GetBandedData(CGetBandedDataThreadData(
  337. pIWiaDataTransfer,
  338. &WiaDataTransferInfo,
  339. pIWiaDataCallback
  340. ));
  341. EnableWindow(hWndParent, TRUE);
  342. // check if the user has pressed cancel
  343. if (pProgress)
  344. {
  345. BOOL bCancelled;
  346. if (pProgress->Cancelled(&bCancelled) == S_OK && bCancelled)
  347. {
  348. hr = S_FALSE;
  349. }
  350. pProgress->Destroy();
  351. }
  352. if (hr != S_OK)
  353. {
  354. Trace(_T("idtGetBandedData HRESULT=%08x\n"), hr);
  355. return hr;
  356. }
  357. // return the results
  358. pDataCallback->PrintTimes();
  359. *phDib = pDataCallback->GetBuffer();
  360. return S_OK;
  361. }
  362. //////////////////////////////////////////////////////////////////////////
  363. //
  364. //
  365. //
  366. CWIAMgr::CGetBandedDataThreadData::CGetBandedDataThreadData(
  367. IWiaDataTransfer *pIWiaDataTransfer,
  368. WIA_DATA_TRANSFER_INFO *pWiaDataTransferInfo,
  369. IWiaDataCallback *pIWiaDataCallback
  370. ) :
  371. m_pIWiaDataTransfer(pIWiaDataTransfer),
  372. m_pWiaDataTransferInfo(pWiaDataTransferInfo),
  373. m_pIWiaDataCallback(pIWiaDataCallback)
  374. {
  375. }
  376. //////////////////////////////////////////////////////////////////////////
  377. //
  378. //
  379. //
  380. HRESULT CWIAMgr::CGetBandedDataThreadData::Marshal()
  381. {
  382. HRESULT hr;
  383. // marshal the IWiaDataTransfer interface
  384. ASSERT(m_pIWiaDataTransfer != 0);
  385. hr = CoMarshalInterThreadInterfaceInStream(
  386. IID_IWiaDataTransfer,
  387. m_pIWiaDataTransfer,
  388. &m_pIWiaDataTransferStream
  389. );
  390. if (hr != S_OK)
  391. {
  392. Trace(_T("CoMarshalInterThreadInterfaceInStream HRESULT=%08x\n"), hr);
  393. return hr;
  394. }
  395. m_pIWiaDataTransfer.Release();
  396. // marshal the IWiaDataCallback interface
  397. ASSERT(m_pIWiaDataCallback != 0);
  398. hr = CoMarshalInterThreadInterfaceInStream(
  399. IID_IWiaDataCallback,
  400. m_pIWiaDataCallback,
  401. &m_pIWiaDataCallbackStream
  402. );
  403. if (hr != S_OK)
  404. {
  405. Trace(_T("CoMarshalInterThreadInterfaceInStream HRESULT=%08x\n"), hr);
  406. return hr;
  407. }
  408. m_pIWiaDataCallback.Release();
  409. return hr;
  410. }
  411. //////////////////////////////////////////////////////////////////////////
  412. //
  413. //
  414. //
  415. HRESULT CWIAMgr::CGetBandedDataThreadData::Unmarshal()
  416. {
  417. HRESULT hr;
  418. // unmarshal the IWiaDataTransfer interface
  419. ASSERT(m_pIWiaDataTransferStream != 0);
  420. hr = CoGetInterfaceAndReleaseStream(
  421. m_pIWiaDataTransferStream,
  422. IID_IWiaDataTransfer,
  423. (void **) &m_pIWiaDataTransfer
  424. );
  425. // CoGetInterfaceAndReleaseStream should already have
  426. // released the stream pointer, so set it to zero so that
  427. // ~CGetBandedDataThreadData will not try to release it again
  428. m_pIWiaDataTransferStream.Detach();
  429. if (hr != S_OK)
  430. {
  431. Trace(_T("CoGetInterfaceAndReleaseStream HRESULT=%08x\n"), hr);
  432. return hr;
  433. }
  434. // unmarshal the IWiaDataCallback interface
  435. ASSERT(m_pIWiaDataCallbackStream != 0);
  436. hr = CoGetInterfaceAndReleaseStream(
  437. m_pIWiaDataCallbackStream,
  438. IID_IWiaDataCallback,
  439. (void **) &m_pIWiaDataCallback
  440. );
  441. m_pIWiaDataCallbackStream.Detach();
  442. if (hr != S_OK)
  443. {
  444. Trace(_T("CoGetInterfaceAndReleaseStream HRESULT=%08x\n"), hr);
  445. return hr;
  446. }
  447. return hr;
  448. }
  449. //////////////////////////////////////////////////////////////////////////
  450. //
  451. //
  452. //
  453. HRESULT CWIAMgr::GetBandedData(CGetBandedDataThreadData &ThreadData)
  454. {
  455. // marshal the interface pointers before passing them to another thread
  456. HRESULT hr = ThreadData.Marshal();
  457. if (hr != S_OK)
  458. {
  459. return hr;
  460. }
  461. // fire up the new thread
  462. unsigned nThreadId;
  463. HANDLE hThread = (HANDLE) _beginthreadex(
  464. 0,
  465. 0,
  466. GetBandedDataThread,
  467. &ThreadData,
  468. 0,
  469. &nThreadId
  470. );
  471. if (hThread == 0)
  472. {
  473. Trace(_T("CreateThread LastError=%08x\n"), GetLastError());
  474. return HRESULT_FROM_WIN32(GetLastError());
  475. }
  476. // enter a msg loop while waiting for the thread to complete;
  477. // this will keep the mspaint UI alive
  478. while (MsgWaitForMultipleObjects(1, &hThread, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0+1)
  479. {
  480. MSG msg;
  481. while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  482. {
  483. TranslateMessage(&msg);
  484. DispatchMessage(&msg);
  485. }
  486. theApp.RestoreWaitCursor();
  487. }
  488. // if we reach here, the thread must have ended; get the result
  489. DWORD dwExitCode = S_FALSE;
  490. GetExitCodeThread(hThread, &dwExitCode);
  491. CloseHandle(hThread);
  492. ASSERT(sizeof(DWORD) >= sizeof(HRESULT));
  493. return (HRESULT) dwExitCode;
  494. }
  495. //////////////////////////////////////////////////////////////////////////
  496. //
  497. //
  498. //
  499. unsigned WINAPI CWIAMgr::GetBandedDataThread(PVOID pVoid)
  500. {
  501. // Init COM for this thread
  502. HRESULT hr = CoInitialize(0);
  503. if (hr != S_OK)
  504. {
  505. Trace(_T("CoInitialize HRESULT=%08x\n"), hr);
  506. return (unsigned) hr;
  507. }
  508. CGetBandedDataThreadData *pThreadData = (CGetBandedDataThreadData *) pVoid;
  509. ASSERT(pThreadData != 0);
  510. if (pThreadData != 0)
  511. {
  512. // unmarshal the interface pointers before calling idtGetBandedData
  513. hr = pThreadData->Unmarshal();
  514. if (hr == S_OK)
  515. {
  516. hr = pThreadData->m_pIWiaDataTransfer->idtGetBandedData(
  517. pThreadData->m_pWiaDataTransferInfo,
  518. pThreadData->m_pIWiaDataCallback
  519. );
  520. }
  521. }
  522. CoUninitialize();
  523. ASSERT(sizeof(unsigned) >= sizeof(HRESULT));
  524. return (unsigned) hr;
  525. }
  526. //////////////////////////////////////////////////////////////////////////
  527. //
  528. //
  529. //
  530. int CWIAMgr::NumDevices(HWND /*hWndParent*/)
  531. {
  532. return m_pEventCallback ? m_pEventCallback->GetNumDevices() : 0;
  533. }
  534. #ifdef USE_TWAIN
  535. //////////////////////////////////////////////////////////////////////////
  536. //
  537. //
  538. //
  539. CTwainMgr::CTwainMgr()
  540. {
  541. m_TwainState = State_1_Pre_Session;
  542. // fill in the m_AppId struct with defaults
  543. m_AppId.Id = 0;
  544. m_AppId.Version.MajorNum = 1;
  545. m_AppId.Version.MinorNum = 0;
  546. m_AppId.Version.Language = TWLG_USA;
  547. m_AppId.Version.Country = TWCY_USA;
  548. strcpy(m_AppId.Version.Info, "FileDescription");
  549. m_AppId.ProtocolMajor = TWON_PROTOCOLMAJOR;
  550. m_AppId.ProtocolMinor = TWON_PROTOCOLMINOR;
  551. m_AppId.SupportedGroups = DG_IMAGE | DG_CONTROL;
  552. strcpy(m_AppId.Manufacturer, "CompanyName");
  553. strcpy(m_AppId.ProductFamily, "ProductVersion");
  554. strcpy(m_AppId.ProductName, "ProductName");
  555. // reset m_SrcId
  556. m_SrcId.Id = 0;
  557. m_SrcId.ProductName[0] = '\0';
  558. // Load TWAIN DLL
  559. m_hTwainDll = LoadLibrary(_T("TWAIN_32.DLL"));
  560. if (m_hTwainDll)
  561. {
  562. // Get the entry point
  563. m_DSM_Entry = (DSMENTRYPROC) GetProcAddress(m_hTwainDll, "DSM_Entry");
  564. if (m_DSM_Entry)
  565. {
  566. m_TwainState = State_2_Source_Manager_Loaded;
  567. }
  568. }
  569. }
  570. //////////////////////////////////////////////////////////////////////////
  571. //
  572. //
  573. //
  574. CTwainMgr::~CTwainMgr()
  575. {
  576. // Free the library if loaded
  577. if (m_TwainState >= State_1_Pre_Session)
  578. {
  579. FreeLibrary(m_hTwainDll);
  580. }
  581. }
  582. //////////////////////////////////////////////////////////////////////////
  583. //
  584. //
  585. //
  586. HRESULT
  587. CTwainMgr::SelectSource(
  588. HWND hWndParent,
  589. LONG /*lFlags*/
  590. )
  591. {
  592. HRESULT hr = S_FALSE;
  593. TW_UINT16 rc = TWRC_FAILURE;
  594. if (m_TwainState >= State_2_Source_Manager_Loaded)
  595. {
  596. __try
  597. {
  598. if (m_TwainState == State_2_Source_Manager_Loaded)
  599. {
  600. // Open the data source manager
  601. rc = m_DSM_Entry(
  602. &m_AppId,
  603. 0,
  604. DG_CONTROL,
  605. DAT_PARENT,
  606. MSG_OPENDSM,
  607. (TW_MEMREF) &hWndParent
  608. );
  609. if (rc != TWRC_SUCCESS)
  610. {
  611. __leave;
  612. }
  613. m_TwainState = State_3_Source_Manager_Open;
  614. }
  615. // pop up the selection dialog
  616. rc = m_DSM_Entry(
  617. &m_AppId,
  618. 0,
  619. DG_CONTROL,
  620. DAT_IDENTITY,
  621. MSG_USERSELECT,
  622. (TW_MEMREF) &m_SrcId
  623. );
  624. ASSERT(rc == TWRC_SUCCESS || rc == TWRC_CANCEL);
  625. if (rc == TWRC_SUCCESS)
  626. {
  627. hr = S_OK;
  628. }
  629. }
  630. __finally
  631. {
  632. if (m_TwainState == State_3_Source_Manager_Open)
  633. {
  634. // Close the data source manager
  635. rc = m_DSM_Entry(
  636. &m_AppId,
  637. 0,
  638. DG_CONTROL,
  639. DAT_PARENT,
  640. MSG_CLOSEDSM,
  641. (TW_MEMREF) &hWndParent
  642. );
  643. ASSERT(rc == TWRC_SUCCESS);
  644. m_TwainState = State_2_Source_Manager_Loaded;
  645. }
  646. }
  647. }
  648. return hr;
  649. }
  650. //////////////////////////////////////////////////////////////////////////
  651. //
  652. //
  653. //
  654. HRESULT
  655. CTwainMgr::Select(
  656. LPCTSTR pDeviceId
  657. )
  658. {
  659. #ifdef UNICODE
  660. WideCharToMultiByte(CP_ACP, 0, pDeviceId, -1,
  661. m_SrcId.ProductName, sizeof(m_SrcId.ProductName), 0, 0);
  662. #else //UNICODE
  663. lstrcpyn(m_SrcId.ProductName, pDeviceId, sizeof(m_SrcId.ProductName));
  664. #endif //UNICODE
  665. return S_OK;
  666. }
  667. //////////////////////////////////////////////////////////////////////////
  668. //
  669. //
  670. //
  671. HRESULT
  672. CTwainMgr::Acquire(
  673. HWND hWndParent,
  674. HGLOBAL *phDib
  675. )
  676. {
  677. ASSERT(phDib);
  678. HRESULT hr = S_FALSE;
  679. TW_UINT16 rc = TWRC_FAILURE;
  680. if (m_TwainState >= State_2_Source_Manager_Loaded)
  681. {
  682. __try
  683. {
  684. if (m_TwainState == State_2_Source_Manager_Loaded)
  685. {
  686. // Open the data source manager
  687. rc = m_DSM_Entry(
  688. &m_AppId,
  689. 0,
  690. DG_CONTROL,
  691. DAT_PARENT,
  692. MSG_OPENDSM,
  693. (TW_MEMREF) &hWndParent
  694. );
  695. if (rc != TWRC_SUCCESS)
  696. {
  697. __leave;
  698. }
  699. m_TwainState = State_3_Source_Manager_Open;
  700. }
  701. #ifdef USE_SELECTSOURCE_MENUITEM
  702. if (m_SrcId.ProductName[0] == '\0')
  703. {
  704. // if no data source is selected yet, get the default
  705. rc = m_DSM_Entry(
  706. &m_AppId,
  707. 0,
  708. DG_CONTROL,
  709. DAT_IDENTITY,
  710. MSG_GETDEFAULT,
  711. (TW_MEMREF) &m_SrcId
  712. );
  713. if (rc != TWRC_SUCCESS)
  714. {
  715. __leave;
  716. }
  717. }
  718. #else //USE_SELECTSOURCE_MENUITEM
  719. rc = m_DSM_Entry(
  720. &m_AppId,
  721. 0,
  722. DG_CONTROL,
  723. DAT_IDENTITY,
  724. MSG_USERSELECT,
  725. (TW_MEMREF) &m_SrcId
  726. );
  727. ASSERT(rc == TWRC_SUCCESS || rc == TWRC_CANCEL);
  728. if (rc != TWRC_SUCCESS)
  729. {
  730. __leave;
  731. }
  732. #endif //USE_SELECTSOURCE_MENUITEM
  733. if (m_TwainState == State_3_Source_Manager_Open)
  734. {
  735. // open the data source
  736. rc = m_DSM_Entry(
  737. &m_AppId,
  738. 0,
  739. DG_CONTROL,
  740. DAT_IDENTITY,
  741. MSG_OPENDS,
  742. (TW_MEMREF) &m_SrcId
  743. );
  744. if (rc != TWRC_SUCCESS)
  745. {
  746. __leave;
  747. }
  748. m_TwainState = State_4_Source_Open;
  749. }
  750. // set the desired transfer options;
  751. // we want to transfer a single 8-bit RGB image
  752. SetCapability(CAP_XFERCOUNT, TWTY_INT16, 1);
  753. SetCapability(ICAP_PIXELTYPE, TWTY_UINT32, TWPT_RGB);
  754. SetCapability(ICAP_BITDEPTH, TWTY_UINT32, 8);
  755. if (m_TwainState == State_4_Source_Open)
  756. {
  757. // enable the data source
  758. TW_USERINTERFACE twUI;
  759. twUI.ShowUI = TRUE;
  760. twUI.hParent = hWndParent;
  761. rc = m_DSM_Entry(
  762. &m_AppId,
  763. &m_SrcId,
  764. DG_CONTROL,
  765. DAT_USERINTERFACE,
  766. MSG_ENABLEDS,
  767. (TW_MEMREF) &twUI
  768. );
  769. theApp.RestoreWaitCursor();
  770. if (rc != TWRC_SUCCESS)
  771. {
  772. __leave;
  773. }
  774. m_TwainState = State_5_Source_Enabled;
  775. }
  776. if (m_TwainState == State_5_Source_Enabled)
  777. {
  778. // Disable the parent window
  779. EnableWindow(hWndParent, FALSE);
  780. // Enter the message loop to transfer the image
  781. MSG msg;
  782. BOOL bDone = FALSE;
  783. while (!bDone && GetMessage(&msg, 0, 0, 0))
  784. {
  785. // process the event through TWAIN
  786. TW_EVENT twEvent;
  787. twEvent.pEvent = &msg;
  788. twEvent.TWMessage = MSG_NULL;
  789. rc = m_DSM_Entry(
  790. &m_AppId,
  791. &m_SrcId,
  792. DG_CONTROL,
  793. DAT_EVENT,
  794. MSG_PROCESSEVENT,
  795. (TW_MEMREF) &twEvent
  796. );
  797. if (twEvent.TWMessage == MSG_CLOSEDSREQ)
  798. {
  799. bDone = TRUE;
  800. hr = S_FALSE;
  801. }
  802. else if (twEvent.TWMessage == MSG_XFERREADY)
  803. {
  804. m_TwainState = State_6_Transfer_Ready;
  805. TW_PENDINGXFERS twPendingXfers;
  806. do
  807. {
  808. m_TwainState = State_7_Transferring;
  809. rc = m_DSM_Entry(
  810. &m_AppId,
  811. &m_SrcId,
  812. DG_IMAGE,
  813. DAT_IMAGENATIVEXFER,
  814. MSG_GET,
  815. (TW_MEMREF) phDib
  816. );
  817. if (rc != TWRC_XFERDONE)
  818. {
  819. if (*phDib)
  820. {
  821. GlobalFree(*phDib);
  822. }
  823. __leave;
  824. }
  825. hr = S_OK;
  826. // End the transfer
  827. rc = m_DSM_Entry(
  828. &m_AppId,
  829. &m_SrcId,
  830. DG_CONTROL,
  831. DAT_PENDINGXFERS,
  832. MSG_ENDXFER,
  833. (TW_MEMREF) &twPendingXfers
  834. );
  835. if (rc != TWRC_SUCCESS)
  836. {
  837. __leave;
  838. }
  839. m_TwainState = State_6_Transfer_Ready;
  840. } while (twPendingXfers.Count != 0);
  841. m_TwainState = State_5_Source_Enabled;
  842. //exit after a single image transfer
  843. bDone = TRUE;
  844. }
  845. if (rc == TWRC_NOTDSEVENT)
  846. {
  847. TranslateMessage(&msg);
  848. DispatchMessage(&msg);
  849. }
  850. }
  851. }
  852. }
  853. __finally
  854. {
  855. // enable the parent window upon exiting the message loop
  856. EnableWindow(hWndParent, TRUE);
  857. ASSERT(m_TwainState <= State_6_Transfer_Ready);
  858. if (m_TwainState == State_6_Transfer_Ready)
  859. {
  860. TW_PENDINGXFERS twPendingXfers;
  861. rc = m_DSM_Entry(
  862. &m_AppId,
  863. &m_SrcId,
  864. DG_CONTROL,
  865. DAT_PENDINGXFERS,
  866. MSG_RESET,
  867. (TW_MEMREF) &twPendingXfers
  868. );
  869. ASSERT(rc == TWRC_SUCCESS);
  870. m_TwainState = State_5_Source_Enabled;
  871. }
  872. if (m_TwainState == State_5_Source_Enabled)
  873. {
  874. TW_USERINTERFACE twUI;
  875. rc = m_DSM_Entry(
  876. &m_AppId,
  877. &m_SrcId,
  878. DG_CONTROL,
  879. DAT_USERINTERFACE,
  880. MSG_DISABLEDS,
  881. (TW_MEMREF) &twUI
  882. );
  883. ASSERT(rc == TWRC_SUCCESS);
  884. m_TwainState = State_4_Source_Open;
  885. }
  886. if (m_TwainState == State_4_Source_Open)
  887. {
  888. rc = m_DSM_Entry(
  889. &m_AppId,
  890. 0,
  891. DG_CONTROL,
  892. DAT_IDENTITY,
  893. MSG_CLOSEDS,
  894. (TW_MEMREF) &m_SrcId
  895. );
  896. ASSERT(rc == TWRC_SUCCESS);
  897. m_TwainState = State_3_Source_Manager_Open;
  898. }
  899. if (m_TwainState == State_3_Source_Manager_Open)
  900. {
  901. rc = m_DSM_Entry(
  902. &m_AppId,
  903. 0,
  904. DG_CONTROL,
  905. DAT_PARENT,
  906. MSG_CLOSEDSM,
  907. (TW_MEMREF) &hWndParent
  908. );
  909. ASSERT(rc == TWRC_SUCCESS);
  910. m_TwainState = State_2_Source_Manager_Loaded;
  911. }
  912. }
  913. }
  914. return hr;
  915. }
  916. //////////////////////////////////////////////////////////////////////////
  917. //
  918. //
  919. //
  920. int CTwainMgr::NumDevices(HWND hWndParent)
  921. {
  922. return 1; // this is too slow, better lie...
  923. int nNumDevices = 0;
  924. TW_UINT16 rc = TWRC_FAILURE;
  925. // m_TwainState >= State_2 guarantees m_DSM_Entry != 0
  926. if (m_TwainState >= State_2_Source_Manager_Loaded)
  927. {
  928. __try
  929. {
  930. if (m_TwainState == State_2_Source_Manager_Loaded)
  931. {
  932. // Open the data source manager
  933. rc = m_DSM_Entry(
  934. &m_AppId,
  935. 0,
  936. DG_CONTROL,
  937. DAT_PARENT,
  938. MSG_OPENDSM,
  939. (TW_MEMREF) &hWndParent
  940. );
  941. if (rc != TWRC_SUCCESS)
  942. {
  943. __leave;
  944. }
  945. m_TwainState = State_3_Source_Manager_Open;
  946. }
  947. // Enumerate the devices one by one
  948. TW_IDENTITY SrcId;
  949. rc = m_DSM_Entry(
  950. &m_AppId,
  951. 0,
  952. DG_CONTROL,
  953. DAT_IDENTITY,
  954. MSG_GETFIRST,
  955. (TW_MEMREF) &SrcId
  956. );
  957. while (rc == TWRC_SUCCESS)
  958. {
  959. ++nNumDevices;
  960. rc = m_DSM_Entry(
  961. &m_AppId,
  962. 0,
  963. DG_CONTROL,
  964. DAT_IDENTITY,
  965. MSG_GETNEXT,
  966. (TW_MEMREF) &SrcId
  967. );
  968. }
  969. }
  970. __finally
  971. {
  972. if (m_TwainState == State_3_Source_Manager_Open)
  973. {
  974. // Close the data source manager
  975. rc = m_DSM_Entry(
  976. &m_AppId,
  977. 0,
  978. DG_CONTROL,
  979. DAT_PARENT,
  980. MSG_CLOSEDSM,
  981. (TW_MEMREF) &hWndParent
  982. );
  983. ASSERT(rc == TWRC_SUCCESS);
  984. m_TwainState = State_2_Source_Manager_Loaded;
  985. }
  986. }
  987. }
  988. return nNumDevices;
  989. }
  990. //////////////////////////////////////////////////////////////////////////
  991. //
  992. //
  993. //
  994. TW_UINT16
  995. CTwainMgr::SetCapability(
  996. TW_UINT16 Cap,
  997. TW_UINT16 ItemType,
  998. TW_UINT32 Item
  999. )
  1000. {
  1001. TW_UINT16 rc = TWRC_FAILURE;
  1002. TW_CAPABILITY twCapability;
  1003. twCapability.Cap = Cap;
  1004. twCapability.ConType = TWON_ONEVALUE;
  1005. twCapability.hContainer = 0;
  1006. twCapability.hContainer = GlobalAlloc(
  1007. GMEM_MOVEABLE | GMEM_ZEROINIT,
  1008. sizeof(TW_ONEVALUE)
  1009. );
  1010. if (twCapability.hContainer)
  1011. {
  1012. pTW_ONEVALUE pVal = (pTW_ONEVALUE) GlobalLock(twCapability.hContainer);
  1013. if (pVal)
  1014. {
  1015. pVal->ItemType = ItemType;
  1016. pVal->Item = Item;
  1017. GlobalUnlock(twCapability.hContainer);
  1018. rc = m_DSM_Entry(
  1019. &m_AppId,
  1020. &m_SrcId,
  1021. DG_CONTROL,
  1022. DAT_CAPABILITY,
  1023. MSG_SET,
  1024. (TW_MEMREF) &twCapability
  1025. );
  1026. }
  1027. GlobalFree(twCapability.hContainer);
  1028. }
  1029. return rc;
  1030. }
  1031. //////////////////////////////////////////////////////////////////////////
  1032. //
  1033. //
  1034. //
  1035. TW_UINT16
  1036. CTwainMgr::GetCapability(
  1037. TW_UINT16 Cap,
  1038. pTW_UINT16 pItemType,
  1039. pTW_UINT32 pItem
  1040. )
  1041. {
  1042. TW_CAPABILITY twCapability;
  1043. twCapability.Cap = Cap;
  1044. twCapability.ConType = TWON_DONTCARE16;
  1045. twCapability.hContainer = 0;
  1046. TW_UINT16 rc = m_DSM_Entry(
  1047. &m_AppId,
  1048. &m_SrcId,
  1049. DG_CONTROL,
  1050. DAT_CAPABILITY,
  1051. MSG_GET,
  1052. (TW_MEMREF) &twCapability
  1053. );
  1054. if (twCapability.hContainer)
  1055. {
  1056. pTW_ONEVALUE pVal = (pTW_ONEVALUE) GlobalLock(twCapability.hContainer);
  1057. if (pVal)
  1058. {
  1059. if (pItemType)
  1060. {
  1061. *pItemType = pVal->ItemType;
  1062. }
  1063. if (pItem)
  1064. {
  1065. *pItem = pVal->Item;
  1066. }
  1067. }
  1068. GlobalFree(twCapability.hContainer);
  1069. }
  1070. return rc;
  1071. }
  1072. #endif //USE_TWAIN
  1073. //////////////////////////////////////////////////////////////////////////
  1074. //
  1075. //
  1076. //
  1077. HRESULT
  1078. WiaGetNumDevices(
  1079. IWiaDevMgr *_pWiaDevMgr,
  1080. ULONG *pulNumDevices
  1081. )
  1082. {
  1083. HRESULT hr;
  1084. // Validate and initialize output parameters
  1085. if (pulNumDevices == 0)
  1086. {
  1087. return E_POINTER;
  1088. }
  1089. *pulNumDevices = 0;
  1090. // Create a connection to the local WIA device manager
  1091. CComPtr<IWiaDevMgr> pWiaDevMgr = _pWiaDevMgr;
  1092. if (pWiaDevMgr == 0)
  1093. {
  1094. hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
  1095. if (!SUCCEEDED(hr))
  1096. {
  1097. return hr;
  1098. }
  1099. }
  1100. // Get a list of all the WIA devices on the system
  1101. CComPtr<IEnumWIA_DEV_INFO> pIEnumWIA_DEV_INFO;
  1102. hr = pWiaDevMgr->EnumDeviceInfo(
  1103. 0,
  1104. &pIEnumWIA_DEV_INFO
  1105. );
  1106. if (!SUCCEEDED(hr))
  1107. {
  1108. return hr;
  1109. }
  1110. // Get the number of WIA devices
  1111. ULONG celt;
  1112. hr = pIEnumWIA_DEV_INFO->GetCount(&celt);
  1113. if (!SUCCEEDED(hr))
  1114. {
  1115. return hr;
  1116. }
  1117. *pulNumDevices = celt;
  1118. return S_OK;
  1119. }
  1120. //////////////////////////////////////////////////////////////////////////
  1121. //
  1122. //
  1123. //
  1124. CEventCallback::CEventCallback()
  1125. {
  1126. m_cRef = 0;
  1127. m_nNumDevices = 0;
  1128. }
  1129. //////////////////////////////////////////////////////////////////////////
  1130. //
  1131. //
  1132. //
  1133. HRESULT CEventCallback::Register()
  1134. {
  1135. HRESULT hr;
  1136. // Create a connection to the local WIA device manager
  1137. CComPtr<IWiaDevMgr> pWiaDevMgr;
  1138. hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
  1139. if (!SUCCEEDED(hr))
  1140. {
  1141. return hr;
  1142. }
  1143. // Get the count of all the WIA devices on the system
  1144. hr = WiaGetNumDevices(pWiaDevMgr, &m_nNumDevices);
  1145. if (!SUCCEEDED(hr))
  1146. {
  1147. return hr;
  1148. }
  1149. // Register the callback interface
  1150. hr = pWiaDevMgr->RegisterEventCallbackInterface(
  1151. 0,
  1152. 0,
  1153. &WIA_EVENT_DEVICE_CONNECTED,
  1154. this,
  1155. &m_pConnectEventObject
  1156. );
  1157. if (!SUCCEEDED(hr))
  1158. {
  1159. return hr;
  1160. }
  1161. hr = pWiaDevMgr->RegisterEventCallbackInterface(
  1162. 0,
  1163. 0,
  1164. &WIA_EVENT_DEVICE_DISCONNECTED,
  1165. this,
  1166. &m_pDisconnectEventObject
  1167. );
  1168. if (!SUCCEEDED(hr))
  1169. {
  1170. return hr;
  1171. }
  1172. return S_OK;
  1173. }
  1174. //////////////////////////////////////////////////////////////////////////
  1175. //
  1176. //
  1177. //
  1178. ULONG CEventCallback::GetNumDevices() const
  1179. {
  1180. return m_nNumDevices;
  1181. }
  1182. //////////////////////////////////////////////////////////////////////////
  1183. //
  1184. //
  1185. //
  1186. STDMETHODIMP CEventCallback::QueryInterface(REFIID iid, LPVOID *ppvObj)
  1187. {
  1188. if (ppvObj == 0)
  1189. {
  1190. return E_POINTER;
  1191. }
  1192. if (iid == IID_IUnknown)
  1193. {
  1194. AddRef();
  1195. *ppvObj = (IUnknown *) this;
  1196. return S_OK;
  1197. }
  1198. if (iid == IID_IWiaEventCallback)
  1199. {
  1200. AddRef();
  1201. *ppvObj = (IWiaEventCallback *) this;
  1202. return S_OK;
  1203. }
  1204. *ppvObj = 0;
  1205. return E_NOINTERFACE;
  1206. }
  1207. //////////////////////////////////////////////////////////////////////////
  1208. //
  1209. //
  1210. //
  1211. STDMETHODIMP_(ULONG) CEventCallback::AddRef()
  1212. {
  1213. return InterlockedIncrement(&m_cRef);
  1214. }
  1215. //////////////////////////////////////////////////////////////////////////
  1216. //
  1217. //
  1218. //
  1219. STDMETHODIMP_(ULONG) CEventCallback::Release()
  1220. {
  1221. ASSERT( 0 != m_cRef );
  1222. ULONG cRef = InterlockedDecrement(&m_cRef);
  1223. if (cRef == 0)
  1224. {
  1225. delete this;
  1226. }
  1227. return cRef;
  1228. }
  1229. //////////////////////////////////////////////////////////////////////////
  1230. //
  1231. //
  1232. //
  1233. STDMETHODIMP CEventCallback::ImageEventCallback(
  1234. LPCGUID pEventGuid,
  1235. BSTR bstrEventDescription,
  1236. BSTR bstrDeviceID,
  1237. BSTR bstrDeviceDescription,
  1238. DWORD dwDeviceType,
  1239. BSTR bstrFullItemName,
  1240. ULONG *pulEventType,
  1241. ULONG ulReserved
  1242. )
  1243. {
  1244. return WiaGetNumDevices(0, &m_nNumDevices);
  1245. }
  1246. //////////////////////////////////////////////////////////////////////////
  1247. //
  1248. //
  1249. //
  1250. CDataCallback::CDataCallback(IWiaProgressDialog *pProgress)
  1251. {
  1252. m_cRef = 0;
  1253. m_hBuffer = 0;
  1254. m_lBufferSize = 0;
  1255. m_lDataSize = 0;
  1256. m_pProgress = pProgress;
  1257. #ifdef DBG
  1258. m_hDumpFile = CreateFile(_T("wiadump.bin"), GENERIC_WRITE,
  1259. FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  1260. m_TimeDeviceBegin.QuadPart = 0;
  1261. m_TimeDeviceEnd.QuadPart = 0;
  1262. m_TimeProcessBegin.QuadPart = 0;
  1263. m_TimeProcessEnd.QuadPart = 0;
  1264. m_TimeClientBegin.QuadPart = 0;
  1265. m_TimeClientEnd.QuadPart = 0;
  1266. #endif //DBG
  1267. }
  1268. //////////////////////////////////////////////////////////////////////////
  1269. //
  1270. //
  1271. //
  1272. CDataCallback::~CDataCallback()
  1273. {
  1274. if (m_hBuffer)
  1275. {
  1276. GlobalFree(m_hBuffer);
  1277. }
  1278. #ifdef DBG
  1279. CloseHandle(m_hDumpFile);
  1280. #endif //DBG
  1281. }
  1282. //////////////////////////////////////////////////////////////////////////
  1283. //
  1284. //
  1285. //
  1286. HGLOBAL CDataCallback::GetBuffer()
  1287. {
  1288. HGLOBAL hBuffer = m_hBuffer;
  1289. m_hBuffer = 0;
  1290. m_lBufferSize = 0;
  1291. m_lDataSize = 0;
  1292. return hBuffer;
  1293. }
  1294. //////////////////////////////////////////////////////////////////////////
  1295. //
  1296. //
  1297. //
  1298. STDMETHODIMP CDataCallback::QueryInterface(REFIID iid, LPVOID *ppvObj)
  1299. {
  1300. if (ppvObj == 0)
  1301. {
  1302. return E_POINTER;
  1303. }
  1304. if (iid == IID_IUnknown)
  1305. {
  1306. AddRef();
  1307. *ppvObj = (IUnknown*) this;
  1308. return S_OK;
  1309. }
  1310. if (iid == IID_IWiaDataCallback)
  1311. {
  1312. AddRef();
  1313. *ppvObj = (IWiaDataCallback *) this;
  1314. return S_OK;
  1315. }
  1316. *ppvObj = 0;
  1317. return E_NOINTERFACE;
  1318. }
  1319. //////////////////////////////////////////////////////////////////////////
  1320. //
  1321. //
  1322. //
  1323. STDMETHODIMP_(ULONG) CDataCallback::AddRef()
  1324. {
  1325. return InterlockedIncrement(&m_cRef);
  1326. }
  1327. //////////////////////////////////////////////////////////////////////////
  1328. //
  1329. //
  1330. //
  1331. STDMETHODIMP_(ULONG) CDataCallback::Release()
  1332. {
  1333. ASSERT( 0 != m_cRef );
  1334. ULONG cRef = InterlockedDecrement(&m_cRef);
  1335. if (cRef == 0)
  1336. {
  1337. delete this;
  1338. }
  1339. return cRef;
  1340. }
  1341. //////////////////////////////////////////////////////////////////////////
  1342. //
  1343. //
  1344. //
  1345. STDMETHODIMP CDataCallback::BandedDataCallback(
  1346. LONG lReason,
  1347. LONG lStatus,
  1348. LONG lPercentComplete,
  1349. LONG lOffset,
  1350. LONG lLength,
  1351. LONG lReserved,
  1352. LONG lResLength,
  1353. PBYTE pbBuffer
  1354. )
  1355. {
  1356. HRESULT hr;
  1357. Trace(
  1358. _T("DataCallback: Reason=%d Stat=%d %%=%d Offset=%d Length=%d Buf=%p\n"),
  1359. lReason, lStatus, lPercentComplete, lOffset, lLength, pbBuffer
  1360. );
  1361. // check if the user has pressed cancel
  1362. BOOL bCancelled;
  1363. if (m_pProgress && m_pProgress->Cancelled(&bCancelled) == S_OK && bCancelled)
  1364. {
  1365. return S_FALSE;
  1366. }
  1367. switch (lReason)
  1368. {
  1369. case IT_MSG_DATA_HEADER:
  1370. {
  1371. // allocate memory for the image if the size is given in the header
  1372. PWIA_DATA_CALLBACK_HEADER pHeader = (PWIA_DATA_CALLBACK_HEADER) pbBuffer;
  1373. if (pHeader && pHeader->lBufferSize)
  1374. {
  1375. hr = ReAllocBuffer(pHeader->lBufferSize);
  1376. if (hr != S_OK)
  1377. {
  1378. return S_FALSE;
  1379. }
  1380. }
  1381. break;
  1382. }
  1383. case IT_MSG_DATA:
  1384. {
  1385. QueryStartTimes(lStatus, lPercentComplete);
  1386. UpdateStatus(lStatus, lPercentComplete);
  1387. // if the buffer is not allocated yet and this is the first block,
  1388. // try to allocate a buffer according to the bitmap header info
  1389. if (m_lBufferSize == 0 && lOffset == 0)
  1390. {
  1391. LONG lBufferSize = FindDibSize(pbBuffer);
  1392. if (lBufferSize)
  1393. {
  1394. hr = ReAllocBuffer(lBufferSize);
  1395. if (hr != S_OK)
  1396. {
  1397. return S_FALSE;
  1398. }
  1399. }
  1400. }
  1401. // if the transfer goes past the buffer, try to expand it
  1402. if (lOffset + lLength > m_lBufferSize)
  1403. {
  1404. hr = ReAllocBuffer(lOffset + 2*lLength);
  1405. if (hr != S_OK)
  1406. {
  1407. return S_FALSE;
  1408. }
  1409. }
  1410. // keep track of data size
  1411. if (lOffset + lLength > m_lDataSize)
  1412. {
  1413. m_lDataSize = lOffset + lLength;
  1414. }
  1415. // copy the transfer buffer
  1416. PBYTE pBuffer = (PBYTE) GlobalLock(m_hBuffer);
  1417. if (pBuffer)
  1418. {
  1419. CopyMemory(pBuffer + lOffset, pbBuffer, lLength);
  1420. GlobalUnlock(m_hBuffer);
  1421. }
  1422. #ifdef DBG
  1423. DWORD nWritten;
  1424. SetFilePointer(m_hDumpFile, lOffset, 0, FILE_BEGIN);
  1425. WriteFile(m_hDumpFile, pbBuffer, lLength, &nWritten, 0);
  1426. #endif //DBG
  1427. QueryStopTimes(lStatus, lPercentComplete);
  1428. break;
  1429. }
  1430. case IT_MSG_STATUS:
  1431. {
  1432. // update the progress bar position
  1433. QueryStartTimes(lStatus, lPercentComplete);
  1434. UpdateStatus(lStatus, lPercentComplete);
  1435. QueryStopTimes(lStatus, lPercentComplete);
  1436. break;
  1437. }
  1438. case IT_MSG_TERMINATION:
  1439. {
  1440. PVOID pBuffer = GlobalLock(m_hBuffer);
  1441. if (pBuffer)
  1442. {
  1443. FixDibHeader(pBuffer, m_lDataSize);
  1444. GlobalUnlock(m_hBuffer);
  1445. }
  1446. break;
  1447. }
  1448. case IT_MSG_NEW_PAGE:
  1449. {
  1450. // mspaint should not get this message, but...
  1451. PVOID pBuffer = GlobalLock(m_hBuffer);
  1452. if (pBuffer)
  1453. {
  1454. FixDibHeader(pBuffer, m_lDataSize);
  1455. GlobalUnlock(m_hBuffer);
  1456. }
  1457. break;
  1458. }
  1459. }
  1460. return S_OK;
  1461. }
  1462. //////////////////////////////////////////////////////////////////////////
  1463. //
  1464. //
  1465. //
  1466. HRESULT CDataCallback::ReAllocBuffer(LONG lBufferSize)
  1467. {
  1468. // try to allocate the new buffer
  1469. Trace(_T("Allocating %d bytes for image data\n"), lBufferSize);
  1470. HGLOBAL hBuffer;
  1471. if (m_hBuffer == 0)
  1472. {
  1473. hBuffer = (PBYTE) GlobalAlloc(GMEM_MOVEABLE, lBufferSize);
  1474. }
  1475. else
  1476. {
  1477. hBuffer = (PBYTE) GlobalReAlloc(m_hBuffer, lBufferSize, 0);
  1478. }
  1479. if (hBuffer == 0)
  1480. {
  1481. theApp.SetMemoryEmergency(TRUE);
  1482. return S_FALSE;
  1483. }
  1484. // store this new buffer
  1485. m_hBuffer = hBuffer;
  1486. m_lBufferSize = lBufferSize;
  1487. return S_OK;
  1488. }
  1489. //////////////////////////////////////////////////////////////////////////
  1490. //
  1491. //
  1492. //
  1493. inline ULONG LineWidth(ULONG nWidth, ULONG nBitCount)
  1494. {
  1495. return (((nWidth * nBitCount) + 31) & ~31) >> 3;
  1496. }
  1497. //////////////////////////////////////////////////////////////////////////
  1498. //
  1499. //
  1500. //
  1501. ULONG FindDibSize(LPCVOID pDib)
  1502. {
  1503. ULONG nHeaderSize = *(PDWORD)pDib;
  1504. // Do we recognize the header?
  1505. if (nHeaderSize != sizeof(BITMAPCOREHEADER) &&
  1506. nHeaderSize != sizeof(BITMAPINFOHEADER) &&
  1507. nHeaderSize != sizeof(BITMAPV4HEADER) &&
  1508. nHeaderSize != sizeof(BITMAPV5HEADER))
  1509. {
  1510. return 0;
  1511. }
  1512. // Start the calculation with the header size
  1513. ULONG nDibSize = nHeaderSize;
  1514. // is this an old style BITMAPCOREHEADER?
  1515. if (nHeaderSize == sizeof(BITMAPCOREHEADER))
  1516. {
  1517. PBITMAPCOREHEADER pbmch = (PBITMAPCOREHEADER) pDib;
  1518. // Add the color table size
  1519. if (pbmch->bcBitCount <= 8)
  1520. {
  1521. nDibSize += sizeof(RGBTRIPLE) * (1 << pbmch->bcBitCount);
  1522. }
  1523. // Add the bitmap size
  1524. nDibSize += LineWidth(pbmch->bcWidth, pbmch->bcBitCount) * pbmch->bcHeight;
  1525. }
  1526. else
  1527. {
  1528. // this is at least a BITMAPINFOHEADER
  1529. PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) pDib;
  1530. // Add the color table size
  1531. if (pbmih->biClrUsed != 0)
  1532. {
  1533. nDibSize += sizeof(RGBQUAD) * pbmih->biClrUsed;
  1534. }
  1535. else if (pbmih->biBitCount <= 8)
  1536. {
  1537. nDibSize += sizeof(RGBQUAD) * (1 << pbmih->biBitCount);
  1538. }
  1539. // Add the bitmap size
  1540. if (pbmih->biSizeImage != 0)
  1541. {
  1542. nDibSize += pbmih->biSizeImage;
  1543. }
  1544. else
  1545. {
  1546. // biSizeImage must be specified for compressed bitmaps
  1547. if (pbmih->biCompression != BI_RGB &&
  1548. pbmih->biCompression != BI_BITFIELDS)
  1549. {
  1550. return 0;
  1551. }
  1552. nDibSize += LineWidth(pbmih->biWidth, pbmih->biBitCount) * abs(pbmih->biHeight);
  1553. }
  1554. // Consider special cases
  1555. if (nHeaderSize == sizeof(BITMAPINFOHEADER))
  1556. {
  1557. // If this is a 16 or 32 bit bitmap and BI_BITFIELDS is used,
  1558. // bmiColors member contains three DWORD color masks.
  1559. // For V4 or V5 headers, this info is included the header
  1560. if (pbmih->biCompression == BI_BITFIELDS)
  1561. {
  1562. nDibSize += 3 * sizeof(DWORD);
  1563. }
  1564. }
  1565. else if (nHeaderSize >= sizeof(BITMAPV5HEADER))
  1566. {
  1567. // If this is a V5 header and an ICM profile is specified,
  1568. // we need to consider the profile data size
  1569. PBITMAPV5HEADER pbV5h = (PBITMAPV5HEADER) pDib;
  1570. // if there is some padding before the profile data, add it
  1571. if (pbV5h->bV5ProfileData > nDibSize)
  1572. {
  1573. nDibSize = pbV5h->bV5ProfileData;
  1574. }
  1575. // add the profile data size
  1576. nDibSize += pbV5h->bV5ProfileSize;
  1577. }
  1578. }
  1579. return nDibSize;
  1580. }
  1581. //////////////////////////////////////////////////////////////////////////
  1582. //
  1583. //
  1584. //
  1585. ULONG FindDibOffBits(LPCVOID pDib)
  1586. {
  1587. ULONG nHeaderSize = *(PDWORD)pDib;
  1588. // Do we recognize the header?
  1589. if (nHeaderSize != sizeof(BITMAPCOREHEADER) &&
  1590. nHeaderSize != sizeof(BITMAPINFOHEADER) &&
  1591. nHeaderSize != sizeof(BITMAPV4HEADER) &&
  1592. nHeaderSize != sizeof(BITMAPV5HEADER))
  1593. {
  1594. return 0;
  1595. }
  1596. // Start the calculation with the header size
  1597. ULONG nOffBits = nHeaderSize;
  1598. // is this an old style BITMAPCOREHEADER?
  1599. if (nHeaderSize == sizeof(BITMAPCOREHEADER))
  1600. {
  1601. PBITMAPCOREHEADER pbmch = (PBITMAPCOREHEADER) pDib;
  1602. // Add the color table size
  1603. if (pbmch->bcBitCount <= 8)
  1604. {
  1605. nOffBits += sizeof(RGBTRIPLE) * (1 << pbmch->bcBitCount);
  1606. }
  1607. }
  1608. else
  1609. {
  1610. // this is at least a BITMAPINFOHEADER
  1611. PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) pDib;
  1612. // Add the color table size
  1613. if (pbmih->biClrUsed != 0)
  1614. {
  1615. nOffBits += sizeof(RGBQUAD) * pbmih->biClrUsed;
  1616. }
  1617. else if (pbmih->biBitCount <= 8)
  1618. {
  1619. nOffBits += sizeof(RGBQUAD) * (1 << pbmih->biBitCount);
  1620. }
  1621. // Consider special cases
  1622. if (nHeaderSize == sizeof(BITMAPINFOHEADER))
  1623. {
  1624. // If this is a 16 or 32 bit bitmap and BI_BITFIELDS is used,
  1625. // bmiColors member contains three DWORD color masks.
  1626. // For V4 or V5 headers, this info is included the header
  1627. if (pbmih->biCompression == BI_BITFIELDS)
  1628. {
  1629. nOffBits += 3 * sizeof(DWORD);
  1630. }
  1631. }
  1632. else if (nHeaderSize >= sizeof(BITMAPV5HEADER))
  1633. {
  1634. // If this is a V5 header and an ICM profile is specified,
  1635. // we need to consider the profile data size
  1636. PBITMAPV5HEADER pbV5h = (PBITMAPV5HEADER) pDib;
  1637. // if the profile data comes before the pixel data, add it
  1638. if (pbV5h->bV5ProfileData <= nOffBits)
  1639. {
  1640. nOffBits += pbV5h->bV5ProfileSize;
  1641. }
  1642. }
  1643. }
  1644. return nOffBits;
  1645. }
  1646. //////////////////////////////////////////////////////////////////////////
  1647. //
  1648. //
  1649. //
  1650. void FixDibHeader(LPVOID pDib, DWORD dwSize)
  1651. {
  1652. ULONG nHeaderSize = *(PDWORD)pDib;
  1653. // Do we recognize the header?
  1654. if (nHeaderSize != sizeof(BITMAPCOREHEADER) &&
  1655. nHeaderSize != sizeof(BITMAPINFOHEADER) &&
  1656. nHeaderSize != sizeof(BITMAPV4HEADER) &&
  1657. nHeaderSize != sizeof(BITMAPV5HEADER))
  1658. {
  1659. return;
  1660. }
  1661. // is this an old style BITMAPCOREHEADER?
  1662. if (nHeaderSize == sizeof(BITMAPCOREHEADER))
  1663. {
  1664. PBITMAPCOREHEADER pbmch = (PBITMAPCOREHEADER) pDib;
  1665. // fix the height value if necessary
  1666. if (pbmch->bcHeight == 0)
  1667. {
  1668. // start the calculation with the header size
  1669. DWORD dwSizeImage = dwSize - nHeaderSize;
  1670. // subtract the color table size
  1671. if (pbmch->bcBitCount <= 8)
  1672. {
  1673. dwSizeImage -= sizeof(RGBTRIPLE) * (1 << pbmch->bcBitCount);
  1674. }
  1675. // calculate the height
  1676. pbmch->bcHeight = (WORD) (dwSizeImage / LineWidth(pbmch->bcWidth, pbmch->bcBitCount));
  1677. }
  1678. }
  1679. else
  1680. {
  1681. // this is at least a BITMAPINFOHEADER
  1682. PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) pDib;
  1683. // fix the height value if necessary
  1684. if (pbmih->biHeight == 0)
  1685. {
  1686. // find the size of the image data
  1687. DWORD dwSizeImage;
  1688. if (pbmih->biSizeImage != 0)
  1689. {
  1690. // if the size is specified in the header, take it
  1691. dwSizeImage = pbmih->biSizeImage;
  1692. }
  1693. else
  1694. {
  1695. // start the calculation with the header size
  1696. dwSizeImage = dwSize - nHeaderSize;
  1697. // subtract the color table size
  1698. if (pbmih->biClrUsed != 0)
  1699. {
  1700. dwSizeImage -= sizeof(RGBQUAD) * pbmih->biClrUsed;
  1701. }
  1702. else if (pbmih->biBitCount <= 8)
  1703. {
  1704. dwSizeImage -= sizeof(RGBQUAD) * (1 << pbmih->biBitCount);
  1705. }
  1706. // Consider special cases
  1707. if (nHeaderSize == sizeof(BITMAPINFOHEADER))
  1708. {
  1709. // If this is a 16 or 32 bit bitmap and BI_BITFIELDS is used,
  1710. // bmiColors member contains three DWORD color masks.
  1711. // For V4 or V5 headers, this info is included the header
  1712. if (pbmih->biCompression == BI_BITFIELDS)
  1713. {
  1714. dwSizeImage -= 3 * sizeof(DWORD);
  1715. }
  1716. }
  1717. else if (nHeaderSize >= sizeof(BITMAPV5HEADER))
  1718. {
  1719. // If this is a V5 header and an ICM profile is specified,
  1720. // we need to consider the profile data size
  1721. PBITMAPV5HEADER pbV5h = (PBITMAPV5HEADER) pDib;
  1722. // add the profile data size
  1723. dwSizeImage -= pbV5h->bV5ProfileSize;
  1724. }
  1725. // store the image size
  1726. pbmih->biSizeImage = dwSizeImage;
  1727. }
  1728. // finally, calculate the height
  1729. pbmih->biHeight = -(LONG) (dwSizeImage / LineWidth(pbmih->biWidth, pbmih->biBitCount));
  1730. }
  1731. }
  1732. }
  1733. //////////////////////////////////////////////////////////////////////////
  1734. //
  1735. //
  1736. //
  1737. void CDataCallback::UpdateStatus(LONG lStatus, LONG lPercentComplete)
  1738. {
  1739. if (m_pProgress)
  1740. {
  1741. m_pProgress->SetPercentComplete(lPercentComplete);
  1742. CString strFormat;
  1743. switch (lStatus)
  1744. {
  1745. case IT_STATUS_TRANSFER_FROM_DEVICE:
  1746. strFormat.LoadString(IDS_STATUS_TRANSFER_FROM_DEVICE);
  1747. break;
  1748. case IT_STATUS_PROCESSING_DATA:
  1749. strFormat.LoadString(IDS_STATUS_PROCESSING_DATA);
  1750. break;
  1751. case IT_STATUS_TRANSFER_TO_CLIENT:
  1752. strFormat.LoadString(IDS_STATUS_TRANSFER_TO_CLIENT);
  1753. break;
  1754. }
  1755. CString strStatusText;
  1756. strStatusText.Format(strFormat, lPercentComplete);
  1757. USES_CONVERSION;
  1758. m_pProgress->SetMessage(T2CW(strStatusText));
  1759. }
  1760. }
  1761. //////////////////////////////////////////////////////////////////////////
  1762. //
  1763. //
  1764. //
  1765. #ifdef DBG
  1766. void CDataCallback::QueryStartTimes(LONG lStatus, LONG lPercentComplete)
  1767. {
  1768. if (lStatus & IT_STATUS_TRANSFER_FROM_DEVICE &&
  1769. (lPercentComplete == 0 || m_TimeDeviceBegin.QuadPart == 0))
  1770. {
  1771. QueryPerformanceCounter(&m_TimeDeviceBegin);
  1772. }
  1773. if (lStatus & IT_STATUS_PROCESSING_DATA &&
  1774. (lPercentComplete == 0 || m_TimeProcessBegin.QuadPart == 0))
  1775. {
  1776. QueryPerformanceCounter(&m_TimeProcessBegin);
  1777. }
  1778. if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT &&
  1779. (lPercentComplete == 0 || m_TimeClientBegin.QuadPart == 0))
  1780. {
  1781. QueryPerformanceCounter(&m_TimeClientBegin);
  1782. }
  1783. }
  1784. void CDataCallback::QueryStopTimes(LONG lStatus, LONG lPercentComplete)
  1785. {
  1786. if (lStatus & IT_STATUS_TRANSFER_FROM_DEVICE && lPercentComplete == 100)
  1787. {
  1788. QueryPerformanceCounter(&m_TimeDeviceEnd);
  1789. }
  1790. if (lStatus & IT_STATUS_PROCESSING_DATA && lPercentComplete == 100)
  1791. {
  1792. QueryPerformanceCounter(&m_TimeProcessEnd);
  1793. }
  1794. if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT && lPercentComplete == 100)
  1795. {
  1796. QueryPerformanceCounter(&m_TimeClientEnd);
  1797. }
  1798. }
  1799. void CDataCallback::PrintTimes()
  1800. {
  1801. LARGE_INTEGER Freq;
  1802. QueryPerformanceFrequency(&Freq);
  1803. double nTimeDevice =
  1804. (double) (m_TimeDeviceEnd.QuadPart - m_TimeDeviceBegin.QuadPart) /
  1805. (double) Freq.QuadPart;
  1806. double nTimeProcess =
  1807. (double) (m_TimeProcessEnd.QuadPart - m_TimeProcessBegin.QuadPart) /
  1808. (double) Freq.QuadPart;
  1809. double nTimeClient =
  1810. (double) (m_TimeClientEnd.QuadPart - m_TimeClientBegin.QuadPart) /
  1811. (double) Freq.QuadPart;
  1812. Trace(
  1813. _T("TRANSFER_FROM_DEVICE = %.02lf secs\n")
  1814. _T("PROCESSING_DATA = %.02lf secs\n")
  1815. _T("TRANSFER_TO_CLIENT = %.02lf secs\n")
  1816. _T("\n"),
  1817. nTimeDevice,
  1818. nTimeProcess,
  1819. nTimeClient
  1820. );
  1821. }
  1822. #else //DBG
  1823. inline void CDataCallback::QueryStartTimes(LONG, LONG)
  1824. {
  1825. }
  1826. inline void CDataCallback::QueryStopTimes(LONG, LONG)
  1827. {
  1828. }
  1829. inline void CDataCallback::PrintTimes()
  1830. {
  1831. }
  1832. #endif //DBG
  1833. //////////////////////////////////////////////////////////////////////////
  1834. //
  1835. //
  1836. //
  1837. CProgressDialog::CProgressDialog()
  1838. {
  1839. m_cRef = 0;
  1840. }
  1841. CProgressDialog::~CProgressDialog()
  1842. {
  1843. // remove the "downloading..." message from the status bar
  1844. if (g_pStatBarWnd)
  1845. {
  1846. g_pStatBarWnd->SetPaneText(0, _T(""));
  1847. }
  1848. }
  1849. STDMETHODIMP CProgressDialog::QueryInterface(REFIID iid, LPVOID *ppvObj)
  1850. {
  1851. if (ppvObj == 0)
  1852. {
  1853. return E_POINTER;
  1854. }
  1855. if (iid == IID_IUnknown)
  1856. {
  1857. AddRef();
  1858. *ppvObj = (IUnknown*) this;
  1859. return S_OK;
  1860. }
  1861. if (iid == IID_IWiaProgressDialog)
  1862. {
  1863. AddRef();
  1864. *ppvObj = (IWiaProgressDialog *) this;
  1865. return S_OK;
  1866. }
  1867. *ppvObj = 0;
  1868. return E_NOINTERFACE;
  1869. }
  1870. STDMETHODIMP_(ULONG) CProgressDialog::AddRef()
  1871. {
  1872. return InterlockedIncrement(&m_cRef);
  1873. }
  1874. STDMETHODIMP_(ULONG) CProgressDialog::Release()
  1875. {
  1876. ASSERT( 0 != m_cRef );
  1877. LONG cRef = InterlockedDecrement(&m_cRef);
  1878. if (cRef == 0)
  1879. {
  1880. delete this;
  1881. }
  1882. return cRef;
  1883. }
  1884. STDMETHODIMP CProgressDialog::Create(HWND hwndParent, LONG lFlags)
  1885. {
  1886. if (g_pStatBarWnd)
  1887. {
  1888. RECT r;
  1889. g_pStatBarWnd->GetItemRect(1, &r);
  1890. m_ProgressCtrl.Create(WS_CHILD | WS_VISIBLE, r, g_pStatBarWnd, 1);
  1891. m_ProgressCtrl.SetRange(0, 100);
  1892. }
  1893. return S_OK;
  1894. }
  1895. STDMETHODIMP CProgressDialog::Show()
  1896. {
  1897. m_ProgressCtrl.UpdateWindow();
  1898. return S_OK;
  1899. }
  1900. STDMETHODIMP CProgressDialog::Hide()
  1901. {
  1902. return S_OK;
  1903. }
  1904. STDMETHODIMP CProgressDialog::Cancelled(BOOL *pbCancelled)
  1905. {
  1906. *pbCancelled = FALSE;
  1907. return S_OK;
  1908. }
  1909. STDMETHODIMP CProgressDialog::SetTitle(LPCWSTR pszMessage)
  1910. {
  1911. return S_OK;
  1912. }
  1913. STDMETHODIMP CProgressDialog::SetMessage(LPCWSTR pszTitle)
  1914. {
  1915. if (g_pStatBarWnd)
  1916. {
  1917. USES_CONVERSION;
  1918. g_pStatBarWnd->SetPaneText(0, W2CT(pszTitle));
  1919. }
  1920. return S_OK;
  1921. }
  1922. STDMETHODIMP CProgressDialog::SetPercentComplete(UINT nPercent)
  1923. {
  1924. m_ProgressCtrl.SetPos(nPercent);
  1925. return S_OK;
  1926. }
  1927. STDMETHODIMP CProgressDialog::Destroy()
  1928. {
  1929. return S_OK;
  1930. }