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.

2531 lines
116 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: THRDMSG.CPP
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 9/28/1999
  12. *
  13. * DESCRIPTION: These classes are instantiated for each message posted to the
  14. * background thread. Each is derived from CThreadMessage, and
  15. * is sent to the thread message handler.
  16. *
  17. *******************************************************************************/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include "itranhlp.h"
  21. #include "isuppfmt.h"
  22. #include "wiadevdp.h"
  23. #include "acqmgrcw.h"
  24. #include "propstrm.h"
  25. #include "uiexthlp.h"
  26. #include "flnfile.h"
  27. #include "resource.h"
  28. #include "itranspl.h"
  29. #include "svselfil.h"
  30. #include "uniqfile.h"
  31. #include "mboxex.h"
  32. #include "wiaffmt.h"
  33. #define FILE_CREATION_MUTEX_NAME TEXT("Global\\WiaScannerAndCameraWizardFileNameCreationMutex")
  34. #define UPLOAD_PROGRESS_GRANULARITY 10
  35. #ifndef S_CONTINUE
  36. #define S_CONTINUE ((HRESULT)0x00000002L)
  37. #endif
  38. //
  39. // The delete progress page goes by too quickly, so we will slow it down here
  40. //
  41. #define DELETE_DELAY_BEFORE 1000
  42. #define DELETE_DELAY_DURING 3000
  43. #define DELETE_DELAY_AFTER 1000
  44. //
  45. // Some APIs claim to set the thread's last error, but don't
  46. // For those which don't, we will return E_FAIL. This function
  47. // will not return S_OK
  48. //
  49. inline HRESULT MY_HRESULT_FROM_WIN32( DWORD gle )
  50. {
  51. if (!gle)
  52. {
  53. return E_FAIL;
  54. }
  55. return HRESULT_FROM_WIN32(gle);
  56. }
  57. // -------------------------------------------------
  58. // CGlobalInterfaceTableThreadMessage
  59. // -------------------------------------------------
  60. CGlobalInterfaceTableThreadMessage::CGlobalInterfaceTableThreadMessage( int nMessage, HWND hWndNotify, DWORD dwGlobalInterfaceTableCookie )
  61. : CNotifyThreadMessage( nMessage, hWndNotify ),
  62. m_dwGlobalInterfaceTableCookie(dwGlobalInterfaceTableCookie)
  63. {
  64. }
  65. DWORD CGlobalInterfaceTableThreadMessage::GlobalInterfaceTableCookie(void) const
  66. {
  67. return(m_dwGlobalInterfaceTableCookie);
  68. }
  69. // -------------------------------------------------
  70. // CDownloadThumbnailThreadMessage
  71. // -------------------------------------------------
  72. CDownloadThumbnailsThreadMessage::CDownloadThumbnailsThreadMessage( HWND hWndNotify, const CSimpleDynamicArray<DWORD> &Cookies, HANDLE hCancelEvent )
  73. : CNotifyThreadMessage( TQ_DOWNLOADTHUMBNAIL, hWndNotify ),
  74. m_Cookies(Cookies),
  75. m_hCancelEvent(NULL)
  76. {
  77. DuplicateHandle( GetCurrentProcess(), hCancelEvent, GetCurrentProcess(), &m_hCancelEvent, 0, FALSE, DUPLICATE_SAME_ACCESS );
  78. }
  79. CDownloadThumbnailsThreadMessage::~CDownloadThumbnailsThreadMessage(void)
  80. {
  81. if (m_hCancelEvent)
  82. {
  83. CloseHandle(m_hCancelEvent);
  84. m_hCancelEvent = NULL;
  85. }
  86. }
  87. // Helper function that gets the thumbnail data and creates a DIB from it
  88. static HRESULT DownloadAndCreateThumbnail( IWiaItem *pWiaItem, PBYTE *ppBitmapData, LONG &nWidth, LONG &nHeight, LONG &nBitmapDataLength, GUID &guidPreferredFormat, LONG &nAccessRights, LONG &nImageWidth, LONG &nImageHeight, CAnnotationType &AnnotationType, CSimpleString &strDefExt )
  89. {
  90. #if 0 // defined(DBG)
  91. Sleep(3000);
  92. #endif
  93. WIA_PUSH_FUNCTION((TEXT("DownloadAndCreateThumbnail")));
  94. CComPtr<IWiaPropertyStorage> pIWiaPropertyStorage;
  95. HRESULT hr = pWiaItem->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropertyStorage);
  96. if (SUCCEEDED(hr))
  97. {
  98. AnnotationType = AnnotationNone;
  99. CComPtr<IWiaAnnotationHelpers> pWiaAnnotationHelpers;
  100. if (SUCCEEDED(CoCreateInstance( CLSID_WiaDefaultUi, NULL,CLSCTX_INPROC_SERVER, IID_IWiaAnnotationHelpers,(void**)&pWiaAnnotationHelpers )))
  101. {
  102. pWiaAnnotationHelpers->GetAnnotationType( pWiaItem, AnnotationType );
  103. }
  104. const int c_NumProps = 7;
  105. PROPVARIANT PropVar[c_NumProps];
  106. PROPSPEC PropSpec[c_NumProps];
  107. PropSpec[0].ulKind = PRSPEC_PROPID;
  108. PropSpec[0].propid = WIA_IPC_THUMB_WIDTH;
  109. PropSpec[1].ulKind = PRSPEC_PROPID;
  110. PropSpec[1].propid = WIA_IPC_THUMB_HEIGHT;
  111. PropSpec[2].ulKind = PRSPEC_PROPID;
  112. PropSpec[2].propid = WIA_IPC_THUMBNAIL;
  113. PropSpec[3].ulKind = PRSPEC_PROPID;
  114. PropSpec[3].propid = WIA_IPA_PREFERRED_FORMAT;
  115. PropSpec[4].ulKind = PRSPEC_PROPID;
  116. PropSpec[4].propid = WIA_IPA_ACCESS_RIGHTS;
  117. PropSpec[5].ulKind = PRSPEC_PROPID;
  118. PropSpec[5].propid = WIA_IPA_PIXELS_PER_LINE;
  119. PropSpec[6].ulKind = PRSPEC_PROPID;
  120. PropSpec[6].propid = WIA_IPA_NUMBER_OF_LINES;
  121. hr = pIWiaPropertyStorage->ReadMultiple(ARRAYSIZE(PropSpec),PropSpec,PropVar );
  122. if (SUCCEEDED(hr))
  123. {
  124. //
  125. // Save the item type
  126. //
  127. if (VT_CLSID == PropVar[3].vt && PropVar[3].puuid)
  128. {
  129. guidPreferredFormat = *(PropVar[3].puuid);
  130. }
  131. else
  132. {
  133. guidPreferredFormat = IID_NULL;
  134. }
  135. //
  136. // Get the extension for the default format
  137. //
  138. strDefExt = CWiaFileFormat::GetExtension( guidPreferredFormat, TYMED_FILE, pWiaItem );
  139. //
  140. // Save the access rights
  141. //
  142. nAccessRights = PropVar[4].lVal;
  143. if ((PropVar[0].vt == VT_I4 || PropVar[0].vt == VT_UI4) &&
  144. (PropVar[1].vt == VT_I4 || PropVar[1].vt == VT_UI4) &&
  145. (PropVar[2].vt == (VT_UI1|VT_VECTOR)))
  146. {
  147. if (PropVar[2].caub.cElems >= PropVar[0].ulVal * PropVar[1].ulVal)
  148. {
  149. //
  150. // Allocate memory for the bitmap data. It will be freed by the main thread.
  151. //
  152. *ppBitmapData = reinterpret_cast<PBYTE>(LocalAlloc( LPTR, PropVar[2].caub.cElems ));
  153. if (*ppBitmapData)
  154. {
  155. WIA_TRACE((TEXT("We found a thumbnail!")));
  156. CopyMemory( *ppBitmapData, PropVar[2].caub.pElems, PropVar[2].caub.cElems );
  157. nWidth = PropVar[0].ulVal;
  158. nHeight = PropVar[1].ulVal;
  159. nImageWidth = PropVar[5].ulVal;
  160. nImageHeight = PropVar[6].ulVal;
  161. nBitmapDataLength = PropVar[2].caub.cElems;
  162. WIA_TRACE((TEXT("nImageWidth = %d, nImageHeight = %d!"), nImageWidth, nImageHeight ));
  163. }
  164. else
  165. {
  166. hr = E_OUTOFMEMORY;
  167. WIA_PRINTHRESULT((hr,TEXT("Unable to allocate bitmap data")));
  168. }
  169. }
  170. else
  171. {
  172. hr = E_FAIL;
  173. WIA_PRINTHRESULT((hr,TEXT("Invalid bitmap data returned")));
  174. }
  175. }
  176. else
  177. {
  178. hr = E_FAIL;
  179. WIA_ERROR((TEXT("The bitmap data is in the wrong format! %d"),PropVar[2].vt));
  180. }
  181. //
  182. // Free any properties the array contains
  183. //
  184. FreePropVariantArray( ARRAYSIZE(PropVar), PropVar );
  185. }
  186. else
  187. {
  188. WIA_PRINTHRESULT((hr,TEXT("ReadMultiple failed")));
  189. }
  190. }
  191. else
  192. {
  193. WIA_PRINTHRESULT((hr,TEXT("QueryInterface on IID_IWiaPropertyStorage failed")));
  194. }
  195. return hr;
  196. }
  197. HRESULT CDownloadThumbnailsThreadMessage::Download(void)
  198. {
  199. WIA_PUSHFUNCTION((TEXT("CDownloadThumbnailsThreadMessage::Download")));
  200. //
  201. // Tell the main thread we are going to start downloading thumbnails
  202. //
  203. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadThumbnailsThreadNotifyMessage::BeginDownloadAllMessage( m_Cookies.Size() ) );
  204. //
  205. // Get an instance of the GIT
  206. //
  207. CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
  208. HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (VOID**)&pGlobalInterfaceTable );
  209. if (SUCCEEDED(hr))
  210. {
  211. //
  212. // m_Cookies.Size() contains the number of thumbnails we need to get
  213. //
  214. for (int i=0;i<m_Cookies.Size() && hr == S_OK;i++)
  215. {
  216. //
  217. // Check to see if we're cancelled. If we are, break out of the loop
  218. //
  219. if (m_hCancelEvent && WAIT_OBJECT_0==WaitForSingleObject(m_hCancelEvent,0))
  220. {
  221. hr = S_FALSE;
  222. break;
  223. }
  224. //
  225. // Get the item from the global interface table
  226. //
  227. CComPtr<IWiaItem> pWiaItem = NULL;
  228. hr = pGlobalInterfaceTable->GetInterfaceFromGlobal( m_Cookies[i], IID_IWiaItem, (void**)&pWiaItem );
  229. if (SUCCEEDED(hr))
  230. {
  231. //
  232. // Get the bitmap data and other properties we are reading now
  233. //
  234. PBYTE pBitmapData = NULL;
  235. GUID guidPreferredFormat;
  236. LONG nAccessRights = 0, nWidth = 0, nHeight = 0, nPictureWidth = 0, nPictureHeight = 0, nBitmapDataLength = 0;
  237. CAnnotationType AnnotationType = AnnotationNone;
  238. CSimpleString strDefExt;
  239. //
  240. // Notify the main thread that we are beginning to download the thumbnail and other props
  241. //
  242. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadThumbnailsThreadNotifyMessage::BeginDownloadThumbnailMessage( i, m_Cookies[i] ) );
  243. //
  244. // Only send an End message if we were successful
  245. //
  246. if (SUCCEEDED(DownloadAndCreateThumbnail( pWiaItem, &pBitmapData, nWidth, nHeight, nBitmapDataLength, guidPreferredFormat, nAccessRights, nPictureWidth, nPictureHeight, AnnotationType, strDefExt )))
  247. {
  248. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadThumbnailsThreadNotifyMessage::EndDownloadThumbnailMessage( i, m_Cookies[i], pBitmapData, nWidth, nHeight, nBitmapDataLength, guidPreferredFormat, nAccessRights, nPictureWidth, nPictureHeight, AnnotationType, strDefExt ) );
  249. }
  250. }
  251. }
  252. }
  253. //
  254. // Tell the main thread we are done
  255. //
  256. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadThumbnailsThreadNotifyMessage::EndDownloadAllMessage( hr ) );
  257. return hr;
  258. }
  259. // -------------------------------------------------
  260. // CDownloadImagesThreadMessage
  261. // -------------------------------------------------
  262. CDownloadImagesThreadMessage::CDownloadImagesThreadMessage(
  263. HWND hWndNotify,
  264. const CSimpleDynamicArray<DWORD> &Cookies,
  265. const CSimpleDynamicArray<int> &Rotation,
  266. LPCTSTR pszDirectory,
  267. LPCTSTR pszFilename,
  268. const GUID &guidFormat,
  269. HANDLE hCancelDownloadEvent,
  270. bool bStampTime,
  271. HANDLE hPauseDownloadEvent
  272. )
  273. : CNotifyThreadMessage( TQ_DOWNLOADIMAGE, hWndNotify ),
  274. m_Cookies(Cookies),
  275. m_Rotation(Rotation),
  276. m_strDirectory(pszDirectory),
  277. m_strFilename(pszFilename),
  278. m_guidFormat(guidFormat),
  279. m_hCancelDownloadEvent(NULL),
  280. m_bStampTime(bStampTime),
  281. m_nLastStatusUpdatePercent(-1),
  282. m_bFirstTransfer(true),
  283. m_hPauseDownloadEvent(NULL),
  284. m_hFilenameCreationMutex(NULL)
  285. {
  286. DuplicateHandle( GetCurrentProcess(), hCancelDownloadEvent, GetCurrentProcess(), &m_hCancelDownloadEvent, 0, FALSE, DUPLICATE_SAME_ACCESS );
  287. DuplicateHandle( GetCurrentProcess(), hPauseDownloadEvent, GetCurrentProcess(), &m_hPauseDownloadEvent, 0, FALSE, DUPLICATE_SAME_ACCESS );
  288. m_hFilenameCreationMutex = CreateMutex( NULL, FALSE, FILE_CREATION_MUTEX_NAME );
  289. }
  290. CDownloadImagesThreadMessage::~CDownloadImagesThreadMessage(void)
  291. {
  292. if (m_hCancelDownloadEvent)
  293. {
  294. CloseHandle(m_hCancelDownloadEvent);
  295. m_hCancelDownloadEvent = NULL;
  296. }
  297. if (m_hPauseDownloadEvent)
  298. {
  299. CloseHandle(m_hPauseDownloadEvent);
  300. m_hPauseDownloadEvent = NULL;
  301. }
  302. if (m_hFilenameCreationMutex)
  303. {
  304. CloseHandle(m_hFilenameCreationMutex);
  305. m_hFilenameCreationMutex = NULL;
  306. }
  307. }
  308. int CDownloadImagesThreadMessage::ReportError( HWND hWndNotify, const CSimpleString &strMessage, int nMessageBoxFlags )
  309. {
  310. //
  311. // How long should we wait to find out if this is being handled?
  312. //
  313. const UINT c_nSecondsToWaitForHandler = 10;
  314. //
  315. // Cancel is the default, in case nobody handles the message, or we are out of resources
  316. //
  317. int nResult = CMessageBoxEx::IDMBEX_CANCEL;
  318. //
  319. // This event will be signalled by the handler when it is going to display some UI
  320. //
  321. HANDLE hHandledMessageEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  322. if (hHandledMessageEvent)
  323. {
  324. //
  325. // This event will be signalled when the user has responded
  326. //
  327. HANDLE hRespondedMessageEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  328. if (hRespondedMessageEvent)
  329. {
  330. //
  331. // Create a notification message class and make sure it isn't NULL
  332. //
  333. CDownloadErrorNotificationMessage *pDownloadErrorNotificationMessage = CDownloadErrorNotificationMessage::ReportDownloadError( strMessage, hHandledMessageEvent, hRespondedMessageEvent, nMessageBoxFlags, nResult );
  334. if (pDownloadErrorNotificationMessage)
  335. {
  336. //
  337. // Send the message
  338. //
  339. CThreadNotificationMessage::SendMessage( hWndNotify, pDownloadErrorNotificationMessage );
  340. //
  341. // Wait c_nSecondsToWaitForHandler seconds for someone to decide to handle the message
  342. //
  343. if (WiaUiUtil::MsgWaitForSingleObject(hHandledMessageEvent,c_nSecondsToWaitForHandler*1000))
  344. {
  345. //
  346. // Wait forever for user input
  347. //
  348. if (WiaUiUtil::MsgWaitForSingleObject(hRespondedMessageEvent,INFINITE))
  349. {
  350. //
  351. // Nothing to do.
  352. //
  353. }
  354. }
  355. }
  356. //
  357. // Done with this event
  358. //
  359. CloseHandle(hRespondedMessageEvent);
  360. }
  361. //
  362. // Done with this event
  363. //
  364. CloseHandle(hHandledMessageEvent);
  365. }
  366. return nResult;
  367. }
  368. //
  369. // This function will sort of arbitrarily try to decide if a
  370. // it is possible the user chose an area that is too large
  371. //
  372. static bool ScannerImageSizeSeemsExcessive( IWiaItem *pWiaItem )
  373. {
  374. WIA_PUSHFUNCTION(TEXT("ScannerImageSizeSeemsExcessive"));
  375. //
  376. // Assume it isn't too large
  377. //
  378. bool bResult = false;
  379. LONG nHorizontalExt=0, nVerticalExt=0;
  380. if (PropStorageHelpers::GetProperty( pWiaItem, WIA_IPS_XEXTENT, nHorizontalExt ) && PropStorageHelpers::GetProperty( pWiaItem, WIA_IPS_YEXTENT, nVerticalExt ))
  381. {
  382. LONG nColorDepth=0;
  383. if (PropStorageHelpers::GetProperty( pWiaItem, WIA_IPA_DEPTH, nColorDepth ))
  384. {
  385. WIA_TRACE((TEXT("Scan Size: %d"), (nHorizontalExt * nVerticalExt * nColorDepth) / 8 ));
  386. //
  387. // If an uncompressed scan is larger than 50 MB
  388. //
  389. if ((nHorizontalExt * nVerticalExt * nColorDepth) / 8 > 1024*1024*50)
  390. {
  391. bResult = true;
  392. }
  393. }
  394. }
  395. return bResult;
  396. }
  397. int CDownloadImagesThreadMessage::ReportDownloadError( HWND hWndNotify, IWiaItem *pWiaItem, HRESULT &hr, bool bAllowContinue, bool bPageFeederActive, bool bUsableMultipageFileExists, bool bMultiPageTransfer )
  398. {
  399. WIA_PUSH_FUNCTION((TEXT("CDownloadImagesThreadMessage::ReportDownloadError( hWndNotify: %p, pWiaItem: %p, hr: %08X, bAllowContinue: %d, bPageFeederActive: %d, bUsableMultipageFileExists: %d"), hWndNotify, pWiaItem, hr, bAllowContinue, bPageFeederActive, bUsableMultipageFileExists ));
  400. WIA_PRINTHRESULT((hr,TEXT("HRESULT:")));
  401. //
  402. // Get the device type property
  403. //
  404. LONG lDeviceType = 0;
  405. CComPtr<IWiaItem> pWiaItemRoot;
  406. if (pWiaItem && SUCCEEDED(pWiaItem->GetRootItem(&pWiaItemRoot)))
  407. {
  408. PropStorageHelpers::GetProperty( pWiaItemRoot, WIA_DIP_DEV_TYPE, lDeviceType );
  409. }
  410. //
  411. // Get the actual device type bits
  412. //
  413. lDeviceType = GET_STIDEVICE_TYPE(lDeviceType);
  414. //
  415. // Default message box buttons
  416. //
  417. int nMessageBoxFlags = 0;
  418. //
  419. // Default message
  420. //
  421. CSimpleString strMessage(TEXT(""));
  422. //
  423. // Take a first cut at getting the correct error message
  424. //
  425. switch (hr)
  426. {
  427. case WIA_ERROR_OFFLINE:
  428. //
  429. // The device is disconnected. Nothing we can do here, so just return.
  430. //
  431. return CMessageBoxEx::IDMBEX_CANCEL;
  432. case WIA_ERROR_ITEM_DELETED:
  433. //
  434. // If the item has been deleted, just continue.
  435. //
  436. return CMessageBoxEx::IDMBEX_SKIP;
  437. case WIA_ERROR_BUSY:
  438. nMessageBoxFlags = CMessageBoxEx::MBEX_CANCELRETRY|CMessageBoxEx::MBEX_DEFBUTTON2|CMessageBoxEx::MBEX_ICONWARNING;
  439. strMessage = CSimpleString( IDS_TRANSFER_DEVICEBUSY, g_hInstance );
  440. break;
  441. case WIA_ERROR_PAPER_EMPTY:
  442. nMessageBoxFlags = CMessageBoxEx::MBEX_CANCELRETRY|CMessageBoxEx::MBEX_DEFBUTTON2|CMessageBoxEx::MBEX_ICONWARNING;
  443. strMessage = CSimpleString( IDS_TRANSFER_PAPEREMPTY, g_hInstance );
  444. break;
  445. case E_OUTOFMEMORY:
  446. if (StiDeviceTypeScanner == lDeviceType && ScannerImageSizeSeemsExcessive(pWiaItem))
  447. {
  448. //
  449. // Handle the case where we think the user may have chosen an insane image size
  450. //
  451. nMessageBoxFlags = CMessageBoxEx::MBEX_OK|CMessageBoxEx::MBEX_ICONWARNING;
  452. strMessage = CSimpleString( IDS_TRANSFER_SCANNEDITEMMAYBETOOLARGE, g_hInstance );
  453. break;
  454. }
  455. }
  456. //
  457. // If we still don't have an error message, see if this is a special case
  458. //
  459. if (!nMessageBoxFlags || !strMessage.Length())
  460. {
  461. if (bPageFeederActive)
  462. {
  463. if (bMultiPageTransfer)
  464. {
  465. if (bUsableMultipageFileExists)
  466. {
  467. switch (hr)
  468. {
  469. case WIA_ERROR_PAPER_JAM:
  470. case WIA_ERROR_PAPER_PROBLEM:
  471. //
  472. // We can recover the rest of the file in these cases.
  473. //
  474. nMessageBoxFlags = CMessageBoxEx::MBEX_ICONINFORMATION|CMessageBoxEx::MBEX_YESNO;
  475. strMessage = CSimpleString( IDS_MULTIPAGE_PAPER_PROBLEM, g_hInstance );
  476. break;
  477. default:
  478. nMessageBoxFlags = CMessageBoxEx::MBEX_ICONERROR|CMessageBoxEx::MBEX_OK;
  479. strMessage = CSimpleString( IDS_MULTIPAGE_FATAL_ERROR, g_hInstance );
  480. break;
  481. }
  482. }
  483. else
  484. {
  485. nMessageBoxFlags = CMessageBoxEx::MBEX_ICONERROR|CMessageBoxEx::MBEX_OK;
  486. strMessage = CSimpleString( IDS_MULTIPAGE_FATAL_ERROR, g_hInstance );
  487. }
  488. }
  489. }
  490. }
  491. //
  492. // If we still don't have a message, use the default
  493. //
  494. if (!nMessageBoxFlags || !strMessage.Length())
  495. {
  496. if (bAllowContinue)
  497. {
  498. nMessageBoxFlags = CMessageBoxEx::MBEX_CANCELRETRYSKIPSKIPALL|CMessageBoxEx::MBEX_DEFBUTTON2|CMessageBoxEx::MBEX_ICONWARNING;
  499. strMessage = CSimpleString( IDS_TRANSFER_GENERICFAILURE, g_hInstance );
  500. }
  501. else
  502. {
  503. nMessageBoxFlags = CMessageBoxEx::MBEX_CANCELRETRY|CMessageBoxEx::MBEX_DEFBUTTON1|CMessageBoxEx::MBEX_ICONWARNING;
  504. strMessage = CSimpleString( IDS_TRANSFER_GENERICFAILURE_NO_CONTINUE, g_hInstance );
  505. }
  506. }
  507. //
  508. // Report the error
  509. //
  510. int nResult = ReportError( hWndNotify, strMessage, nMessageBoxFlags );
  511. //
  512. // Special cases, give us a chance to change the hresult and return value
  513. //
  514. if (bPageFeederActive && !bUsableMultipageFileExists && (CMessageBoxEx::IDMBEX_SKIP == nResult || CMessageBoxEx::IDMBEX_SKIPALL == nResult))
  515. {
  516. hr = WIA_ERROR_PAPER_EMPTY;
  517. nResult = CMessageBoxEx::IDMBEX_SKIP;
  518. }
  519. else if (bPageFeederActive && bUsableMultipageFileExists && (WIA_ERROR_PAPER_JAM == hr || WIA_ERROR_PAPER_PROBLEM == hr))
  520. {
  521. if (CMessageBoxEx::IDMBEX_YES == nResult)
  522. {
  523. hr = S_OK;
  524. nResult = CMessageBoxEx::IDMBEX_SKIP;
  525. }
  526. else
  527. {
  528. nResult = CMessageBoxEx::IDMBEX_CANCEL;
  529. }
  530. }
  531. return nResult;
  532. }
  533. static void GetIdealInputFormat( IWiaSupportedFormats *pWiaSupportedFormats, const GUID &guidOutputFormat, GUID &guidInputFormat )
  534. {
  535. //
  536. // If we can get the input format and the output format to be the same, that is best
  537. // If we cannot, we will use DIB, which we can convert to the output format
  538. //
  539. //
  540. // Get the format count
  541. //
  542. LONG nCount = 0;
  543. HRESULT hr = pWiaSupportedFormats->GetFormatCount(&nCount);
  544. if (SUCCEEDED(hr))
  545. {
  546. //
  547. // Search for the output format
  548. //
  549. for (LONG i=0;i<nCount;i++)
  550. {
  551. GUID guidCurrentFormat;
  552. hr = pWiaSupportedFormats->GetFormatType( i, &guidCurrentFormat );
  553. if (SUCCEEDED(hr))
  554. {
  555. //
  556. // If we've found the output format, save it as the input format and return
  557. //
  558. if (guidCurrentFormat == guidOutputFormat)
  559. {
  560. guidInputFormat = guidOutputFormat;
  561. return;
  562. }
  563. }
  564. }
  565. }
  566. //
  567. // If we've gotten this far, we have to use BMP
  568. //
  569. guidInputFormat = WiaImgFmt_BMP;
  570. }
  571. HRESULT CDownloadImagesThreadMessage::GetListOfTransferItems( IWiaItem *pWiaItem, CSimpleDynamicArray<CTransferItem> &TransferItems )
  572. {
  573. if (pWiaItem)
  574. {
  575. //
  576. // Add this item
  577. //
  578. TransferItems.Append(CTransferItem(pWiaItem));
  579. //
  580. // If this item has attachments, enumerate and add them
  581. //
  582. LONG nItemType = 0;
  583. if (SUCCEEDED(pWiaItem->GetItemType(&nItemType)) && (nItemType & WiaItemTypeHasAttachments))
  584. {
  585. CComPtr<IEnumWiaItem> pEnumWiaItem;
  586. if (SUCCEEDED(pWiaItem->EnumChildItems( &pEnumWiaItem )))
  587. {
  588. CComPtr<IWiaItem> pWiaItem;
  589. while (S_OK == pEnumWiaItem->Next(1,&pWiaItem,NULL))
  590. {
  591. TransferItems.Append(CTransferItem(pWiaItem));
  592. pWiaItem = NULL;
  593. }
  594. }
  595. }
  596. }
  597. return TransferItems.Size() ? S_OK : E_FAIL;
  598. }
  599. static int Find( const CSimpleDynamicArray<CTransferItem> &TransferItems, const CSimpleString &strFilename )
  600. {
  601. WIA_PUSH_FUNCTION((TEXT("Find( %s )"),strFilename.String()));
  602. for (int i=0;i<TransferItems.Size();i++)
  603. {
  604. WIA_TRACE((TEXT("Comparing %s to %s"), strFilename.String(), TransferItems[i].Filename().String()));
  605. if (strFilename == TransferItems[i].Filename())
  606. {
  607. WIA_TRACE((TEXT("Returning %d"),i));
  608. return i;
  609. }
  610. }
  611. WIA_TRACE((TEXT("Returning -1")));
  612. return -1;
  613. }
  614. HRESULT CDownloadImagesThreadMessage::ReserveTransferItemFilenames( CSimpleDynamicArray<CTransferItem> &TransferItems, LPCTSTR pszDirectory, LPCTSTR pszFilename, LPCTSTR pszNumberMask, bool bAllowUnNumberedFile, int &nPrevFileNumber )
  615. {
  616. WIA_PUSH_FUNCTION((TEXT("CDownloadImagesThreadMessage::ReserveTransferItemFilenames")));
  617. //
  618. // The maximum number of identical attachments
  619. //
  620. int c_nMaxDuplicateFile = 1000;
  621. //
  622. // Assume success
  623. //
  624. HRESULT hr = S_OK;
  625. //
  626. // We can only release the mutex if we were able to grab it.
  627. //
  628. bool bGrabbedMutex = false;
  629. //
  630. // It is not an error if we can't grab the mutex here
  631. //
  632. if (m_hFilenameCreationMutex && WiaUiUtil::MsgWaitForSingleObject(m_hFilenameCreationMutex,2000))
  633. {
  634. bGrabbedMutex = true;
  635. }
  636. //
  637. // Get the root filename
  638. //
  639. TCHAR szFullPathname[MAX_PATH*2] = TEXT("");
  640. int nFileNumber = NumberedFileName::GenerateLowestAvailableNumberedFileName( 0, szFullPathname, pszDirectory, pszFilename, pszNumberMask, TEXT(""), bAllowUnNumberedFile, nPrevFileNumber );
  641. WIA_TRACE((TEXT("nFileNumber = %d"),nFileNumber));
  642. //
  643. // Make sure we got a valid file number
  644. //
  645. if (nFileNumber >= 0)
  646. {
  647. //
  648. // Now loop through the transfer items for this item and create a unique filename for each
  649. //
  650. for (int nCurrTransferItem=0;nCurrTransferItem<TransferItems.Size();nCurrTransferItem++)
  651. {
  652. CSimpleString strFilename = CSimpleString(szFullPathname);
  653. CSimpleString strExtension = CWiaFileFormat::GetExtension(TransferItems[nCurrTransferItem].OutputFormat(),TransferItems[nCurrTransferItem].MediaType(),TransferItems[nCurrTransferItem].WiaItem() );
  654. //
  655. // Now we are going to make sure there are no existing files with the same name
  656. // in this transfer group. This could be caused by having multiple attachments of the same
  657. // type. So we are going to loop until we find a filename that is unused. The first file
  658. // will be named like this:
  659. //
  660. // File NNN.ext
  661. //
  662. // Subsequent files will be named like this:
  663. //
  664. // File NNN-X.ext
  665. // File NNN-Y.ext
  666. // File NNN-Z.ext
  667. // ...
  668. //
  669. bool bFoundUniqueFile = false;
  670. for (int nCurrDuplicateCheckIndex=1;nCurrDuplicateCheckIndex<c_nMaxDuplicateFile && !bFoundUniqueFile;nCurrDuplicateCheckIndex++)
  671. {
  672. //
  673. // Append the extension, if there is one
  674. //
  675. if (strExtension.Length())
  676. {
  677. strFilename += TEXT(".");
  678. strFilename += strExtension;
  679. }
  680. //
  681. // If this filename exists in the transfer items list, append the new suffix, and remain in the loop.
  682. //
  683. WIA_TRACE((TEXT("Calling Find on %s"), strFilename.String()));
  684. if (Find(TransferItems,strFilename) >= 0)
  685. {
  686. strFilename = szFullPathname;
  687. strFilename += CSimpleString().Format(IDS_DUPLICATE_FILENAME_MASK,g_hInstance,nCurrDuplicateCheckIndex);
  688. }
  689. //
  690. // Otherwise, we are done.
  691. //
  692. else
  693. {
  694. bFoundUniqueFile = true;
  695. }
  696. }
  697. //
  698. // Make sure we found a unique filename for this set of files
  699. //
  700. WIA_TRACE((TEXT("strFilename = %s"), strFilename.String()));
  701. if (bFoundUniqueFile && strFilename.Length())
  702. {
  703. TransferItems[nCurrTransferItem].Filename(strFilename);
  704. hr = TransferItems[nCurrTransferItem].OpenPlaceholderFile();
  705. if (FAILED(hr))
  706. {
  707. break;
  708. }
  709. }
  710. //
  711. // If we didn't find a valid name, exit the loop and set the return value to an error
  712. //
  713. else
  714. {
  715. hr = E_FAIL;
  716. break;
  717. }
  718. }
  719. //
  720. // Save this number so the next search starts here
  721. //
  722. nPrevFileNumber = nFileNumber;
  723. }
  724. else
  725. {
  726. WIA_ERROR((TEXT("NumberedFileName::GenerateLowestAvailableNumberedFileName returned %d"), nFileNumber ));
  727. hr = E_FAIL;
  728. }
  729. //
  730. // If we grabbed the mutex, release it
  731. //
  732. if (bGrabbedMutex)
  733. {
  734. ReleaseMutex(m_hFilenameCreationMutex);
  735. }
  736. WIA_CHECK_HR(hr,"CDownloadImagesThreadMessage::ReserveTransferItemFilenames");
  737. return hr;
  738. }
  739. BOOL CDownloadImagesThreadMessage::GetCancelledState()
  740. {
  741. BOOL bResult = FALSE;
  742. //
  743. // First, wait until we are not paused
  744. //
  745. if (m_hPauseDownloadEvent)
  746. {
  747. WiaUiUtil::MsgWaitForSingleObject(m_hPauseDownloadEvent,INFINITE);
  748. }
  749. //
  750. // Then check to see if we have been cancelled
  751. //
  752. if (m_hCancelDownloadEvent && WAIT_TIMEOUT!=WaitForSingleObject(m_hCancelDownloadEvent,0))
  753. {
  754. bResult = TRUE;
  755. }
  756. return bResult;
  757. }
  758. static void CloseAndDeletePlaceholderFiles(CSimpleDynamicArray<CTransferItem> &TransferItems)
  759. {
  760. for (int nCurrTransferItem=0;nCurrTransferItem<TransferItems.Size();nCurrTransferItem++)
  761. {
  762. if (TransferItems[nCurrTransferItem].Filename().Length())
  763. {
  764. TransferItems[nCurrTransferItem].DeleteFile();
  765. }
  766. }
  767. }
  768. static void SnapExtentToRotatableSize( IUnknown *pUnknown, const GUID &guidFormat )
  769. {
  770. WIA_PUSH_FUNCTION((TEXT("SnapExtentToRotatableSize")));
  771. //
  772. // Make sure we have a valid pointer
  773. //
  774. if (!pUnknown)
  775. {
  776. WIA_TRACE((TEXT("Invalid pointer")));
  777. return;
  778. }
  779. //
  780. // Make sure we have a JPEG file.
  781. //
  782. if (WiaImgFmt_JPEG != guidFormat)
  783. {
  784. return;
  785. }
  786. //
  787. // Make sure we can read the access flags
  788. //
  789. ULONG nHorizontalAccessFlags=0, nVerticalAccessFlags=0;
  790. if (!PropStorageHelpers::GetPropertyAccessFlags( pUnknown, WIA_IPS_XEXTENT, nHorizontalAccessFlags ) ||
  791. !PropStorageHelpers::GetPropertyAccessFlags( pUnknown, WIA_IPS_YEXTENT, nVerticalAccessFlags ))
  792. {
  793. WIA_TRACE((TEXT("Unable to read access flags")));
  794. return;
  795. }
  796. //
  797. // Make sure we have read/write access to the extent properties
  798. //
  799. if ((WIA_PROP_RW & nHorizontalAccessFlags)==0 || (WIA_PROP_RW & nVerticalAccessFlags)==0)
  800. {
  801. WIA_TRACE((TEXT("Invalid access flags")));
  802. return;
  803. }
  804. //
  805. // Get the ranges
  806. //
  807. PropStorageHelpers::CPropertyRange HorizontalRange, VerticalRange;
  808. if (!PropStorageHelpers::GetPropertyRange( pUnknown, WIA_IPS_XEXTENT, HorizontalRange ) ||
  809. !PropStorageHelpers::GetPropertyRange( pUnknown, WIA_IPS_YEXTENT, VerticalRange ))
  810. {
  811. WIA_TRACE((TEXT("Unable to read ranges")));
  812. return;
  813. }
  814. //
  815. // Make sure they are valid ranges. We aren't going to mess with it if it doesn't have a step value of 1
  816. //
  817. if (!HorizontalRange.nMax || HorizontalRange.nStep != 1 || !VerticalRange.nMax || VerticalRange.nStep != 1)
  818. {
  819. WIA_TRACE((TEXT("Invalid ranges")));
  820. return;
  821. }
  822. //
  823. // Get the current values
  824. //
  825. LONG nHorizontalExt=0, nVerticalExt=0;
  826. if (!PropStorageHelpers::GetProperty( pUnknown, WIA_IPS_XEXTENT, nHorizontalExt ) ||
  827. !PropStorageHelpers::GetProperty( pUnknown, WIA_IPS_YEXTENT, nVerticalExt ))
  828. {
  829. WIA_TRACE((TEXT("Can't read current extents")));
  830. return;
  831. }
  832. //
  833. // Round to the nearest 8, ensuring we don't go over the maximum extent (which is often not a multiple of 16, but oh well)
  834. //
  835. PropStorageHelpers::SetProperty( pUnknown, WIA_IPS_XEXTENT, WiaUiUtil::Min( WiaUiUtil::Align( nHorizontalExt, 16 ), HorizontalRange.nMax ) );
  836. PropStorageHelpers::SetProperty( pUnknown, WIA_IPS_YEXTENT, WiaUiUtil::Min( WiaUiUtil::Align( nVerticalExt, 16 ), VerticalRange.nMax ) );
  837. }
  838. static void UpdateFolderTime( LPCTSTR pszFolder )
  839. {
  840. if (pszFolder && lstrlen(pszFolder))
  841. {
  842. FILETIME ftCurrent = {0};
  843. GetSystemTimeAsFileTime(&ftCurrent);
  844. //
  845. // Private flag 0x100 lets us open a directory in write access
  846. //
  847. HANDLE hFolder = CreateFile( pszFolder, GENERIC_READ | 0x100, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
  848. if (INVALID_HANDLE_VALUE != hFolder)
  849. {
  850. SetFileTime( hFolder, NULL, NULL, &ftCurrent );
  851. CloseHandle( hFolder );
  852. }
  853. }
  854. }
  855. static bool FileExistsAndContainsData( LPCTSTR pszFileName )
  856. {
  857. bool bResult = false;
  858. //
  859. // Make sure we have a filename
  860. //
  861. if (pszFileName && lstrlen(pszFileName))
  862. {
  863. //
  864. // Make sure the file exists
  865. //
  866. if (NumberedFileName::DoesFileExist(pszFileName))
  867. {
  868. //
  869. // Attempt to open the file
  870. //
  871. HANDLE hFile = CreateFile( pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  872. if (INVALID_HANDLE_VALUE != hFile)
  873. {
  874. //
  875. // Get the file size and make sure we didn't have an error
  876. //
  877. ULARGE_INTEGER nFileSize = {0};
  878. nFileSize.LowPart = GetFileSize( hFile, &nFileSize.HighPart );
  879. if (nFileSize.LowPart != INVALID_FILE_SIZE && GetLastError() == NO_ERROR)
  880. {
  881. if (nFileSize.QuadPart != 0)
  882. {
  883. //
  884. // Success
  885. //
  886. bResult = true;
  887. }
  888. }
  889. CloseHandle( hFile );
  890. }
  891. }
  892. }
  893. return bResult;
  894. }
  895. HRESULT CDownloadImagesThreadMessage::Download(void)
  896. {
  897. WIA_PUSH_FUNCTION((TEXT("CDownloadImagesThreadMessage::Download")));
  898. CDownloadedFileInformationList DownloadedFileInformationList;
  899. //
  900. // Will be set to true if the user cancels
  901. //
  902. bool bCancelled = false;
  903. //
  904. // Will be set to true if some error prevents us from continuing
  905. //
  906. bool bStopTransferring = false;
  907. //
  908. // Tell the notification window we are going to start downloading images
  909. //
  910. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::BeginDownloadAllMessage( m_Cookies.Size() ) );
  911. //
  912. // We will sometimes have more error information than we can fit in an HRESULT
  913. //
  914. CSimpleString strExtendedErrorInformation = TEXT("");
  915. //
  916. // Get an instance of the GIT
  917. //
  918. CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
  919. HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (VOID**)&pGlobalInterfaceTable );
  920. if (SUCCEEDED(hr))
  921. {
  922. //
  923. // Get an instance of our transfer helper classes
  924. //
  925. CComPtr<IWiaTransferHelper> pWiaTransferHelper;
  926. hr = CoCreateInstance( CLSID_WiaDefaultUi, NULL, CLSCTX_INPROC_SERVER, IID_IWiaTransferHelper, (void**)&pWiaTransferHelper );
  927. if (SUCCEEDED(hr))
  928. {
  929. //
  930. // Get an instance of our helper class for identifying supported formats
  931. //
  932. CComPtr<IWiaSupportedFormats> pWiaSupportedFormats;
  933. hr = pWiaTransferHelper->QueryInterface( IID_IWiaSupportedFormats, (void**)&pWiaSupportedFormats );
  934. if (SUCCEEDED(hr))
  935. {
  936. //
  937. // We (this) are an instance of the callback class. Get an interface pointer to it.
  938. //
  939. CComPtr<IWiaDataCallback> pWiaDataCallback;
  940. hr = this->QueryInterface( IID_IWiaDataCallback, (void**)&pWiaDataCallback );
  941. if (SUCCEEDED(hr))
  942. {
  943. //
  944. // Initialize the uniqueness list
  945. //
  946. CFileUniquenessList FileUniquenessList( m_strDirectory );
  947. //
  948. // Skip all download errors?
  949. //
  950. bool bSkipAllDownloadErrors = false;
  951. //
  952. // If the most recent error was skipped, set this to true to ensure
  953. // we don't pass back an error on the last image
  954. //
  955. bool bLastErrorSkipped = false;
  956. //
  957. // Save all or delete all duplicates?
  958. //
  959. int nPersistentDuplicateResult = 0;
  960. //
  961. // Save the previous file number, so we don't have to search the whole range of files
  962. // to find an open section
  963. //
  964. int nPrevFileNumber = NumberedFileName::FindHighestNumberedFile( m_strDirectory, m_strFilename );
  965. //
  966. // Loop through all of the images
  967. //
  968. for ( int nCurrentImage=0; nCurrentImage<m_Cookies.Size() && !bCancelled && !bStopTransferring; nCurrentImage++ )
  969. {
  970. WIA_TRACE((TEXT("Preparing to transfer the %d'th image (Cookie %08X)"), nCurrentImage, m_Cookies[nCurrentImage] ));
  971. //
  972. // Assume we won't skip any transfer error that occurs
  973. //
  974. bLastErrorSkipped = false;
  975. //
  976. // Save the current cookie ID for the callback
  977. //
  978. m_nCurrentCookie = m_Cookies[nCurrentImage];
  979. //
  980. // If we have been cancelled, exit the loop
  981. //
  982. if (GetCancelledState())
  983. {
  984. hr = S_FALSE;
  985. bCancelled = true;
  986. break;
  987. }
  988. //
  989. // Get the IWiaItem interface pointer from the GIT
  990. //
  991. CComPtr<IWiaItem> pWiaItem;
  992. hr = pGlobalInterfaceTable->GetInterfaceFromGlobal(m_Cookies[nCurrentImage], IID_IWiaItem, (void**)&pWiaItem );
  993. if (SUCCEEDED(hr))
  994. {
  995. bool bInPageFeederMode = false;
  996. //
  997. // Ensure the image is a multiple of eight pixels in size
  998. //
  999. SnapExtentToRotatableSize(pWiaItem,m_guidFormat);
  1000. //
  1001. // Get the root item
  1002. //
  1003. CComPtr<IWiaItem> pWiaItemRoot;
  1004. if (SUCCEEDED(pWiaItem->GetRootItem(&pWiaItemRoot)))
  1005. {
  1006. LONG nPaperSource = 0;
  1007. if (PropStorageHelpers::GetProperty( pWiaItemRoot, WIA_DPS_DOCUMENT_HANDLING_SELECT, static_cast<LONG>(nPaperSource)))
  1008. {
  1009. if (nPaperSource & FEEDER)
  1010. {
  1011. bInPageFeederMode = true;
  1012. }
  1013. }
  1014. }
  1015. //
  1016. // Download the thumbnail, in case we haven't already
  1017. //
  1018. GUID guidPreferredFormat;
  1019. LONG nAccessRights;
  1020. PBYTE pBitmapData = NULL;
  1021. LONG nWidth = 0, nHeight = 0, nPictureWidth = 0, nPictureHeight = 0, nBitmapDataLength = 0;
  1022. CAnnotationType AnnotationType = AnnotationNone;
  1023. CSimpleString strDefExt;
  1024. if (SUCCEEDED(DownloadAndCreateThumbnail( pWiaItem, &pBitmapData, nWidth, nHeight, nBitmapDataLength, guidPreferredFormat, nAccessRights, nPictureWidth, nPictureHeight, AnnotationType, strDefExt )))
  1025. {
  1026. WIA_TRACE((TEXT("DownloadAndCreateThumbnail succeeded")));
  1027. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadThumbnailsThreadNotifyMessage::EndDownloadThumbnailMessage( nCurrentImage, m_Cookies[nCurrentImage], pBitmapData, nWidth, nHeight, nBitmapDataLength, guidPreferredFormat, nAccessRights, nPictureWidth, nPictureHeight, AnnotationType, strDefExt ) );
  1028. }
  1029. //
  1030. // If we are a scanner, and we are in feeder mode,
  1031. // determine whether or not the selected format is available
  1032. // in multipage format. This won't work if the requested
  1033. // format is IID_NULL, so it rules out cameras implicitly
  1034. // (since we only transfer camera items in their default
  1035. // format.
  1036. //
  1037. LONG nMediaType = TYMED_FILE;
  1038. if (m_guidFormat != IID_NULL && bInPageFeederMode)
  1039. {
  1040. //
  1041. // Initialize the supported format helper for multipage files
  1042. //
  1043. if (SUCCEEDED(pWiaSupportedFormats->Initialize( pWiaItem, TYMED_MULTIPAGE_FILE )))
  1044. {
  1045. //
  1046. // See if there are any multipage formats supported
  1047. //
  1048. LONG nFormatCount;
  1049. if (SUCCEEDED(pWiaSupportedFormats->GetFormatCount( &nFormatCount )))
  1050. {
  1051. //
  1052. // Loop through the formats looking for the requested format
  1053. //
  1054. for (LONG nCurrFormat = 0;nCurrFormat<nFormatCount;nCurrFormat++)
  1055. {
  1056. //
  1057. // Get the format
  1058. //
  1059. GUID guidCurrFormat = IID_NULL;
  1060. if (SUCCEEDED(pWiaSupportedFormats->GetFormatType(nCurrFormat,&guidCurrFormat)))
  1061. {
  1062. //
  1063. // If this is the same format, store the media type
  1064. //
  1065. if (guidCurrFormat == m_guidFormat)
  1066. {
  1067. nMediaType = TYMED_MULTIPAGE_FILE;
  1068. }
  1069. }
  1070. }
  1071. }
  1072. }
  1073. }
  1074. //
  1075. // Initialize the supported formats helper by telling it we are saving to a file or a multipage
  1076. // file
  1077. //
  1078. hr = WIA_FORCE_ERROR(FE_WIAACMGR,1,pWiaSupportedFormats->Initialize( pWiaItem, nMediaType ));
  1079. if (SUCCEEDED(hr))
  1080. {
  1081. //
  1082. // Get the default format
  1083. //
  1084. GUID guidDefaultFormat = IID_NULL;
  1085. hr = pWiaSupportedFormats->GetDefaultClipboardFileFormat( &guidDefaultFormat );
  1086. if (SUCCEEDED(hr))
  1087. {
  1088. //
  1089. // Get the output format. If the requested format is IID_NULL, we want to use the default format as the input format and output format (i.e., the preferrerd format).
  1090. //
  1091. GUID guidOutputFormat, guidInputFormat;
  1092. if (IID_NULL == m_guidFormat)
  1093. {
  1094. guidOutputFormat = guidInputFormat = guidDefaultFormat;
  1095. }
  1096. else
  1097. {
  1098. guidOutputFormat = m_guidFormat;
  1099. GetIdealInputFormat( pWiaSupportedFormats, m_guidFormat, guidInputFormat );
  1100. }
  1101. //
  1102. // Verify the rotation setting is legal. If it isn't, clear the rotation angle.
  1103. //
  1104. if (m_Rotation[nCurrentImage] && guidOutputFormat != IID_NULL && nPictureWidth && nPictureHeight && !WiaUiUtil::CanWiaImageBeSafelyRotated(guidOutputFormat,nPictureWidth,nPictureHeight))
  1105. {
  1106. m_Rotation[nCurrentImage] = 0;
  1107. }
  1108. //
  1109. // Number of pages per scan. We increment it at the end of each successful acquire.
  1110. // This way, if we get an out of paper error when we haven't scanned any pages,
  1111. // we can tell the user
  1112. //
  1113. int nPageCount = 0;
  1114. //
  1115. // We will store all of the successfully downloaded files for the following loop
  1116. // in this list.
  1117. //
  1118. // If this is a single image transfer, that will be one filename.
  1119. // If it is a multi-page transfer, it will be:
  1120. //
  1121. // (a) if the file format supports multi-page files (TIFF)--it will be one
  1122. // filename
  1123. // (b) if the file format doesn't support multi-page files (everything but TIFF)--
  1124. // it will be multiple files
  1125. //
  1126. CDownloadedFileInformationList CurrentFileInformationList;
  1127. //
  1128. // This is the loop where we keep scanning pages until either:
  1129. //
  1130. // (a) the ADF-active device returns out-of-paper or
  1131. // (b) we have retrieved one image from a non-ADF-active device
  1132. //
  1133. bool bContinueScanningPages = true;
  1134. while (bContinueScanningPages)
  1135. {
  1136. //
  1137. // Just before retrieving, let's make sure we've not been cancelled. If we are, break out of the loop
  1138. // and set the HRESULT to S_FALSE (which signifies cancel)
  1139. //
  1140. if (GetCancelledState())
  1141. {
  1142. hr = S_FALSE;
  1143. bCancelled = true;
  1144. break;
  1145. }
  1146. //
  1147. // Get the item and the list of any attached items
  1148. //
  1149. CSimpleDynamicArray<CTransferItem> TransferItems;
  1150. hr = WIA_FORCE_ERROR(FE_WIAACMGR,2,GetListOfTransferItems( pWiaItem, TransferItems ));
  1151. if (SUCCEEDED(hr))
  1152. {
  1153. //
  1154. // Set the output format of the first item (the image) to the desired output format
  1155. //
  1156. TransferItems[0].InputFormat(guidInputFormat);
  1157. TransferItems[0].OutputFormat(guidOutputFormat);
  1158. TransferItems[0].MediaType(nMediaType);
  1159. //
  1160. // Try to create the sub-directory. Don't worry about failing. We will catch any failures on the next call.
  1161. //
  1162. CAcquisitionManagerControllerWindow::RecursiveCreateDirectory(m_strDirectory);
  1163. //
  1164. // Find the correct filename, and reserve it
  1165. //
  1166. hr = WIA_FORCE_ERROR(FE_WIAACMGR,3,ReserveTransferItemFilenames( TransferItems, m_strDirectory, m_strFilename, CSimpleString(IDS_NUMBER_MASK,g_hInstance), m_Cookies.Size()==1 && !bInPageFeederMode, nPrevFileNumber ));
  1167. if (SUCCEEDED(hr))
  1168. {
  1169. //
  1170. // Loop through each item in the transfer list
  1171. //
  1172. for (int nCurrentTransferItem=0;nCurrentTransferItem<TransferItems.Size();nCurrentTransferItem++)
  1173. {
  1174. //
  1175. // Save the final filename
  1176. //
  1177. CSimpleString strFinalFilename = TransferItems[nCurrentTransferItem].Filename();
  1178. //
  1179. // Create a temporary file to hold the unrotated/unconverted image
  1180. //
  1181. CSimpleString strIntermediateFilename = WiaUiUtil::CreateTempFileName();
  1182. //
  1183. // Make sure the filenames are valid
  1184. //
  1185. if (strFinalFilename.Length() && strIntermediateFilename.Length())
  1186. {
  1187. //
  1188. // Tell the notification window we are starting to download this item
  1189. //
  1190. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::BeginDownloadImageMessage( nCurrentImage, m_Cookies[nCurrentImage], strFinalFilename ) );
  1191. //
  1192. // We are going to repeat failed images in this loop until the user cancels or skips them
  1193. //
  1194. bool bRetry = false;
  1195. do
  1196. {
  1197. //
  1198. // If this is a multi-page file transfer, set the page count to 0 (transfer all pages)
  1199. //
  1200. if (TYMED_MULTIPAGE_FILE == TransferItems[nCurrentTransferItem].MediaType())
  1201. {
  1202. //
  1203. // Get the root item and set the page count to 0
  1204. //
  1205. CComPtr<IWiaItem> pWiaItemRoot;
  1206. if (SUCCEEDED(TransferItems[nCurrentTransferItem].WiaItem()->GetRootItem(&pWiaItemRoot)))
  1207. {
  1208. PropStorageHelpers::SetProperty( pWiaItemRoot, WIA_DPS_PAGES, 0 );
  1209. }
  1210. }
  1211. else
  1212. {
  1213. //
  1214. // Get the root item and set the page count to 1
  1215. //
  1216. CComPtr<IWiaItem> pWiaItemRoot;
  1217. if (SUCCEEDED(TransferItems[nCurrentTransferItem].WiaItem()->GetRootItem(&pWiaItemRoot)))
  1218. {
  1219. PropStorageHelpers::SetProperty( pWiaItemRoot, WIA_DPS_PAGES, 1 );
  1220. }
  1221. }
  1222. //
  1223. // Turn off preview mode
  1224. //
  1225. PropStorageHelpers::SetProperty( pWiaItem, WIA_DPS_PREVIEW, WIA_FINAL_SCAN );
  1226. //
  1227. // Download the file using our helper class
  1228. //
  1229. hr = WIA_FORCE_ERROR(FE_WIAACMGR,4,pWiaTransferHelper->TransferItemFile( TransferItems[nCurrentTransferItem].WiaItem(), NotifyWindow(), WIA_TRANSFERHELPER_NOPROGRESS|WIA_TRANSFERHELPER_PRESERVEFAILEDFILE, TransferItems[nCurrentTransferItem].InputFormat(), CSimpleStringConvert::WideString(strIntermediateFilename).String(), pWiaDataCallback, TransferItems[nCurrentTransferItem].MediaType()));
  1230. //
  1231. // Check to if the download was cancelled
  1232. //
  1233. if (GetCancelledState())
  1234. {
  1235. hr = S_FALSE;
  1236. bCancelled = true;
  1237. CloseAndDeletePlaceholderFiles(TransferItems);
  1238. break;
  1239. }
  1240. //
  1241. // We handle this special return differently later on
  1242. //
  1243. if (nPageCount && WIA_ERROR_PAPER_EMPTY == hr)
  1244. {
  1245. break;
  1246. }
  1247. //
  1248. // We will not treat this as an error
  1249. //
  1250. if (WIA_ERROR_ITEM_DELETED == hr)
  1251. {
  1252. break;
  1253. }
  1254. WIA_PRINTHRESULT((hr,TEXT("pWiaTransferHelper->TransferItemFile returned")));
  1255. //
  1256. // If there was a failure, we are going to aler the user
  1257. //
  1258. if (FAILED(hr))
  1259. {
  1260. int nResult;
  1261. bool bUsableMultipageFileExists = false;
  1262. if (bInPageFeederMode)
  1263. {
  1264. if (TYMED_MULTIPAGE_FILE == TransferItems[nCurrentTransferItem].MediaType())
  1265. {
  1266. if (FileExistsAndContainsData(strIntermediateFilename))
  1267. {
  1268. bUsableMultipageFileExists = true;
  1269. }
  1270. }
  1271. }
  1272. //
  1273. // If the user wants to skip all the images with download errors, set the result to SKIP
  1274. //
  1275. if (bSkipAllDownloadErrors)
  1276. {
  1277. nResult = CMessageBoxEx::IDMBEX_SKIP;
  1278. if (bInPageFeederMode && !bUsableMultipageFileExists)
  1279. {
  1280. hr = WIA_ERROR_PAPER_EMPTY;
  1281. }
  1282. else if (bInPageFeederMode && bUsableMultipageFileExists && (WIA_ERROR_PAPER_JAM == hr || WIA_ERROR_PAPER_PROBLEM == hr))
  1283. {
  1284. hr = S_OK;
  1285. }
  1286. }
  1287. else
  1288. {
  1289. //
  1290. // Tell the notification window about the failure, and get a user decision
  1291. //
  1292. nResult = ReportDownloadError( NotifyWindow(), pWiaItem, hr, (m_Cookies.Size() != 1 || bInPageFeederMode), bInPageFeederMode, bUsableMultipageFileExists, TYMED_MULTIPAGE_FILE == TransferItems[nCurrentTransferItem].MediaType() );
  1293. }
  1294. if (CMessageBoxEx::IDMBEX_CANCEL == nResult)
  1295. {
  1296. bCancelled = true;
  1297. break;
  1298. }
  1299. else if (CMessageBoxEx::IDMBEX_SKIP == nResult)
  1300. {
  1301. bRetry = false;
  1302. bLastErrorSkipped = true;
  1303. }
  1304. else if (CMessageBoxEx::IDMBEX_SKIPALL == nResult)
  1305. {
  1306. bSkipAllDownloadErrors = true;
  1307. bRetry = false;
  1308. }
  1309. else if (CMessageBoxEx::IDMBEX_RETRY == nResult)
  1310. {
  1311. bRetry = true;
  1312. }
  1313. else
  1314. {
  1315. bRetry = false;
  1316. }
  1317. }
  1318. else
  1319. {
  1320. bRetry = false;
  1321. }
  1322. //
  1323. // If the transfer returned S_FALSE, the user chose to cancel
  1324. //
  1325. if (S_FALSE == hr)
  1326. {
  1327. bCancelled = true;
  1328. }
  1329. }
  1330. while (bRetry);
  1331. //
  1332. // Close the file so we can overwrite it or delete it
  1333. //
  1334. TransferItems[nCurrentTransferItem].ClosePlaceholderFile();
  1335. //
  1336. // We only do this if and if the user didn't cancel and it didn't fail
  1337. //
  1338. if (S_OK == hr)
  1339. {
  1340. //
  1341. // If we need to rotate, and we are on the anchor image, perform the rotation
  1342. //
  1343. if (nCurrentTransferItem==0 && m_Rotation[nCurrentImage] != 0)
  1344. {
  1345. hr = WIA_FORCE_ERROR(FE_WIAACMGR,5,m_GdiPlusHelper.Rotate( CSimpleStringConvert::WideString(strIntermediateFilename).String(), CSimpleStringConvert::WideString(strFinalFilename).String(), m_Rotation[nCurrentImage], guidOutputFormat ));
  1346. }
  1347. else if (nCurrentTransferItem==0 && guidInputFormat != guidOutputFormat)
  1348. {
  1349. //
  1350. // Else if are saving as a different file type, use the conversion filter
  1351. //
  1352. hr = WIA_FORCE_ERROR(FE_WIAACMGR,6,m_GdiPlusHelper.Convert( CSimpleStringConvert::WideString(strIntermediateFilename).String(), CSimpleStringConvert::WideString(strFinalFilename).String(), guidOutputFormat ));
  1353. }
  1354. else
  1355. {
  1356. //
  1357. // Otherwise copy/delete or move the actual file over
  1358. //
  1359. hr = WIA_FORCE_ERROR(FE_WIAACMGR,7,WiaUiUtil::MoveOrCopyFile( strIntermediateFilename, strFinalFilename ));
  1360. WIA_PRINTHRESULT((hr,TEXT("WiaUiUtil::MoveOrCopyFile returned")));
  1361. }
  1362. //
  1363. // If we hit an error here, we are going to stop transferring
  1364. //
  1365. if (FAILED(hr))
  1366. {
  1367. bStopTransferring = true;
  1368. switch (hr)
  1369. {
  1370. case HRESULT_FROM_WIN32(ERROR_DISK_FULL):
  1371. strExtendedErrorInformation.LoadString( IDS_DISKFULL, g_hInstance );
  1372. break;
  1373. default:
  1374. strExtendedErrorInformation.Format( IDS_UNABLE_TO_SAVE_FILE, g_hInstance, strFinalFilename.String() );
  1375. break;
  1376. }
  1377. }
  1378. }
  1379. //
  1380. // Save a flag that says whether or not this was a duplicate image. If it was, we don't want to delete
  1381. // it in case of an error or the user cancelling.
  1382. //
  1383. bool bDuplicateImage = false;
  1384. //
  1385. // Check to if the download was cancelled
  1386. //
  1387. if (GetCancelledState())
  1388. {
  1389. hr = S_FALSE;
  1390. bCancelled = true;
  1391. CloseAndDeletePlaceholderFiles(TransferItems);
  1392. break;
  1393. }
  1394. //
  1395. // Only check for duplicates if everything is OK AND
  1396. // we are not on page one of a multi-page scan AND
  1397. // we are on the anchor image (not an attachment).
  1398. //
  1399. // If we are on page 1 of a multipage scan, we have
  1400. // to save the first name, because we may be overwriting
  1401. // it with a multipage formatted file later. In other
  1402. // words, we may be changing the file after this point,
  1403. // which is not true in any other case.
  1404. //
  1405. if (nCurrentTransferItem==0 && TransferItems[nCurrentTransferItem].MediaType() == TYMED_FILE && S_OK == hr && !(bInPageFeederMode && !nPageCount))
  1406. {
  1407. //
  1408. // Check to see if this file has already been downloaded
  1409. //
  1410. int nIdenticalFileIndex = FileUniquenessList.FindIdenticalFile(strFinalFilename,true);
  1411. if (nIdenticalFileIndex != -1)
  1412. {
  1413. //
  1414. // Get the duplicate's name
  1415. //
  1416. CSimpleString strDuplicateName = FileUniquenessList.GetFileName(nIdenticalFileIndex);
  1417. //
  1418. // Make sure the name is not empty
  1419. //
  1420. if (strDuplicateName.Length())
  1421. {
  1422. //
  1423. // Create the message to give the user
  1424. //
  1425. CSimpleString strMessage;
  1426. strMessage.Format( IDS_DUPLICATE_FILE_WARNING, g_hInstance );
  1427. //
  1428. // Ask the user if they want to keep the new one
  1429. //
  1430. int nResult;
  1431. if (CMessageBoxEx::IDMBEX_YESTOALL == nPersistentDuplicateResult)
  1432. {
  1433. nResult = CMessageBoxEx::IDMBEX_YES;
  1434. }
  1435. else if (CMessageBoxEx::IDMBEX_NOTOALL == nPersistentDuplicateResult)
  1436. {
  1437. nResult = CMessageBoxEx::IDMBEX_NO;
  1438. }
  1439. else
  1440. {
  1441. nResult = ReportError( NotifyWindow(), strMessage, CMessageBoxEx::MBEX_YESYESTOALLNONOTOALL|CMessageBoxEx::MBEX_ICONQUESTION );
  1442. WIA_TRACE((TEXT("User's Response to \"Save Duplicate? %08X\""), nResult ));
  1443. }
  1444. //
  1445. // Save persistent responses
  1446. //
  1447. if (nResult == CMessageBoxEx::IDMBEX_YESTOALL)
  1448. {
  1449. nPersistentDuplicateResult = CMessageBoxEx::IDMBEX_YESTOALL;
  1450. nResult = CMessageBoxEx::IDMBEX_YES;
  1451. }
  1452. else if (nResult == CMessageBoxEx::IDMBEX_NOTOALL)
  1453. {
  1454. nPersistentDuplicateResult = CMessageBoxEx::IDMBEX_NOTOALL;
  1455. nResult = CMessageBoxEx::IDMBEX_NO;
  1456. }
  1457. //
  1458. // If the user doesn't want to keep new one, delete it, and save the filename
  1459. //
  1460. if (nResult == CMessageBoxEx::IDMBEX_NO)
  1461. {
  1462. DeleteFile( strFinalFilename );
  1463. strFinalFilename = strDuplicateName;
  1464. bDuplicateImage = true;
  1465. }
  1466. }
  1467. }
  1468. }
  1469. //
  1470. // If everything is *still* OK
  1471. //
  1472. if (S_OK == hr)
  1473. {
  1474. //
  1475. // Save the audio, if any
  1476. //
  1477. CSimpleString strAudioFilename;
  1478. HRESULT hResAudio = WiaUiUtil::SaveWiaItemAudio( pWiaItem, strFinalFilename, strAudioFilename );
  1479. if (SUCCEEDED(hResAudio) && strAudioFilename.Length())
  1480. {
  1481. CurrentFileInformationList.Append(CDownloadedFileInformation(strAudioFilename,false,m_Cookies[nCurrentImage],false));
  1482. }
  1483. else
  1484. {
  1485. WIA_PRINTHRESULT((hResAudio,TEXT("SaveWiaItemAudio failed!")));
  1486. }
  1487. //
  1488. // Set the file time to the item time
  1489. //
  1490. if (m_bStampTime)
  1491. {
  1492. HRESULT hResFileTime = WiaUiUtil::StampItemTimeOnFile( pWiaItem, strFinalFilename );
  1493. if (!SUCCEEDED(hResFileTime))
  1494. {
  1495. WIA_PRINTHRESULT((hResAudio,TEXT("StampItemTimeOnFile failed!")));
  1496. }
  1497. }
  1498. //
  1499. // Save the downloaded file information. Mark it "IncludeInFileCount" if it is the first image in the group.
  1500. //
  1501. CurrentFileInformationList.Append(CDownloadedFileInformation(strFinalFilename,bDuplicateImage==false,m_Cookies[nCurrentImage],nCurrentTransferItem==0));
  1502. }
  1503. else
  1504. {
  1505. //
  1506. // Clean up the final filename, in case of failure
  1507. //
  1508. if (!DeleteFile( strFinalFilename ))
  1509. {
  1510. WIA_PRINTHRESULT((MY_HRESULT_FROM_WIN32(GetLastError()),TEXT("DeleteFile(%s) failed!"), strFinalFilename.String()));
  1511. }
  1512. }
  1513. //
  1514. // Make sure the intermediate file is removed
  1515. //
  1516. if (!DeleteFile( strIntermediateFilename ))
  1517. {
  1518. WIA_PRINTHRESULT((MY_HRESULT_FROM_WIN32(GetLastError()),TEXT("DeleteFile(%s) failed!"), strIntermediateFilename.String()));
  1519. }
  1520. //
  1521. // Tell the notify window we are done with this image
  1522. //
  1523. if (hr != WIA_ERROR_PAPER_EMPTY)
  1524. {
  1525. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::EndDownloadImageMessage( nCurrentImage, m_Cookies[nCurrentImage], strFinalFilename, hr ) );
  1526. }
  1527. }
  1528. else
  1529. {
  1530. bStopTransferring = true;
  1531. hr = E_OUTOFMEMORY;
  1532. }
  1533. }
  1534. }
  1535. else
  1536. {
  1537. //
  1538. // Tell the user specifically why we couldn't create the placeholder file
  1539. //
  1540. WIA_PRINTHRESULT((hr,TEXT("Unable to create a placeholder file")));
  1541. bStopTransferring = true;
  1542. switch (hr)
  1543. {
  1544. case E_ACCESSDENIED:
  1545. strExtendedErrorInformation.LoadString( IDS_ERROR_ACCESS_DENIED, g_hInstance );
  1546. break;
  1547. }
  1548. }
  1549. }
  1550. else
  1551. {
  1552. WIA_PRINTHRESULT((hr,TEXT("Unable to create an output filename")));
  1553. bStopTransferring = true;
  1554. }
  1555. //
  1556. // Assume we will not be continuing
  1557. //
  1558. bContinueScanningPages = false;
  1559. //
  1560. // If we are out of paper, and we have one or more pages already, we are done, and there are no errors
  1561. //
  1562. if (nPageCount && WIA_ERROR_PAPER_EMPTY == hr)
  1563. {
  1564. //
  1565. // If we are doing single-page TIFF output, we can create a multi-page TIFF file
  1566. //
  1567. if (Gdiplus::ImageFormatTIFF == guidOutputFormat && TYMED_FILE == nMediaType)
  1568. {
  1569. //
  1570. // Get the list of all files we are going to concatenate
  1571. //
  1572. CSimpleDynamicArray<CSimpleStringWide> AllFiles;
  1573. if (SUCCEEDED(CurrentFileInformationList.GetAllFiles(AllFiles)) && AllFiles.Size())
  1574. {
  1575. //
  1576. // Create a temporary filename to save the images to, so we don't overwrite the original
  1577. //
  1578. CSimpleStringWide strwTempOutputFilename = CSimpleStringConvert::WideString(WiaUiUtil::CreateTempFileName(0));
  1579. if (strwTempOutputFilename.Length())
  1580. {
  1581. //
  1582. // Save the images as a multi-page TIFF file
  1583. //
  1584. if (SUCCEEDED(m_GdiPlusHelper.SaveMultipleImagesAsMultiPage( AllFiles, strwTempOutputFilename, Gdiplus::ImageFormatTIFF )))
  1585. {
  1586. //
  1587. // Save the first entry in the current list
  1588. //
  1589. CDownloadedFileInformation MultipageOutputFilename = CurrentFileInformationList[0];
  1590. //
  1591. // Mark the first entry as non-deletable
  1592. //
  1593. CurrentFileInformationList[0].DeleteOnError(false);
  1594. //
  1595. // Try to move the file from the temp folder to the final destination
  1596. //
  1597. if (SUCCEEDED(WiaUiUtil::MoveOrCopyFile( CSimpleStringConvert::NaturalString(strwTempOutputFilename), CurrentFileInformationList[0].Filename())))
  1598. {
  1599. //
  1600. // Delete all of the files (they are now part of the multi-page TIFF
  1601. //
  1602. CurrentFileInformationList.DeleteAllFiles();
  1603. //
  1604. // Destroy the list
  1605. //
  1606. CurrentFileInformationList.Destroy();
  1607. //
  1608. // Add the saved first image back to the list
  1609. //
  1610. CurrentFileInformationList.Append(MultipageOutputFilename);
  1611. }
  1612. else
  1613. {
  1614. //
  1615. // If we can't move the file, we have to delete it, to make sure we don't leave
  1616. // abandoned files laying around
  1617. //
  1618. DeleteFile( CSimpleStringConvert::NaturalString(strwTempOutputFilename) );
  1619. }
  1620. }
  1621. }
  1622. }
  1623. }
  1624. //
  1625. // WIA_ERROR_PAPER_EMPTY is not an error in this context, so clear it
  1626. //
  1627. hr = S_OK;
  1628. }
  1629. else if (hr == S_OK)
  1630. {
  1631. //
  1632. // if we are in page feeder mode, we should continue scanning since we didn't get any errors
  1633. //
  1634. if (bInPageFeederMode && TYMED_FILE == nMediaType)
  1635. {
  1636. bContinueScanningPages = true;
  1637. }
  1638. //
  1639. // One more page transferred
  1640. //
  1641. nPageCount++;
  1642. }
  1643. } // End while loop
  1644. //
  1645. // Add all of the successfully transferred files to the complete file list
  1646. //
  1647. DownloadedFileInformationList.Append(CurrentFileInformationList);
  1648. }
  1649. else
  1650. {
  1651. WIA_PRINTHRESULT((hr,TEXT("pWiaSupportedFormats->GetDefaultClipboardFileFormat() failed")));
  1652. bStopTransferring = true;
  1653. }
  1654. }
  1655. else
  1656. {
  1657. WIA_PRINTHRESULT((hr,TEXT("pWiaSupportedFormats->Initialize() failed")));
  1658. bStopTransferring = true;
  1659. }
  1660. }
  1661. else
  1662. {
  1663. WIA_PRINTHRESULT((hr,TEXT("Unable to retrieve interface %08X from the global interface table"),m_Cookies[nCurrentImage]));
  1664. bStopTransferring = true;
  1665. }
  1666. //
  1667. // Do this at the end of the loop, so we can pick up the item cookie it failed on
  1668. // This is only for handling errors specially
  1669. //
  1670. if (FAILED(hr))
  1671. {
  1672. //
  1673. // Make sure we send a message to the UI to alert it to errors, so it can update progress.
  1674. //
  1675. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::EndDownloadImageMessage( nCurrentImage, m_Cookies[nCurrentImage], TEXT(""), hr ) );
  1676. } // end if (FAILED)
  1677. } // end for
  1678. //
  1679. // If there was a download error, but the user chose to suppress these errors
  1680. // AND there were some files downloaded, don't return an error.
  1681. //
  1682. if (FAILED(hr) && bLastErrorSkipped && DownloadedFileInformationList.Size())
  1683. {
  1684. hr = S_OK;
  1685. }
  1686. }
  1687. else
  1688. {
  1689. WIA_PRINTHRESULT((hr,TEXT("QueryInterface failed on IID_IWiaDataCallback")));
  1690. }
  1691. }
  1692. else
  1693. {
  1694. WIA_PRINTHRESULT((hr,TEXT("QueryInterface failed on IID_IWiaSupportedFormats")));
  1695. }
  1696. }
  1697. else
  1698. {
  1699. WIA_PRINTHRESULT((hr,TEXT("Unable to create the transfer helper class")));
  1700. }
  1701. }
  1702. else
  1703. {
  1704. WIA_PRINTHRESULT((hr,TEXT("Unable to create the global interface table")));
  1705. }
  1706. //
  1707. // If the user cancelled, delete all the files we downloaded
  1708. //
  1709. if (FAILED(hr) || bCancelled)
  1710. {
  1711. DownloadedFileInformationList.DeleteAllFiles();
  1712. }
  1713. //
  1714. // Update the folder time, to cause the thumbnail to regenerate
  1715. //
  1716. if (SUCCEEDED(hr))
  1717. {
  1718. UpdateFolderTime( m_strDirectory );
  1719. }
  1720. //
  1721. // Print the final result to the debugger
  1722. //
  1723. WIA_PRINTHRESULT((hr,TEXT("This is the result of downloading all of the images: %s"),strExtendedErrorInformation.String()));
  1724. //
  1725. // Tell the notification window we are done downloading images
  1726. //
  1727. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::EndDownloadAllMessage( hr, strExtendedErrorInformation, &DownloadedFileInformationList ) );
  1728. return S_OK;
  1729. }
  1730. CSimpleString CDownloadImagesThreadMessage::GetDateString(void)
  1731. {
  1732. SYSTEMTIME LocalTime = {0};
  1733. GetLocalTime(&LocalTime);
  1734. TCHAR szDate[MAX_PATH] = {0};
  1735. if (GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &LocalTime, NULL, szDate, ARRAYSIZE(szDate)))
  1736. {
  1737. return CSimpleString().Format( IDS_UPLOADED_STRING, g_hInstance, szDate );
  1738. }
  1739. return TEXT("");
  1740. }
  1741. STDMETHODIMP CDownloadImagesThreadMessage::QueryInterface( REFIID riid, LPVOID *ppvObject )
  1742. {
  1743. WIA_PUSHFUNCTION(TEXT("CWiaDefaultUI::QueryInterface"));
  1744. if (IsEqualIID( riid, IID_IUnknown ))
  1745. {
  1746. *ppvObject = static_cast<IWiaDataCallback*>(this);
  1747. }
  1748. else if (IsEqualIID( riid, IID_IWiaDataCallback ))
  1749. {
  1750. *ppvObject = static_cast<IWiaDataCallback*>(this);
  1751. }
  1752. else
  1753. {
  1754. *ppvObject = NULL;
  1755. return(E_NOINTERFACE);
  1756. }
  1757. reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
  1758. return(S_OK);
  1759. }
  1760. STDMETHODIMP_(ULONG) CDownloadImagesThreadMessage::AddRef(void)
  1761. {
  1762. return 1;
  1763. }
  1764. STDMETHODIMP_(ULONG) CDownloadImagesThreadMessage::Release(void)
  1765. {
  1766. return 1;
  1767. }
  1768. STDMETHODIMP CDownloadImagesThreadMessage::BandedDataCallback(
  1769. LONG lReason,
  1770. LONG lStatus,
  1771. LONG lPercentComplete,
  1772. LONG lOffset,
  1773. LONG lLength,
  1774. LONG lReserved,
  1775. LONG lResLength,
  1776. PBYTE pbBuffer )
  1777. {
  1778. WIA_PUSH_FUNCTION(( TEXT("CDownloadImagesThreadMessage::BandedDataCallback(%X,%X,%d,%X,%X,%X,%X,%X"), lReason, lStatus, lPercentComplete, lOffset, lLength, lReserved, lResLength, pbBuffer ));
  1779. //
  1780. // First of all, check to see if we've been cancelled
  1781. //
  1782. if (m_hCancelDownloadEvent && WAIT_TIMEOUT!=WaitForSingleObject(m_hCancelDownloadEvent,0))
  1783. {
  1784. return S_FALSE;
  1785. }
  1786. switch (lReason)
  1787. {
  1788. case IT_MSG_STATUS:
  1789. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::UpdateDownloadImageMessage( lPercentComplete ) );
  1790. break;
  1791. case IT_MSG_FILE_PREVIEW_DATA_HEADER:
  1792. //
  1793. // Get rid of the old one
  1794. //
  1795. m_MemoryDib.Destroy();
  1796. //
  1797. // Make sure we start a new one
  1798. //
  1799. m_bFirstTransfer = true;
  1800. m_nCurrentPreviewImageLine = 0;
  1801. break;
  1802. case IT_MSG_FILE_PREVIEW_DATA:
  1803. if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT)
  1804. {
  1805. if (m_bFirstTransfer)
  1806. {
  1807. //
  1808. // Assuming there is no way we could get a lLength smaller than the image header size
  1809. //
  1810. m_bFirstTransfer = false;
  1811. m_MemoryDib.Initialize( reinterpret_cast<PBITMAPINFO>(pbBuffer) );
  1812. lLength -= WiaUiUtil::GetBmiSize(reinterpret_cast<PBITMAPINFO>(pbBuffer));
  1813. lOffset += WiaUiUtil::GetBmiSize(reinterpret_cast<PBITMAPINFO>(pbBuffer));
  1814. //
  1815. // We're getting a preview image
  1816. //
  1817. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::BeginPreviewMessage( m_nCurrentCookie, m_MemoryDib.Bitmap()) );
  1818. }
  1819. //
  1820. // Make sure we are dealing with valid data
  1821. //
  1822. if (m_MemoryDib.IsValid())
  1823. {
  1824. //
  1825. // This should be an even number of lines. If it isn't, things are going to get messed up
  1826. //
  1827. int nLineCount = lLength / m_MemoryDib.GetUnpackedWidthInBytes();
  1828. //
  1829. // Scroll the data up if we are out of room
  1830. //
  1831. WIA_TRACE((TEXT("nLineCount = %d, nCurrentLine = %d, m_MemoryDib.GetHeight() = %d"), nLineCount, m_nCurrentPreviewImageLine, m_MemoryDib.GetHeight() ));
  1832. if (nLineCount + m_nCurrentPreviewImageLine > m_MemoryDib.GetHeight())
  1833. {
  1834. int nNumberOfLinesToScroll = (nLineCount + m_nCurrentPreviewImageLine) - m_MemoryDib.GetHeight();
  1835. m_MemoryDib.ScrollDataUp(nNumberOfLinesToScroll);
  1836. m_nCurrentPreviewImageLine = m_MemoryDib.GetHeight() - nLineCount;
  1837. }
  1838. WIA_TRACE((TEXT("nCurrentLine: %d, nLineCount: %d"), m_nCurrentPreviewImageLine, nLineCount ));
  1839. //
  1840. // Copy the data to our bitmap
  1841. //
  1842. m_MemoryDib.SetUnpackedData( pbBuffer, m_nCurrentPreviewImageLine, nLineCount );
  1843. //
  1844. // This is where we'll start next time
  1845. //
  1846. m_nCurrentPreviewImageLine += nLineCount;
  1847. //
  1848. // Tell the UI we have an update
  1849. //
  1850. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::UpdatePreviewMessage( m_nCurrentCookie, m_MemoryDib.Bitmap() ) );
  1851. //
  1852. // If this is it for this preview, tell the UI
  1853. //
  1854. if (lPercentComplete == 100)
  1855. {
  1856. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDownloadImagesThreadNotifyMessage::EndPreviewMessage( m_nCurrentCookie ) );
  1857. }
  1858. }
  1859. } // IT_STATUS_TRANSFER_TO_CLIENT
  1860. break;
  1861. }
  1862. return S_OK;
  1863. }
  1864. // -------------------------------------------------
  1865. // CDeleteImagesThreadMessage
  1866. // -------------------------------------------------
  1867. CDeleteImagesThreadMessage::CDeleteImagesThreadMessage(
  1868. HWND hWndNotify,
  1869. const CSimpleDynamicArray<DWORD> &Cookies,
  1870. HANDLE hCancelDeleteEvent,
  1871. HANDLE hPauseDeleteEvent,
  1872. bool bSlowItDown
  1873. )
  1874. : CNotifyThreadMessage( TQ_DELETEIMAGES, hWndNotify ),
  1875. m_Cookies(Cookies),
  1876. m_hCancelDeleteEvent(NULL),
  1877. m_hPauseDeleteEvent(NULL),
  1878. m_bSlowItDown(bSlowItDown)
  1879. {
  1880. if (hCancelDeleteEvent)
  1881. {
  1882. DuplicateHandle( GetCurrentProcess(), hCancelDeleteEvent, GetCurrentProcess(), &m_hCancelDeleteEvent, 0, FALSE, DUPLICATE_SAME_ACCESS );
  1883. }
  1884. if (hPauseDeleteEvent)
  1885. {
  1886. DuplicateHandle( GetCurrentProcess(), hPauseDeleteEvent, GetCurrentProcess(), &m_hPauseDeleteEvent, 0, FALSE, DUPLICATE_SAME_ACCESS );
  1887. }
  1888. }
  1889. CDeleteImagesThreadMessage::~CDeleteImagesThreadMessage(void)
  1890. {
  1891. if (m_hCancelDeleteEvent)
  1892. {
  1893. CloseHandle(m_hCancelDeleteEvent);
  1894. m_hCancelDeleteEvent = NULL;
  1895. }
  1896. if (m_hPauseDeleteEvent)
  1897. {
  1898. CloseHandle(m_hPauseDeleteEvent);
  1899. m_hPauseDeleteEvent = NULL;
  1900. }
  1901. }
  1902. HRESULT CDeleteImagesThreadMessage::DeleteImages(void)
  1903. {
  1904. WIA_PUSH_FUNCTION((TEXT("CDeleteImagesThreadMessage::DeleteImages")));
  1905. //
  1906. // This is the result of downloading all of the images. If any errors
  1907. // occur, we will return an error. Otherwise, we will return S_OK
  1908. //
  1909. HRESULT hrFinalResult = S_OK;
  1910. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDeleteImagesThreadNotifyMessage::BeginDeleteAllMessage( m_Cookies.Size() ) );
  1911. //
  1912. // Pause a little while, so the user can read the wizard page
  1913. //
  1914. if (m_bSlowItDown)
  1915. {
  1916. Sleep(DELETE_DELAY_BEFORE);
  1917. }
  1918. //
  1919. // Get an instance of the GIT
  1920. //
  1921. CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
  1922. HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (VOID**)&pGlobalInterfaceTable );
  1923. if (SUCCEEDED(hr))
  1924. {
  1925. for (int i=0;i<m_Cookies.Size();i++)
  1926. {
  1927. //
  1928. // Tell the notification window which image we are deleting
  1929. //
  1930. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDeleteImagesThreadNotifyMessage::BeginDeleteImageMessage( i, m_Cookies[i] ) );
  1931. //
  1932. // Get the item from the GIT
  1933. //
  1934. CComPtr<IWiaItem> pWiaItem;
  1935. hr = pGlobalInterfaceTable->GetInterfaceFromGlobal(m_Cookies[i], IID_IWiaItem, (void**)&pWiaItem );
  1936. if (SUCCEEDED(hr))
  1937. {
  1938. //
  1939. // Wait forever if we are paused
  1940. //
  1941. if (m_hPauseDeleteEvent)
  1942. {
  1943. WiaUiUtil::MsgWaitForSingleObject(m_hPauseDeleteEvent,INFINITE);
  1944. }
  1945. //
  1946. // Check for a cancel
  1947. //
  1948. if (m_hCancelDeleteEvent && WAIT_OBJECT_0==WaitForSingleObject(m_hCancelDeleteEvent,0))
  1949. {
  1950. hr = hrFinalResult = S_FALSE;
  1951. break;
  1952. }
  1953. //
  1954. // Delete the item. Note that we don't consider delete errors to be fatal, so we continue
  1955. //
  1956. hr = WIA_FORCE_ERROR(FE_WIAACMGR,8,WiaUiUtil::DeleteItemAndChildren(pWiaItem));
  1957. if (S_OK != hr)
  1958. {
  1959. hrFinalResult = hr;
  1960. WIA_PRINTHRESULT((hr,TEXT("DeleteItemAndChildren failed")));
  1961. }
  1962. }
  1963. else
  1964. {
  1965. hrFinalResult = hr;
  1966. WIA_PRINTHRESULT((hr,TEXT("Unable to retrieve interface %08X from the global interface table"),m_Cookies[i]));
  1967. }
  1968. //
  1969. // Pause a little while, so the user can read the wizard page
  1970. //
  1971. if (m_bSlowItDown)
  1972. {
  1973. Sleep(DELETE_DELAY_DURING / m_Cookies.Size());
  1974. }
  1975. //
  1976. // Save any errors
  1977. //
  1978. if (FAILED(hr))
  1979. {
  1980. hrFinalResult = hr;
  1981. }
  1982. //
  1983. // If the device is disconnected, we may as well stop
  1984. //
  1985. if (WIA_ERROR_OFFLINE == hr)
  1986. {
  1987. break;
  1988. }
  1989. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDeleteImagesThreadNotifyMessage::EndDeleteImageMessage( i, m_Cookies[i], hr ) );
  1990. }
  1991. }
  1992. else
  1993. {
  1994. hrFinalResult = hr;
  1995. }
  1996. //
  1997. // Pause a little while, so the user can read the wizard page
  1998. //
  1999. if (m_bSlowItDown)
  2000. {
  2001. Sleep(DELETE_DELAY_AFTER);
  2002. }
  2003. CThreadNotificationMessage::SendMessage( NotifyWindow(), CDeleteImagesThreadNotifyMessage::EndDeleteAllMessage( hrFinalResult ) );
  2004. return S_OK;
  2005. }
  2006. // -------------------------------------------------
  2007. // CPreviewScanThreadMessage
  2008. // -------------------------------------------------
  2009. CPreviewScanThreadMessage::CPreviewScanThreadMessage(
  2010. HWND hWndNotify,
  2011. DWORD dwCookie,
  2012. HANDLE hCancelPreviewEvent
  2013. )
  2014. : CNotifyThreadMessage( TQ_SCANPREVIEW, hWndNotify ),
  2015. m_dwCookie(dwCookie),
  2016. m_bFirstTransfer(true)
  2017. {
  2018. DuplicateHandle( GetCurrentProcess(), hCancelPreviewEvent, GetCurrentProcess(), &m_hCancelPreviewEvent, 0, FALSE, DUPLICATE_SAME_ACCESS );
  2019. }
  2020. CPreviewScanThreadMessage::~CPreviewScanThreadMessage()
  2021. {
  2022. if (m_hCancelPreviewEvent)
  2023. {
  2024. CloseHandle(m_hCancelPreviewEvent);
  2025. m_hCancelPreviewEvent = NULL;
  2026. }
  2027. }
  2028. //
  2029. // Calculate the maximum scan size using the give DPI
  2030. //
  2031. static bool GetFullResolution( IWiaItem *pWiaItem, LONG nResX, LONG nResY, LONG &nExtX, LONG &nExtY )
  2032. {
  2033. WIA_PUSHFUNCTION(TEXT("CScannerItem::GetFullResolution"));
  2034. CComPtr<IWiaItem> pRootItem;
  2035. if (SUCCEEDED(pWiaItem->GetRootItem(&pRootItem)) && pRootItem)
  2036. {
  2037. LONG lBedSizeX, lBedSizeY, nPaperSource;
  2038. if (PropStorageHelpers::GetProperty( pRootItem, WIA_DPS_DOCUMENT_HANDLING_SELECT, static_cast<LONG>(nPaperSource)) && nPaperSource & FEEDER)
  2039. {
  2040. if (PropStorageHelpers::GetProperty( pRootItem, WIA_DPS_HORIZONTAL_SHEET_FEED_SIZE, lBedSizeX ) &&
  2041. PropStorageHelpers::GetProperty( pRootItem, WIA_DPS_VERTICAL_SHEET_FEED_SIZE, lBedSizeY ))
  2042. {
  2043. nExtX = WiaUiUtil::MulDivNoRound( nResX, lBedSizeX, 1000 );
  2044. nExtY = WiaUiUtil::MulDivNoRound( nResY, lBedSizeY, 1000 );
  2045. return(true);
  2046. }
  2047. }
  2048. if (PropStorageHelpers::GetProperty( pRootItem, WIA_DPS_HORIZONTAL_BED_SIZE, lBedSizeX ) &&
  2049. PropStorageHelpers::GetProperty( pRootItem, WIA_DPS_VERTICAL_BED_SIZE, lBedSizeY ))
  2050. {
  2051. nExtX = WiaUiUtil::MulDivNoRound( nResX, lBedSizeX, 1000 );
  2052. nExtY = WiaUiUtil::MulDivNoRound( nResY, lBedSizeY, 1000 );
  2053. return(true);
  2054. }
  2055. }
  2056. return(false);
  2057. }
  2058. static bool CalculatePreviewResolution( IWiaItem *pWiaItem, LONG &nResX, LONG &nResY )
  2059. {
  2060. const LONG nDesiredResolution = 50;
  2061. PropStorageHelpers::CPropertyRange XResolutionRange, YResolutionRange;
  2062. if (PropStorageHelpers::GetPropertyRange( pWiaItem, WIA_IPS_XRES, XResolutionRange ) &&
  2063. PropStorageHelpers::GetPropertyRange( pWiaItem, WIA_IPS_YRES, YResolutionRange ))
  2064. {
  2065. nResX = WiaUiUtil::GetMinimum<LONG>( XResolutionRange.nMin, nDesiredResolution, XResolutionRange.nStep );
  2066. nResY = WiaUiUtil::GetMinimum<LONG>( YResolutionRange.nMin, nDesiredResolution, YResolutionRange.nStep );
  2067. return(true);
  2068. }
  2069. else
  2070. {
  2071. CSimpleDynamicArray<LONG> XResolutionList, YResolutionList;
  2072. if (PropStorageHelpers::GetPropertyList( pWiaItem, WIA_IPS_XRES, XResolutionList ) &&
  2073. PropStorageHelpers::GetPropertyList( pWiaItem, WIA_IPS_YRES, YResolutionList ))
  2074. {
  2075. for (int i=0;i<XResolutionList.Size();i++)
  2076. {
  2077. nResX = XResolutionList[i];
  2078. if (nResX >= nDesiredResolution)
  2079. break;
  2080. }
  2081. for (i=0;i<YResolutionList.Size();i++)
  2082. {
  2083. nResY = YResolutionList[i];
  2084. if (nResY >= nDesiredResolution)
  2085. break;
  2086. }
  2087. return(true);
  2088. }
  2089. }
  2090. return(false);
  2091. }
  2092. HRESULT CPreviewScanThreadMessage::Scan(void)
  2093. {
  2094. WIA_PUSH_FUNCTION((TEXT("CPreviewScanThreadMessage::Download")));
  2095. CThreadNotificationMessage::SendMessage( NotifyWindow(), CPreviewScanThreadNotifyMessage::BeginDownloadMessage( m_dwCookie ) );
  2096. HRESULT hr = S_OK;
  2097. CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
  2098. hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (VOID**)&pGlobalInterfaceTable );
  2099. if (SUCCEEDED(hr))
  2100. {
  2101. CComPtr<IWiaTransferHelper> pWiaTransferHelper;
  2102. hr = CoCreateInstance( CLSID_WiaDefaultUi, NULL, CLSCTX_INPROC_SERVER, IID_IWiaTransferHelper, (void**)&pWiaTransferHelper );
  2103. if (SUCCEEDED(hr))
  2104. {
  2105. CComPtr<IWiaDataCallback> pWiaDataCallback;
  2106. hr = this->QueryInterface( IID_IWiaDataCallback, (void**)&pWiaDataCallback );
  2107. if (SUCCEEDED(hr))
  2108. {
  2109. CComPtr<IWiaItem> pWiaItem;
  2110. hr = pGlobalInterfaceTable->GetInterfaceFromGlobal(m_dwCookie, IID_IWiaItem, (void**)&pWiaItem );
  2111. if (SUCCEEDED(hr))
  2112. {
  2113. LONG nResX, nResY;
  2114. if (CalculatePreviewResolution(pWiaItem,nResX,nResY))
  2115. {
  2116. LONG nExtX, nExtY;
  2117. if (GetFullResolution(pWiaItem,nResX,nResY,nExtX,nExtY))
  2118. {
  2119. CPropertyStream SavedProperties;
  2120. hr = SavedProperties.AssignFromWiaItem( pWiaItem );
  2121. if (SUCCEEDED(hr))
  2122. {
  2123. if (PropStorageHelpers::SetProperty( pWiaItem, WIA_IPS_XRES, nResX ) &&
  2124. PropStorageHelpers::SetProperty( pWiaItem, WIA_IPS_YRES, nResY ) &&
  2125. PropStorageHelpers::SetProperty( pWiaItem, WIA_IPS_XPOS, 0 ) &&
  2126. PropStorageHelpers::SetProperty( pWiaItem, WIA_IPS_YPOS, 0 ) &&
  2127. PropStorageHelpers::SetProperty( pWiaItem, WIA_IPS_XEXTENT, nExtX ) &&
  2128. PropStorageHelpers::SetProperty( pWiaItem, WIA_IPS_YEXTENT, nExtY ))
  2129. {
  2130. //
  2131. // Set the preview property. Ignore failure (it is an optional property)
  2132. //
  2133. PropStorageHelpers::SetProperty( pWiaItem, WIA_DPS_PREVIEW, 1 );
  2134. hr = pWiaTransferHelper->TransferItemBanded( pWiaItem, NotifyWindow(), WIA_TRANSFERHELPER_NOPROGRESS, WiaImgFmt_MEMORYBMP, 0, pWiaDataCallback );
  2135. }
  2136. else
  2137. {
  2138. hr = E_FAIL;
  2139. }
  2140. SavedProperties.ApplyToWiaItem( pWiaItem );
  2141. }
  2142. }
  2143. else
  2144. {
  2145. WIA_ERROR((TEXT("Unable to calculate the preview resolution size")));
  2146. hr = E_FAIL;
  2147. }
  2148. }
  2149. else
  2150. {
  2151. WIA_ERROR((TEXT("Unable to calculate the preview resolution")));
  2152. hr = E_FAIL;
  2153. }
  2154. }
  2155. else
  2156. {
  2157. WIA_PRINTHRESULT((hr,TEXT("Unable to retrieve interface %08X from the global interface table"),m_dwCookie));
  2158. }
  2159. }
  2160. else
  2161. {
  2162. WIA_PRINTHRESULT((hr,TEXT("QueryInterface failed on IID_IWiaDataCallback")));
  2163. }
  2164. }
  2165. else
  2166. {
  2167. WIA_PRINTHRESULT((hr,TEXT("Unable to create the transfer helper class")));
  2168. }
  2169. }
  2170. else
  2171. {
  2172. WIA_PRINTHRESULT((hr,TEXT("Unable to create the global interface table")));
  2173. }
  2174. if (FAILED(hr) || hr == S_FALSE)
  2175. {
  2176. m_MemoryDib.Destroy();
  2177. }
  2178. CThreadNotificationMessage::SendMessage( NotifyWindow(), CPreviewScanThreadNotifyMessage::EndDownloadMessage( m_dwCookie, m_MemoryDib.DetachBitmap(), hr ) );
  2179. return S_OK;
  2180. }
  2181. STDMETHODIMP CPreviewScanThreadMessage::QueryInterface( REFIID riid, LPVOID *ppvObject )
  2182. {
  2183. WIA_PUSHFUNCTION(TEXT("CWiaDefaultUI::QueryInterface"));
  2184. if (IsEqualIID( riid, IID_IUnknown ))
  2185. {
  2186. *ppvObject = static_cast<IWiaDataCallback*>(this);
  2187. }
  2188. else if (IsEqualIID( riid, IID_IWiaDataCallback ))
  2189. {
  2190. *ppvObject = static_cast<IWiaDataCallback*>(this);
  2191. }
  2192. else
  2193. {
  2194. *ppvObject = NULL;
  2195. return(E_NOINTERFACE);
  2196. }
  2197. reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
  2198. return(S_OK);
  2199. }
  2200. STDMETHODIMP_(ULONG) CPreviewScanThreadMessage::AddRef(void)
  2201. {
  2202. return 1;
  2203. }
  2204. STDMETHODIMP_(ULONG) CPreviewScanThreadMessage::Release(void)
  2205. {
  2206. return 1;
  2207. }
  2208. STDMETHODIMP CPreviewScanThreadMessage::BandedDataCallback(
  2209. LONG lReason,
  2210. LONG lStatus,
  2211. LONG lPercentComplete,
  2212. LONG lOffset,
  2213. LONG lLength,
  2214. LONG lReserved,
  2215. LONG lResLength,
  2216. PBYTE pbBuffer )
  2217. {
  2218. WIA_PUSH_FUNCTION(( TEXT("CPreviewScanThreadMessage::BandedDataCallback(%X,%X,%d,%X,%X,%X,%X,%X"), lReason, lStatus, lPercentComplete, lOffset, lLength, lReserved, lResLength, pbBuffer ));
  2219. if (m_hCancelPreviewEvent && WAIT_OBJECT_0==WaitForSingleObject(m_hCancelPreviewEvent,0))
  2220. {
  2221. return S_FALSE;
  2222. }
  2223. HRESULT hr = S_OK;
  2224. switch (lReason)
  2225. {
  2226. case IT_MSG_DATA_HEADER:
  2227. {
  2228. m_bFirstTransfer = true;
  2229. break;
  2230. } // IT_MSG_DATA_HEADER
  2231. case IT_MSG_DATA:
  2232. if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT)
  2233. {
  2234. if (m_bFirstTransfer)
  2235. {
  2236. //
  2237. // Assuming there is no way we could get a lLength smaller than the image header size
  2238. //
  2239. m_bFirstTransfer = false;
  2240. m_MemoryDib.Initialize( reinterpret_cast<PBITMAPINFO>(pbBuffer) );
  2241. lLength -= WiaUiUtil::GetBmiSize(reinterpret_cast<PBITMAPINFO>(pbBuffer));
  2242. lOffset += WiaUiUtil::GetBmiSize(reinterpret_cast<PBITMAPINFO>(pbBuffer));
  2243. }
  2244. if (SUCCEEDED(hr))
  2245. {
  2246. //
  2247. // Don't bother unless we have some data
  2248. //
  2249. if (lLength)
  2250. {
  2251. //
  2252. // Figure out which line we are on
  2253. //
  2254. int nCurrentLine = (lOffset - m_MemoryDib.GetHeaderLength())/m_MemoryDib.GetUnpackedWidthInBytes();
  2255. //
  2256. // This should be an even number of lines. If it isn't, things are going to get messed up
  2257. //
  2258. int nLineCount = lLength / m_MemoryDib.GetUnpackedWidthInBytes();
  2259. //
  2260. // Copy the data to our bitmap
  2261. //
  2262. m_MemoryDib.SetUnpackedData( pbBuffer, nCurrentLine, nLineCount );
  2263. //
  2264. // Tell the notification window we have some data
  2265. //
  2266. CThreadNotificationMessage::SendMessage( NotifyWindow(), CPreviewScanThreadNotifyMessage::UpdateDownloadMessage( m_dwCookie, m_MemoryDib.Bitmap() ) );
  2267. }
  2268. }
  2269. } // IT_STATUS_TRANSFER_TO_CLIENT
  2270. break;
  2271. case IT_MSG_STATUS:
  2272. {
  2273. } // IT_MSG_STATUS
  2274. break;
  2275. case IT_MSG_TERMINATION:
  2276. {
  2277. } // IT_MSG_TERMINATION
  2278. break;
  2279. default:
  2280. WIA_ERROR((TEXT("ImageDataCallback, unknown lReason: %d"), lReason ));
  2281. break;
  2282. }
  2283. return(hr);
  2284. }