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.

1679 lines
54 KiB

  1. /*-----------------------------------------------------------------------------
  2. *
  3. * File: wiaitem.cpp
  4. * Author: Samuel Clement (samclem)
  5. * Date: Tue Aug 17 17:26:17 1999
  6. *
  7. * Copyright (c) 1999 Microsoft Corporation
  8. *
  9. * Description:
  10. * Contains the implementation of the CWiaItem object. This object provides
  11. * the automation interface to the IWiaItem interface.
  12. *
  13. * History:
  14. * 17 Aug 1999: Created.
  15. * 27 Aug 1999: Added the tagWiaDataTrans (samclem)
  16. * 10 Sep 1999: Moved thumbnail transfer to a static method. Hooked
  17. * thumbnails up to CWiaProtocol for transfer, no more
  18. * temporary files. (samclem)
  19. *----------------------------------------------------------------------------*/
  20. #include "stdafx.h"
  21. HRESULT VerticalFlip(BYTE *pBuf);
  22. DeclareTag( tagWiaDataTrans, "!WiaTrans", "Display output during the transfer" );
  23. //const WORD k_wBitmapType = static_cast<WORD>('BM');
  24. const WORD k_wBitmapType = 0x4d42; // "BM"
  25. /*-----------------------------------------------------------------------------
  26. * CWiaItem::CWiaItem
  27. *
  28. * Create a new wrapper around an IWiaItem for a device. This doesn't do
  29. * anything besides initialize the variables to a known state.
  30. *--(samclem)-----------------------------------------------------------------*/
  31. CWiaItem::CWiaItem()
  32. : m_pWiaItem( NULL ), m_pWiaStorage( NULL ), m_dwThumbWidth( -1 ), m_dwThumbHeight( -1 ),
  33. m_bstrThumbUrl( NULL ), m_dwItemWidth( -1), m_dwItemHeight( -1 )
  34. {
  35. TRACK_OBJECT( "CWiaItem" );
  36. }
  37. /*-----------------------------------------------------------------------------
  38. * CWiaItem::FinalRelease
  39. *
  40. * Called while destroying the object, releases all the interfaces that this
  41. * object is attached to.
  42. *--(samclem)-----------------------------------------------------------------*/
  43. STDMETHODIMP_(void)
  44. CWiaItem::FinalRelease()
  45. {
  46. if ( m_pWiaItem )
  47. m_pWiaItem->Release();
  48. m_pWiaItem = NULL;
  49. if ( m_pWiaStorage )
  50. m_pWiaStorage->Release();
  51. m_pWiaStorage = NULL;
  52. if ( m_bstrThumbUrl )
  53. SysFreeString( m_bstrThumbUrl );
  54. m_bstrThumbUrl = NULL;
  55. }
  56. /*-----------------------------------------------------------------------------
  57. * CWiaItem::CacheProperties
  58. *
  59. * This is called to handle caching the important (frequently used)
  60. * properties so we don't have to talk to the camera when we want these.
  61. *
  62. * pWiaStg: the property storage to read the properties from
  63. *--(samclem)-----------------------------------------------------------------*/
  64. HRESULT CWiaItem::CacheProperties( IWiaPropertyStorage* pWiaStg )
  65. {
  66. HRESULT hr;
  67. enum
  68. {
  69. PropThumbWidth = 0,
  70. PropThumbHeight = 1,
  71. PropItemWidth = 2,
  72. PropItemHeight = 3,
  73. PropCount = 4,
  74. };
  75. PROPSPEC aspec[PropCount] = {
  76. { PRSPEC_PROPID, WIA_IPC_THUMB_WIDTH },
  77. { PRSPEC_PROPID, WIA_IPC_THUMB_HEIGHT },
  78. { PRSPEC_PROPID, WIA_IPA_PIXELS_PER_LINE },
  79. { PRSPEC_PROPID, WIA_IPA_NUMBER_OF_LINES },
  80. };
  81. PROPVARIANT avaProps[PropCount];
  82. hr = THR( pWiaStg->ReadMultiple( PropCount, aspec, avaProps ) );
  83. if ( FAILED( hr ) )
  84. return hr;
  85. // store the values away if they were valid
  86. if ( avaProps[PropThumbWidth].vt != VT_EMPTY )
  87. m_dwThumbWidth = avaProps[PropThumbWidth].lVal;
  88. if ( avaProps[PropThumbHeight].vt != VT_EMPTY )
  89. m_dwThumbHeight = avaProps[PropThumbHeight].lVal;
  90. if ( avaProps[PropItemWidth].vt != VT_EMPTY )
  91. m_dwItemWidth = avaProps[PropItemWidth].lVal;
  92. if ( avaProps[PropItemHeight].vt != VT_EMPTY )
  93. m_dwItemHeight = avaProps[PropItemHeight].lVal;
  94. return S_OK;
  95. }
  96. /*-----------------------------------------------------------------------------
  97. * CWiaItem::AttachTo
  98. *
  99. * Called to attach this object to an IWiaItem that represents the device
  100. *
  101. * pWia: The CWia object that is the root of all evils, used to
  102. * handle callbacks and collection cache.
  103. * pWiaItem: the device item to attach this wrapper to.
  104. *--(samclem)-----------------------------------------------------------------*/
  105. HRESULT
  106. CWiaItem::AttachTo( CWia* pWia, IWiaItem* pWiaItem )
  107. {
  108. Assert( NULL != pWiaItem );
  109. Assert( NULL == m_pWiaItem );
  110. HRESULT hr;
  111. IWiaPropertyStorage* pWiaStg = NULL;
  112. hr = THR( pWiaItem->QueryInterface( IID_IWiaPropertyStorage,
  113. reinterpret_cast<void**>(&pWiaStg) ) );
  114. if ( FAILED( hr ) )
  115. goto Cleanup;
  116. hr = THR( CacheProperties( pWiaStg ) );
  117. if ( FAILED( hr ) )
  118. goto Cleanup;
  119. // set our pointers
  120. m_pWiaItem = pWiaItem;
  121. m_pWiaItem->AddRef();
  122. m_pWiaStorage = pWiaStg;
  123. m_pWiaStorage->AddRef();
  124. // don't addref this, otherwise we have a circular referance
  125. // problem. We will keep a weak referance.
  126. m_pWia = pWia;
  127. Cleanup:
  128. if ( pWiaStg )
  129. pWiaStg->Release();
  130. return hr;
  131. }
  132. /*-----------------------------------------------------------------------------
  133. * CWiaItem::GetItemsFromUI [IWiaDispatchItem]
  134. *
  135. * This handles showing the Data Acquisition U.I. Note that this is only valid
  136. * off a root item.
  137. *
  138. *
  139. * dwFlags: flags specifying UI operations.
  140. * dwIntent: the intent value specifying attributes such as Color etc.
  141. * ppCollection: the return collection of Wia Items
  142. *--(samclem)-----------------------------------------------------------------*/
  143. STDMETHODIMP
  144. CWiaItem::GetItemsFromUI( WiaFlag Flags, WiaIntent Intent, ICollection** ppCollection )
  145. {
  146. HRESULT hr = S_OK;
  147. LONG lCount = 0;
  148. IWiaItem **ppIWiaItem = NULL;
  149. CComObject<CCollection>* pCol = NULL;
  150. IDispatch** rgpDispatch = NULL;
  151. LONG lItemType = 0;
  152. if ( NULL == ppCollection )
  153. return E_POINTER;
  154. // first we want the item type of this item
  155. hr = THR( m_pWiaItem->GetItemType( &lItemType ) );
  156. if ( FAILED( hr ) )
  157. goto Cleanup;
  158. if ( !(lItemType & WiaItemTypeRoot) )
  159. {
  160. hr = E_INVALIDARG;
  161. goto Cleanup;
  162. }
  163. DWORD dwFlags = (DWORD)Flags;
  164. DWORD dwIntent = (DWORD)Intent;
  165. // Show the get image dialog.
  166. hr = m_pWiaItem->DeviceDlg((HWND)NULL,
  167. dwFlags,
  168. dwIntent,
  169. &lCount,
  170. &ppIWiaItem);
  171. if (SUCCEEDED(hr))
  172. {
  173. // Check if user cancelled
  174. if ( S_FALSE == hr )
  175. {
  176. goto Cleanup;
  177. }
  178. // Put returned items into a collection
  179. // allocate our arrays, zeroing them if we are successful.
  180. // Note: we check for failure after each one
  181. if ( lCount > 0 )
  182. {
  183. hr = E_OUTOFMEMORY;
  184. rgpDispatch = reinterpret_cast<IDispatch**>
  185. (CoTaskMemAlloc( sizeof( IDispatch* ) * lCount ) );
  186. if ( rgpDispatch )
  187. ZeroMemory( rgpDispatch, sizeof( IDispatch* ) * lCount );
  188. else
  189. goto Cleanup;
  190. // we have all our items, so we simply need to iterate
  191. // over them and create the CWiaItem to attach to them
  192. for ( LONG i = 0; i < lCount; i++ )
  193. {
  194. if ( !(ppIWiaItem[i]) )
  195. continue;
  196. CComObject<CWiaItem>* pItem;
  197. hr = THR( CComObject<CWiaItem>::CreateInstance( &pItem ) );
  198. if ( FAILED( hr ) )
  199. goto Cleanup;
  200. hr = THR( pItem->AttachTo( m_pWia, ppIWiaItem[i] ) );
  201. if ( FAILED( hr ) )
  202. {
  203. delete pItem;
  204. goto Cleanup;
  205. }
  206. hr = THR( pItem->QueryInterface( &rgpDispatch[i] ) );
  207. Assert( SUCCEEDED( hr ) ); // this shouldn't fail.
  208. }
  209. }
  210. hr = THR( CComObject<CCollection>::CreateInstance( &pCol ) );
  211. if ( FAILED( hr ) )
  212. goto Cleanup;
  213. if ( rgpDispatch )
  214. {
  215. if( !pCol->SetDispatchArray( rgpDispatch, lCount ) )
  216. {
  217. hr = E_FAIL;
  218. goto Cleanup;
  219. }
  220. }
  221. hr = THR( pCol->QueryInterface( ppCollection ) );
  222. }
  223. Cleanup:
  224. if (ppIWiaItem)
  225. {
  226. for ( LONG i = 0; i < lCount; i++ )
  227. {
  228. if ( !(ppIWiaItem[i]) )
  229. continue;
  230. ppIWiaItem[i]->Release();
  231. ppIWiaItem[i] = NULL;
  232. }
  233. LocalFree( ppIWiaItem );
  234. }
  235. if (FAILED(hr) && rgpDispatch)
  236. {
  237. for (LONG index = 0; index < lCount; index ++)
  238. {
  239. if (rgpDispatch[index])
  240. rgpDispatch[index]->Release();
  241. rgpDispatch[index] = NULL;
  242. }
  243. CoTaskMemFree( rgpDispatch );
  244. }
  245. return hr;
  246. }
  247. /*-----------------------------------------------------------------------------
  248. * CWiaItem::Transfer [IWiaDispatchItem]
  249. *
  250. * This handles transfering this item to a file. This does several things:
  251. *
  252. * 1. Verifies that the item can actually be tranferred to a file
  253. * 2. begins the async trans, by spawning a thread
  254. * 3. following the completion of the async transfer the client is
  255. * sent a onTransferComplete( item, filename ) event.
  256. *
  257. * Note: we need to consider how to handle this methods, this object is currently
  258. * unsafe for scripting because this could potentially overwrite system
  259. * files. Proposed fixes:
  260. *
  261. * 1. Don't over write existing files
  262. * 2. If the file exists, then check its attributes if the system
  263. * attribute is present then abort
  264. * 3. If the file name starts with %WinDir% then abort
  265. *
  266. * bstrFilename: the name of the file to save this item to
  267. *--(samclem)-----------------------------------------------------------------*/
  268. STDMETHODIMP
  269. CWiaItem::Transfer( BSTR bstrFilename, VARIANT_BOOL bAsyncTransfer )
  270. {
  271. TraceTag((0, "attempting to transfer image to: %S", bstrFilename ));
  272. DWORD dwThreadId = NULL;
  273. HANDLE hThread = NULL;
  274. LONG lItemType = 0;
  275. HRESULT hr;
  276. IStream* pStrm = NULL;
  277. CWiaDataTransfer::ASYNCTRANSFERPARAMS* pParams;
  278. if (bstrFilename == NULL)
  279. return E_INVALIDARG; // No file name specified
  280. if (SysStringLen(bstrFilename) >= MAX_PATH)
  281. return E_INVALIDARG; // don't allow pathologicaly long file names
  282. hr = THR( m_pWiaItem->GetItemType( &lItemType ) );
  283. if ( FAILED( hr ) )
  284. goto Cleanup;
  285. if ( !( lItemType & WiaItemTypeFile ) && !( lItemType & WiaItemTypeTransfer ) )
  286. return E_INVALIDARG; // can't download this guy
  287. // we need to marshall the m_pWiaItem interface to another thread so that
  288. // we can accessit inside of that object.
  289. hr = THR( CoMarshalInterThreadInterfaceInStream( IID_IWiaItem,
  290. m_pWiaItem,
  291. &pStrm ) );
  292. if ( FAILED( hr ) )
  293. goto Cleanup;
  294. pParams = reinterpret_cast<CWiaDataTransfer::ASYNCTRANSFERPARAMS*>
  295. (CoTaskMemAlloc( sizeof( CWiaDataTransfer::ASYNCTRANSFERPARAMS ) ) );
  296. if (!pParams) {
  297. hr = E_OUTOFMEMORY;
  298. goto Cleanup;
  299. }
  300. // setup the params
  301. pParams->pStream = pStrm;
  302. pParams->pStream->AddRef();
  303. pParams->pItem = this;
  304. pParams->pItem->AddRef();
  305. pParams->bstrFilename = SysAllocString( bstrFilename );
  306. if ( bAsyncTransfer == VARIANT_TRUE )
  307. {
  308. hThread = CreateThread( NULL,
  309. 0,
  310. CWiaDataTransfer::DoAsyncTransfer,
  311. pParams,
  312. 0,
  313. &dwThreadId );
  314. // did we create the thread?
  315. if ( hThread == NULL )
  316. {
  317. TraceTag((0, "error creating the async transfer thread" ));
  318. return E_FAIL;
  319. }
  320. TraceTag((0, "create async download thread: id(%ld)", dwThreadId ));
  321. }
  322. else
  323. hr = CWiaDataTransfer::DoAsyncTransfer(pParams);
  324. Cleanup:
  325. if ( pStrm )
  326. pStrm->Release();
  327. return hr;
  328. }
  329. /*-----------------------------------------------------------------------------
  330. * CWiaItem::TakePicture [IWiaDispatchItem]
  331. *
  332. * This method sends the take picture command to the driver. It will return
  333. * a new dispatch item representing the new picture.
  334. *
  335. *--(byronc)-----------------------------------------------------------------*/
  336. STDMETHODIMP
  337. CWiaItem::TakePicture( IWiaDispatchItem** ppDispItem )
  338. {
  339. TraceTag((0, "attempting to take new picture" ));
  340. HRESULT hr = S_OK;
  341. IWiaItem *pNewIWiaItem = NULL;
  342. CComObject<CWiaItem>*pItem = NULL;
  343. if ( !ppDispItem )
  344. return E_POINTER;
  345. // Initialize the returned item to NULL
  346. *ppDispItem = NULL;
  347. // Send device command "TakePicture"
  348. hr = m_pWiaItem->DeviceCommand(0,
  349. &WIA_CMD_TAKE_PICTURE,
  350. &pNewIWiaItem);
  351. if (SUCCEEDED(hr)) {
  352. // Check for new item created
  353. if (pNewIWiaItem) {
  354. // Set the returned item
  355. hr = THR( CComObject<CWiaItem>::CreateInstance( &pItem ) );
  356. if ( FAILED( hr ) )
  357. goto Cleanup;
  358. hr = THR( pItem->AttachTo( m_pWia, pNewIWiaItem ) );
  359. if ( FAILED( hr ) )
  360. {
  361. delete pItem;
  362. goto Cleanup;
  363. }
  364. hr = THR( pItem->QueryInterface( ppDispItem ) );
  365. Assert( SUCCEEDED( hr ) ); // this shouldn't fail.
  366. }
  367. } else {
  368. // Call failed, so we'll set hr to false and return a NULL item.
  369. hr = S_FALSE;
  370. }
  371. Cleanup:
  372. if (FAILED(hr)) {
  373. if (pItem) {
  374. delete pItem;
  375. pItem = NULL;
  376. }
  377. if (*ppDispItem) {
  378. *ppDispItem = NULL;
  379. }
  380. }
  381. return hr;
  382. }
  383. /*-----------------------------------------------------------------------------
  384. * CWiaItem::SendTransferCompelete
  385. *
  386. * Called to send a transfer complete notification.
  387. *
  388. * pchFilename: the filename that we transfered to
  389. *--(samclem)-----------------------------------------------------------------*/
  390. void
  391. CWiaItem::SendTransferComplete(BSTR bstrFilename )
  392. {
  393. //TODO(Aug, 24) samclem: implement this
  394. TraceTag((0, "SendTransferComplete -- %S done.", bstrFilename ));
  395. CComBSTR bstrPathname = bstrFilename;
  396. m_pWia->SendEventMessage( WEM_TRANSFERCOMPLETE,
  397. reinterpret_cast<WPARAM>(static_cast<IDispatch*>(this)),
  398. reinterpret_cast<LPARAM>(bstrPathname.Detach()) );
  399. }
  400. /*-----------------------------------------------------------------------------
  401. * CWiaItem::get_Children [IWiaDispatchItem]
  402. *
  403. * This returns a collection of the children this item has. this will return
  404. * and empty collection if the doesn't or can't have any children.
  405. *
  406. * ppCollection: Out, recieves the ICollection pointer for our collection
  407. *--(samclem)-----------------------------------------------------------------*/
  408. STDMETHODIMP
  409. CWiaItem::get_Children( ICollection** ppCollection )
  410. {
  411. CComObject<CCollection>* pCol = NULL;
  412. HRESULT hr;
  413. IDispatch** rgpDispatch = NULL;
  414. IEnumWiaItem* pEnum = NULL;
  415. IWiaItem** rgpChildren = NULL;
  416. // code below assumes cChildren is initialized to 0!!!!
  417. ULONG cChildren = 0;
  418. ULONG celtFetched = 0;
  419. LONG ulItemType = 0;
  420. //TODO(Aug, 18) samclem: for performance reasons we will want to
  421. // cache the collection of our children. In order to do that however,
  422. // we need to be able sink to the WIA_EVENT_ITEM_ADDED and the
  423. // WIA_EVENT_ITEM_DELTED events. Currently this object doesn't
  424. // do any syncing so we will create the collection each time it
  425. // is requested. This however can be very slow.
  426. if ( NULL == ppCollection )
  427. return E_POINTER;
  428. // first we want the item type of this item
  429. hr = THR( m_pWiaItem->GetItemType( &ulItemType ) );
  430. if ( FAILED( hr ) )
  431. goto Cleanup;
  432. // You can enumerate the children of a wia item if an only if
  433. // it contains the WiaItemTypeFolder flag. We however, want to
  434. // return an empty enumeration anyhow, so we will make this
  435. // test upfront and get the enumeration and the child count
  436. // only if we can support them
  437. if ( ulItemType & WiaItemTypeFolder )
  438. {
  439. // enum the children
  440. hr = THR( m_pWiaItem->EnumChildItems( &pEnum ) );
  441. if ( FAILED( hr ) )
  442. goto Cleanup;
  443. hr = THR( pEnum->GetCount( &cChildren ) );
  444. if ( FAILED( hr ) )
  445. goto Cleanup;
  446. }
  447. // allocate our arrays, zeroing them if we are successful.
  448. // Note: we check for failure after each one
  449. if ( cChildren > 0 )
  450. {
  451. hr = E_OUTOFMEMORY;
  452. rgpChildren = new IWiaItem*[cChildren];
  453. if ( rgpChildren )
  454. ZeroMemory( rgpChildren, sizeof( IWiaItem* ) * cChildren );
  455. else
  456. goto Cleanup;
  457. rgpDispatch = reinterpret_cast<IDispatch**>
  458. (CoTaskMemAlloc( sizeof( IDispatch* ) * cChildren ) );
  459. if ( rgpDispatch )
  460. ZeroMemory( rgpDispatch, sizeof( IDispatch* ) * cChildren );
  461. else
  462. goto Cleanup;
  463. //BUG (Aug, 18) samclem: You can't retrieve all the items at
  464. // once, WIA doesn't want to do it, so we have another loop here
  465. // but we still use the array, hoping that we can do this in
  466. // the future.
  467. // get the items from the enum
  468. for ( ULONG iChild = 0; iChild < cChildren; iChild++ )
  469. {
  470. hr = THR( pEnum->Next( 1, &rgpChildren[iChild], &celtFetched ) );
  471. if ( FAILED( hr ) || celtFetched != 1 )
  472. goto Cleanup;
  473. }
  474. // we now have all our items, so we simply need iterate
  475. // over them and create the CWiaItem to attach to them
  476. for ( ULONG i = 0; i < cChildren; i++ )
  477. {
  478. if ( !rgpChildren[i] )
  479. continue;
  480. CComObject<CWiaItem>* pItem;
  481. hr = THR( CComObject<CWiaItem>::CreateInstance( &pItem ) );
  482. if ( FAILED( hr ) )
  483. goto Cleanup;
  484. hr = THR( pItem->AttachTo( m_pWia, rgpChildren[i] ) );
  485. if ( FAILED( hr ) )
  486. {
  487. delete pItem;
  488. goto Cleanup;
  489. }
  490. hr = THR( pItem->QueryInterface( &rgpDispatch[i] ) );
  491. Assert( SUCCEEDED( hr ) ); // this shouldn't fail.
  492. }
  493. }
  494. hr = THR( CComObject<CCollection>::CreateInstance( &pCol ) );
  495. if ( FAILED( hr ) )
  496. goto Cleanup;
  497. if ( rgpDispatch )
  498. {
  499. if( !pCol->SetDispatchArray( rgpDispatch, cChildren ) )
  500. {
  501. hr = E_FAIL;
  502. goto Cleanup;
  503. }
  504. }
  505. hr = THR( pCol->QueryInterface( ppCollection ) );
  506. Cleanup:
  507. if ( pEnum )
  508. pEnum->Release();
  509. if ( pCol && FAILED( hr ) )
  510. delete pCol;
  511. if ( rgpChildren )
  512. {
  513. for ( ULONG i = 0; i < cChildren; i++ )
  514. if ( rgpChildren[i] ) rgpChildren[i]->Release();
  515. delete[] rgpChildren;
  516. }
  517. if ( rgpDispatch && FAILED( hr ) )
  518. {
  519. for ( ULONG i = 0; i < cChildren; i++ )
  520. if ( rgpDispatch[i] ) rgpDispatch[i]->Release();
  521. CoTaskMemFree( rgpDispatch );
  522. }
  523. return hr;
  524. }
  525. // macro which helps inside of get_ItemType
  526. #define CAT_SEMI( buf, str ) \
  527. { \
  528. if( *buf ) \
  529. _tcscat( buf, TEXT( ";" ) ); \
  530. _tcscat( buf, str ); \
  531. }
  532. /*-----------------------------------------------------------------------------
  533. * CWiaItem::get_ItemType [IWiaDispatchItem]
  534. *
  535. * Retrieves the item type as a BSTR. This will have the format as follows:
  536. *
  537. * "device;folder", "image;file", "audio;file"
  538. *
  539. * The format is single strings seperated by ';'. there will be no semi-colon
  540. * at the end of the string.
  541. *
  542. * pbstrType: recieves the type of the item as a bstr.
  543. *--(samclem)-----------------------------------------------------------------*/
  544. STDMETHODIMP
  545. CWiaItem::get_ItemType( BSTR* pbstrType )
  546. {
  547. TCHAR tch[MAX_PATH] = { 0, 0 };
  548. HRESULT hr;
  549. LONG lItemType;
  550. USES_CONVERSION;
  551. if ( !pbstrType )
  552. return E_POINTER;
  553. *pbstrType = NULL;
  554. // we will construct an array of tchar's that contain the
  555. // property types. (note: an alternate approach would use CComBSTR)
  556. hr = THR( m_pWiaItem->GetItemType( &lItemType ) );
  557. if ( FAILED( hr ) )
  558. return hr;
  559. // process our flags, and create the item type.
  560. if ( lItemType & WiaItemTypeAnalyze )
  561. CAT_SEMI( tch, TEXT("analyze") );
  562. if ( lItemType & WiaItemTypeAudio )
  563. CAT_SEMI( tch, TEXT("audio") );
  564. if ( lItemType & WiaItemTypeDeleted )
  565. CAT_SEMI( tch, TEXT("deleted") );
  566. if ( lItemType & WiaItemTypeDevice )
  567. CAT_SEMI( tch, TEXT("device") );
  568. if ( lItemType & WiaItemTypeDisconnected )
  569. CAT_SEMI( tch, TEXT("disconnected") );
  570. if ( lItemType & WiaItemTypeFile )
  571. CAT_SEMI( tch, TEXT("file") );
  572. if ( lItemType & WiaItemTypeFolder )
  573. CAT_SEMI( tch, TEXT("folder") );
  574. if ( lItemType & WiaItemTypeFree )
  575. CAT_SEMI( tch, TEXT("free") );
  576. if ( lItemType & WiaItemTypeImage )
  577. CAT_SEMI( tch, TEXT("image") );
  578. if ( lItemType & WiaItemTypeRoot )
  579. CAT_SEMI( tch, TEXT("root") );
  580. if ( lItemType & WiaItemTypeTransfer)
  581. CAT_SEMI( tch, TEXT("transfer") );
  582. //
  583. // Original version:
  584. // WCHAR awch[MAX_PATH];
  585. // if ( MultiByteToWideChar( CP_ACP, 0, ach, -1, awch, MAX_PATH ) )
  586. //
  587. // Replaced with ATL conversion T2W.
  588. //
  589. *pbstrType = SysAllocString( T2W(tch) );
  590. if ( !*pbstrType )
  591. return E_OUTOFMEMORY;
  592. return S_OK;
  593. }
  594. /*-----------------------------------------------------------------------------
  595. * CWiaItem::GetPropById [IWiaDispatchItem]
  596. *
  597. * This returns the unchanged variant value of the property with the given
  598. * id.
  599. *
  600. * This will return a an empty variant if the property doesn't exist or
  601. * it can't be easily converted to a variant.
  602. *
  603. * propid: the id of the property that we want
  604. * pvaOut: Out, gets the value of the property.
  605. *--(samclem)-----------------------------------------------------------------*/
  606. STDMETHODIMP
  607. CWiaItem::GetPropById( WiaItemPropertyId Id, VARIANT* pvaOut )
  608. {
  609. HRESULT hr;
  610. PROPVARIANT vaProp;
  611. DWORD dwPropID = (DWORD)Id;
  612. hr = THR( GetWiaProperty( m_pWiaStorage, dwPropID, &vaProp ) );
  613. if ( FAILED( hr ) )
  614. return hr;
  615. // attempt to convert
  616. hr = THR( PropVariantToVariant( &vaProp, pvaOut ) );
  617. if ( FAILED( hr ) )
  618. {
  619. TraceTag((0, "forcing device property %ld to VT_EMPTY", dwPropID ));
  620. VariantInit( pvaOut );
  621. pvaOut->vt = VT_EMPTY;
  622. }
  623. // clear and return
  624. PropVariantClear( &vaProp );
  625. return S_OK;
  626. }
  627. /*-----------------------------------------------------------------------------
  628. * CWiaItem::get_ConnectStatus [IWiaDispatchItem]
  629. *
  630. * returns the connect status of the item. This is only applicatable to devices
  631. * and otherwise it will return NULL.
  632. *
  633. * Values: "connected", "disconnected" or NULL if not applicable
  634. *
  635. * pbstrStatus: Out, recieves the current connect status of the item
  636. *--(samclem)-----------------------------------------------------------------*/
  637. STDMETHODIMP
  638. CWiaItem::get_ConnectStatus( BSTR* pbstrStatus )
  639. {
  640. PROPVARIANT vaProp;
  641. HRESULT hr;
  642. STRING_TABLE( stConnectStatus )
  643. STRING_ENTRY( WIA_DEVICE_CONNECTED, "connected" )
  644. STRING_ENTRY( WIA_DEVICE_NOT_CONNECTED, "disconnected" )
  645. STRING_ENTRY( WIA_DEVICE_CONNECTED + 2, "not supported" )
  646. END_STRING_TABLE()
  647. if ( !pbstrStatus )
  648. return E_POINTER;
  649. hr = THR( GetWiaProperty( m_pWiaStorage, WIA_DPA_CONNECT_STATUS, &vaProp ) );
  650. if (hr != S_OK) {
  651. if ( FAILED( hr ) ) {
  652. return hr;
  653. }
  654. else {
  655. //
  656. // Property not found, so return "not supported"
  657. //
  658. vaProp.vt = VT_I4;
  659. vaProp.lVal = WIA_DEVICE_CONNECTED + 2;
  660. }
  661. }
  662. *pbstrStatus = SysAllocString( GetStringForVal( stConnectStatus, vaProp.lVal ) );
  663. PropVariantClear( &vaProp );
  664. if ( !*pbstrStatus )
  665. return E_OUTOFMEMORY;
  666. return S_OK;
  667. }
  668. /*-----------------------------------------------------------------------------
  669. * CWiaItem::get_Time [IWiaDispatchItem]
  670. *
  671. * Retrieves the current time from this item.
  672. *
  673. * pbstrTime: Out, recieves the time as a BSTR.
  674. *--(samclem)-----------------------------------------------------------------*/
  675. STDMETHODIMP
  676. CWiaItem::get_Time( BSTR* pbstrTime )
  677. {
  678. if ( !pbstrTime )
  679. return E_POINTER;
  680. PROPVARIANT vaProp;
  681. HRESULT hr = S_OK;
  682. LONG lItemType = 0;
  683. WCHAR wszStr[MAX_PATH];
  684. UNALIGNED SYSTEMTIME *pSysTime;
  685. PropVariantInit(&vaProp);
  686. //
  687. // If this is the root item, get WIA_DPA_DEVICE_TIME, else get
  688. // WIA_IPA_ITEM_ITEM.
  689. //
  690. hr = THR( m_pWiaItem->GetItemType( &lItemType ) );
  691. if ( FAILED( hr ) )
  692. return hr;
  693. if (lItemType & WiaItemTypeRoot) {
  694. hr = THR( GetWiaProperty( m_pWiaStorage, WIA_DPA_DEVICE_TIME, &vaProp ) );
  695. } else {
  696. hr = THR( GetWiaProperty( m_pWiaStorage, WIA_IPA_ITEM_TIME, &vaProp ) );
  697. }
  698. if ( FAILED( hr ) )
  699. return hr;
  700. //
  701. // Convert the value in vaProp to a string. First check that the variant
  702. // contains enough words to make up a SYSTEMTIME structure.
  703. //
  704. if (vaProp.caui.cElems >= (sizeof(SYSTEMTIME) / sizeof(WORD))) {
  705. pSysTime = (SYSTEMTIME*) vaProp.caui.pElems;
  706. swprintf(wszStr, L"%.4d/%.2d/%.2d:%.2d:%.2d:%.2d", pSysTime->wYear,
  707. pSysTime->wMonth,
  708. pSysTime->wDay,
  709. pSysTime->wHour,
  710. pSysTime->wMinute,
  711. pSysTime->wSecond);
  712. *pbstrTime = SysAllocString( wszStr );
  713. } else {
  714. hr = S_FALSE;
  715. }
  716. if ( hr != S_OK ) {
  717. *pbstrTime = SysAllocString( L"not supported" );
  718. }
  719. if ( !*pbstrTime )
  720. hr = E_OUTOFMEMORY;
  721. return hr;
  722. }
  723. /*-----------------------------------------------------------------------------
  724. * CWiaItem::get_FirmwareVersion [IWiaDispatchItem]
  725. *
  726. * Retrieves the firmware version from the device. Only applicatble on devices,
  727. * if its not applicable NULL is returned.
  728. *
  729. * pbstrVersion: Out, recieves the version from the device
  730. *--(samclem)-----------------------------------------------------------------*/
  731. STDMETHODIMP
  732. CWiaItem::get_FirmwareVersion( BSTR* pbstrVersion )
  733. {
  734. if ( !pbstrVersion )
  735. return E_POINTER;
  736. PROPVARIANT vaProp;
  737. HRESULT hr;
  738. hr = THR( GetWiaProperty( m_pWiaStorage, WIA_DPA_FIRMWARE_VERSION, &vaProp ) );
  739. if ( FAILED( hr ) )
  740. return hr;
  741. // if it is already a bstr then leave it alone
  742. if ( vaProp.vt == VT_BSTR )
  743. *pbstrVersion = SysAllocString( vaProp.bstrVal );
  744. else if ( vaProp.vt == VT_I4 )
  745. {
  746. WCHAR rgwch[255];
  747. wsprintf(rgwch, L"%d", vaProp.lVal);
  748. *pbstrVersion = SysAllocString( rgwch );
  749. }
  750. else
  751. {
  752. *pbstrVersion = SysAllocString( L"unknown" );
  753. }
  754. PropVariantClear( &vaProp );
  755. if ( !*pbstrVersion )
  756. return E_OUTOFMEMORY;
  757. return hr;
  758. }
  759. /*-----------------------------------------------------------------------------
  760. * CWiaItem::get_Name [IWiaDispatchItem]
  761. *
  762. * Retrieves the name of the item. Applicable to all items.
  763. *
  764. * pbstrName: Out, recieves the name of the item
  765. *--(samclem)-----------------------------------------------------------------*/
  766. STDMETHODIMP
  767. CWiaItem::get_Name( BSTR* pbstrName )
  768. {
  769. if ( !pbstrName )
  770. return E_POINTER;
  771. return THR( GetWiaPropertyBSTR( m_pWiaStorage, WIA_IPA_ITEM_NAME, pbstrName ) );
  772. }
  773. /*-----------------------------------------------------------------------------
  774. * CWiaItem::get_FullName [IWiaDispatchItem]
  775. *
  776. * Retrieves the full name of the item, Applicable to all items
  777. * Format: "Root\blah\blah"
  778. *
  779. * pbstrFullName: Out, recieves the full name of the item
  780. *--(samclem)-----------------------------------------------------------------*/
  781. STDMETHODIMP
  782. CWiaItem::get_FullName( BSTR* pbstrFullName )
  783. {
  784. if ( !pbstrFullName )
  785. return E_POINTER;
  786. return THR( GetWiaPropertyBSTR( m_pWiaStorage, WIA_IPA_FULL_ITEM_NAME, pbstrFullName ) );
  787. }
  788. /*-----------------------------------------------------------------------------
  789. * CWiaItem::get_Width [IWiaDispatchItem]
  790. *
  791. * Retrieves the width of the item, most items will support getting thier
  792. * width.
  793. *
  794. * plWidth: Out, recieves the items with in pixels
  795. *--(samclem)-----------------------------------------------------------------*/
  796. STDMETHODIMP CWiaItem::get_Width( long* plWidth )
  797. {
  798. if ( !plWidth )
  799. return E_POINTER;
  800. *plWidth = (long)m_dwItemWidth;
  801. return S_OK;
  802. }
  803. /*-----------------------------------------------------------------------------
  804. * CWiaItem::get_Height [IWiaDispatchItem]
  805. *
  806. * Retrieves the height of the item, most items will support getting thier
  807. * width. Will return 0, if there is no with to get
  808. *
  809. * plHeight: Out, recieves the itmes height in pixels
  810. *--(samclem)-----------------------------------------------------------------*/
  811. STDMETHODIMP CWiaItem::get_Height( long* plHeight )
  812. {
  813. if ( !plHeight )
  814. return E_POINTER;
  815. *plHeight = (long)m_dwItemHeight;
  816. return S_OK;
  817. }
  818. /*-----------------------------------------------------------------------------
  819. * CWiaItem::get_ThumbWidth [IWiaDispatchItem]
  820. *
  821. * Retrieves the thumbnail width for the thumbnail associated with this item,
  822. * if this item doesn't support thumbnails this will be 0.
  823. *
  824. * plWidth: Out, recieves the width of the thumbnail image
  825. *--(samclem)-----------------------------------------------------------------*/
  826. STDMETHODIMP
  827. CWiaItem::get_ThumbWidth( long* plWidth )
  828. {
  829. if ( !plWidth )
  830. return E_POINTER;
  831. *plWidth = (long)m_dwThumbWidth;
  832. return S_OK;
  833. }
  834. /*-----------------------------------------------------------------------------
  835. * CWiaItem::get_ThumbHeight [IWiaDispatchItem]
  836. *
  837. * Retrieves the thumbnail height for the thumbnail image. If this item doesn't
  838. * support thumbnails then this will return 0.
  839. *
  840. * plHeight: Out, recieces the height of the thumbnail image
  841. *--(samclem)-----------------------------------------------------------------*/
  842. STDMETHODIMP
  843. CWiaItem::get_ThumbHeight( long* plHeight )
  844. {
  845. if ( !plHeight )
  846. return E_POINTER;
  847. *plHeight = (long)m_dwThumbHeight;
  848. return S_OK;
  849. }
  850. /*-----------------------------------------------------------------------------
  851. * CWiaItem::get_Thumbnail [IWIaDispatchItem]
  852. *
  853. * This recieves a URL to the thumbnail. This returns a magic URL that
  854. * will transfer the bits directly to trident. This will return
  855. * E_INVALIDARG if the given item doesn't support thumbnails. Or NULL if
  856. * we are unable to build a URL for the item.
  857. *
  858. * pbstrPath: Out, recieces teh full path tot the thumbnail
  859. *--(samclem)-----------------------------------------------------------------*/
  860. STDMETHODIMP
  861. CWiaItem::get_Thumbnail( BSTR* pbstrPath )
  862. {
  863. LONG lItemType = 0;
  864. HRESULT hr;
  865. if ( !pbstrPath )
  866. return E_POINTER;
  867. *pbstrPath = NULL;
  868. hr = THR( m_pWiaItem->GetItemType( &lItemType ) );
  869. if ( FAILED( hr ) )
  870. return hr;
  871. if ( !( lItemType & ( WiaItemTypeFile | WiaItemTypeImage ) ) )
  872. {
  873. TraceTag((tagError, "Requested thumbnail on an invaild item type" ));
  874. return E_INVALIDARG;
  875. }
  876. // Do we already have the URL? if not then we can ask our custom
  877. // protocol to create the URL for us.
  878. if ( !m_bstrThumbUrl )
  879. {
  880. hr = THR( CWiaProtocol::CreateURL( m_pWiaItem, &m_bstrThumbUrl ) );
  881. if ( FAILED( hr ) )
  882. return hr;
  883. }
  884. *pbstrPath = SysAllocString( m_bstrThumbUrl );
  885. if ( !*pbstrPath )
  886. return E_OUTOFMEMORY;
  887. return S_OK;
  888. }
  889. /*-----------------------------------------------------------------------------
  890. * CWiaItem::get_PictureWidth [IWiaDispatchItem]
  891. *
  892. * Retrieces the width of the picture produced by this camera. this will return
  893. * -1, if its not supported or on error.
  894. *
  895. * plWidth: Out, recieves the width of the picture
  896. *--(samclem)-----------------------------------------------------------------*/
  897. STDMETHODIMP
  898. CWiaItem::get_PictureWidth( long* plWidth )
  899. {
  900. PROPVARIANT vaProp;
  901. HRESULT hr;
  902. if ( !plWidth )
  903. return E_POINTER;
  904. *plWidth = -1;
  905. hr = THR( GetWiaProperty( m_pWiaStorage, WIA_DPC_PICT_WIDTH, &vaProp ) );
  906. if ( SUCCEEDED( hr ) )
  907. {
  908. if ( vaProp.vt == VT_I4 )
  909. *plWidth = vaProp.lVal;
  910. }
  911. PropVariantClear( &vaProp );
  912. return hr;
  913. }
  914. /*-----------------------------------------------------------------------------
  915. * CWiaItem::get_PictureHeight [IWiaDispatchItem]
  916. *
  917. * Retrieves the height of the pictures produced by this camera, or -1
  918. * if the item doesn't support this property.
  919. *
  920. * plHeight: the height of the pictures produced.
  921. *--(samclem)-----------------------------------------------------------------*/
  922. STDMETHODIMP
  923. CWiaItem::get_PictureHeight( long* plHeight )
  924. {
  925. PROPVARIANT vaProp;
  926. HRESULT hr;
  927. if ( !plHeight )
  928. return E_POINTER;
  929. *plHeight = -1;
  930. hr = THR( GetWiaProperty( m_pWiaStorage, WIA_DPC_PICT_HEIGHT, &vaProp ) );
  931. if ( SUCCEEDED( hr ) )
  932. {
  933. if ( vaProp.vt == VT_I4 )
  934. *plHeight = vaProp.lVal;
  935. }
  936. PropVariantClear( &vaProp );
  937. return hr;
  938. }
  939. /*-----------------------------------------------------------------------------
  940. * CWiaItem::TransferThumbnailToCache
  941. *
  942. * This transfers a thumbnail for this bitmap to our internal cache.
  943. * this will return S_OK if its successful or an error code if something
  944. * goes wrong. It will also fill in the out params with the new thumbnail
  945. *
  946. * pItem: the item to get the thumbnail from
  947. * ppbThumb: Out, recieves a pointer to the in-memory cached bitmap
  948. * pcbThumb: Out, recieves the size of the in-memory bitmap
  949. *--(samclem)-----------------------------------------------------------------*/
  950. HRESULT
  951. CWiaItem::TransferThumbnailToCache( IWiaItem* pItem, BYTE** ppbThumb, DWORD* pcbThumb )
  952. {
  953. enum
  954. {
  955. PropWidth = 0,
  956. PropHeight = 1,
  957. PropThumbnail = 2,
  958. PropFullName = 3,
  959. PropCount = 4,
  960. };
  961. HRESULT hr;
  962. CComPtr<IWiaItem> pItemK = pItem;
  963. DWORD cb = NULL;
  964. BYTE* pbBitmap = NULL;
  965. BYTE* pbData = NULL;
  966. CComQIPtr<IWiaPropertyStorage> pWiaStg;
  967. CWiaCacheManager* pCache = CWiaCacheManager::GetInstance();
  968. PROPVARIANT avaProps[PropCount];
  969. PROPSPEC aspec[PropCount] =
  970. {
  971. { PRSPEC_PROPID, WIA_IPC_THUMB_WIDTH },
  972. { PRSPEC_PROPID, WIA_IPC_THUMB_HEIGHT },
  973. { PRSPEC_PROPID, WIA_IPC_THUMBNAIL },
  974. { PRSPEC_PROPID, WIA_IPA_FULL_ITEM_NAME },
  975. };
  976. Assert( pItem && ppbThumb && pcbThumb );
  977. *ppbThumb = 0;
  978. *pcbThumb = 0;
  979. // initalize our prop variants
  980. for ( int i = 0; i < PropCount; i++ )
  981. PropVariantInit( &avaProps[i] );
  982. // we need to access the WIA property storage. So if we can't
  983. // access that then we better just bail, because everything else
  984. // will be useless
  985. pWiaStg = pItem;
  986. if ( !pWiaStg )
  987. {
  988. TraceTag((tagError, "item didn't support IWiaPropertyStorage" ));
  989. hr = E_NOINTERFACE;
  990. goto Cleanup;
  991. }
  992. hr = THR( pWiaStg->ReadMultiple( PropCount, aspec, avaProps ) );
  993. if ( FAILED( hr ) )
  994. goto Cleanup;
  995. // validate the types, we want to make sure we actually have a
  996. // thumbnail to save, if we don't bail with a failure code
  997. if ( avaProps[PropThumbnail].vt == VT_EMPTY ||
  998. !( avaProps[PropThumbnail].vt & ( VT_VECTOR | VT_UI1 ) ) )
  999. {
  1000. TraceTag((tagError, "item didn't return a useful thumbnail property" ));
  1001. hr = E_FAIL;
  1002. goto Cleanup;
  1003. }
  1004. // we now need to build our bitmap from the data, in order to do that
  1005. // we need to allocate a chunk of memory. Since we are putting
  1006. // this data in the cache, we want to allocate it using the
  1007. // cache
  1008. cb = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) +
  1009. ( sizeof( UCHAR ) * ( avaProps[PropThumbnail].caul.cElems ) );
  1010. if ( !pCache->AllocThumbnail( cb, &pbBitmap ) )
  1011. {
  1012. hr = E_OUTOFMEMORY;
  1013. goto Cleanup;
  1014. }
  1015. BITMAPINFOHEADER bmi;
  1016. BITMAPFILEHEADER bmf;
  1017. //
  1018. // We need to set the BMP header info. To avoid data misalignment problems
  1019. // on 64bit, we'll modify the data structures on the stacj, then just copy them
  1020. // to the buffer.
  1021. //
  1022. // step 0, zero our memory
  1023. ZeroMemory(pbBitmap, sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER ) );
  1024. ZeroMemory(&bmf, sizeof(bmf));
  1025. ZeroMemory(&bmi, sizeof(bmi));
  1026. // step 1, setup the bitmap file header
  1027. bmf.bfType = k_wBitmapType;
  1028. bmf.bfSize = cb;
  1029. bmf.bfOffBits = sizeof(BITMAPINFOHEADER);
  1030. // step 2, setup the bitmap info header
  1031. bmi.biSize = sizeof(BITMAPINFOHEADER);
  1032. bmi.biWidth = avaProps[PropWidth].lVal;
  1033. bmi.biHeight = avaProps[PropHeight].lVal;
  1034. bmi.biPlanes = 1;
  1035. bmi.biBitCount = 24;
  1036. bmi.biCompression = BI_RGB;
  1037. // step 3, copy the new header info. to the buffer
  1038. memcpy(pbBitmap, &bmf, sizeof(BITMAPFILEHEADER));
  1039. memcpy(pbBitmap + sizeof(BITMAPFILEHEADER), &bmi, sizeof(BITMAPINFOHEADER));
  1040. pbData = (pbBitmap + (sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER)));
  1041. // copy the data that WIA gave us into the bitmap buffer. once we
  1042. // done this, our thumbnail is ready for the cache
  1043. memcpy( pbData, avaProps[PropThumbnail].caul.pElems,
  1044. sizeof( UCHAR ) * ( avaProps[PropThumbnail].caul.cElems ) );
  1045. pCache->AddThumbnail(
  1046. avaProps[PropFullName].bstrVal,
  1047. pbBitmap,
  1048. cb );
  1049. // setup the out params
  1050. *pcbThumb = cb;
  1051. *ppbThumb = pbBitmap;
  1052. Cleanup:
  1053. FreePropVariantArray( PropCount, avaProps );
  1054. if ( FAILED( hr ) )
  1055. {
  1056. if ( pbBitmap )
  1057. pCache->FreeThumbnail( pbBitmap );
  1058. }
  1059. return hr;
  1060. }
  1061. //------------------------------- CWiaDataTransfer ----------------------------
  1062. /*-----------------------------------------------------------------------------
  1063. * CWiaDataTransfer::DoAsyncTransfer
  1064. *
  1065. * This is called to begin an Async transfer of the data. This will be
  1066. * called via a call to create thread.
  1067. *
  1068. * Note: You can't use any of the interfaces inside of pItem, you must
  1069. * query for them through the marshaled interface pointer.
  1070. *
  1071. * pvParams: AsyncTransferParams structure which has the data we need
  1072. *--(samclem)-----------------------------------------------------------------*/
  1073. DWORD WINAPI
  1074. CWiaDataTransfer::DoAsyncTransfer( LPVOID pvParams )
  1075. {
  1076. TraceTag((0, "** DoAsyncTransfer --> Begin Thread" ));
  1077. HRESULT hr;
  1078. HRESULT hrCoInit;
  1079. IWiaDataCallback* pCallback = NULL;
  1080. IWiaDataTransfer* pWiaTrans = NULL;
  1081. IWiaItem* pItem = NULL;
  1082. IWiaPropertyStorage* pWiaStg = NULL;
  1083. CComObject<CWiaDataTransfer>* pDataTrans = NULL;
  1084. WIA_DATA_TRANSFER_INFO wdti;
  1085. STGMEDIUM stgMedium;
  1086. enum
  1087. {
  1088. PropTymed = 0,
  1089. PropFormat = 1,
  1090. PropCount = 2,
  1091. };
  1092. PROPSPEC spec[PropCount] =
  1093. {
  1094. { PRSPEC_PROPID, WIA_IPA_TYMED },
  1095. { PRSPEC_PROPID, WIA_IPA_FORMAT },
  1096. };
  1097. PROPVARIANT rgvaProps[PropCount];
  1098. ASYNCTRANSFERPARAMS* pParams = reinterpret_cast<ASYNCTRANSFERPARAMS*>(pvParams);
  1099. Assert( pParams );
  1100. // wait 50ms so that things can settle down
  1101. Sleep( 50 );
  1102. for ( int i = 0; i < PropCount; i++ )
  1103. PropVariantInit( &rgvaProps[i] );
  1104. hrCoInit = THR( CoInitialize( NULL ) );
  1105. if ( FAILED( hrCoInit ) )
  1106. goto Cleanup;
  1107. // force a yield and let everyone else process what they
  1108. // would like to do.
  1109. Sleep( 0 );
  1110. // first we need to unmarshal our interface
  1111. hr = THR( CoGetInterfaceAndReleaseStream( pParams->pStream,
  1112. IID_IWiaItem,
  1113. reinterpret_cast<void**>(&pItem) ) );
  1114. if ( FAILED( hr ) )
  1115. goto Cleanup;
  1116. // we need the wia property storage
  1117. hr = THR( pItem->QueryInterface( IID_IWiaPropertyStorage,
  1118. reinterpret_cast<void**>(&pWiaStg) ) );
  1119. if ( FAILED( hr ) )
  1120. goto Cleanup;
  1121. // first query this object for the IWiaDataTransfer interface
  1122. hr = THR( pItem->QueryInterface( IID_IWiaDataTransfer,
  1123. reinterpret_cast<void**>(&pWiaTrans) ) );
  1124. if ( FAILED( hr ) )
  1125. goto Cleanup;
  1126. ZeroMemory( &wdti, sizeof( wdti ) );
  1127. rgvaProps[PropTymed].vt = VT_I4;
  1128. rgvaProps[PropFormat].vt = VT_CLSID;
  1129. if ( 0 == wcscmp( pParams->bstrFilename, CLIPBOARD_STR_W ) )
  1130. {
  1131. rgvaProps[PropTymed].lVal = TYMED_CALLBACK;
  1132. rgvaProps[PropFormat].puuid = (GUID*)&WiaImgFmt_MEMORYBMP;
  1133. }
  1134. else
  1135. {
  1136. rgvaProps[PropTymed].lVal = TYMED_FILE;
  1137. rgvaProps[PropFormat].puuid = (GUID*)&WiaImgFmt_BMP;
  1138. }
  1139. // write these properties out to the storage
  1140. hr = THR( pWiaStg->WriteMultiple( PropCount, spec, rgvaProps, WIA_IPC_FIRST ) );
  1141. if ( FAILED( hr ) )
  1142. goto Cleanup;
  1143. hr = THR( CComObject<CWiaDataTransfer>::CreateInstance( &pDataTrans ) );
  1144. if ( FAILED( hr ) )
  1145. goto Cleanup;
  1146. hr = THR( pDataTrans->Initialize( pParams->pItem, pParams->bstrFilename ) );
  1147. if ( FAILED( hr ) )
  1148. goto Cleanup;
  1149. hr = THR( pDataTrans->QueryInterface( IID_IWiaDataCallback,
  1150. reinterpret_cast<void**>(&pCallback) ) );
  1151. if ( FAILED( hr ) )
  1152. goto Cleanup;
  1153. // we have everything we need, so setup the info and
  1154. // get ready to transfer
  1155. wdti.ulSize = sizeof( wdti );
  1156. wdti.ulBufferSize = ( 1024 * 64 ); // 64k transfer
  1157. if ( 0 == _wcsicmp( pParams->bstrFilename, CLIPBOARD_STR_W ) )
  1158. // Do the banded transfer.
  1159. hr = THR( pWiaTrans->idtGetBandedData( &wdti, pCallback ) );
  1160. else
  1161. {
  1162. ZeroMemory(&stgMedium, sizeof(STGMEDIUM));
  1163. stgMedium.tymed = TYMED_FILE;
  1164. stgMedium.lpszFileName = pParams->bstrFilename;
  1165. // Do the file transfer.
  1166. hr = THR( pWiaTrans->idtGetData( &stgMedium, pCallback ) );
  1167. }
  1168. Cleanup:
  1169. if ( pItem )
  1170. pItem->Release();
  1171. if ( pWiaStg )
  1172. pWiaStg->Release();
  1173. if ( pCallback )
  1174. pCallback->Release();
  1175. if ( pWiaTrans )
  1176. pWiaTrans->Release();
  1177. //
  1178. // Since the GUID we supplied as CLSID for PropFormat is a global const
  1179. // we must not free it. So we don't call FreePropVariantArry here,
  1180. // since there is nothing to free
  1181. //
  1182. ZeroMemory(rgvaProps, sizeof(rgvaProps));
  1183. // free the params that we were passed.
  1184. if ( pParams )
  1185. {
  1186. SysFreeString( pParams->bstrFilename );
  1187. pParams->pItem->Release();
  1188. CoTaskMemFree( pParams );
  1189. }
  1190. if ( SUCCEEDED( hrCoInit ) )
  1191. CoUninitialize();
  1192. TraceTag((0, "** DoAsyncTransfer --> End Thread" ));
  1193. return hr;
  1194. }
  1195. /*-----------------------------------------------------------------------------
  1196. * CWiaDataTransfer::TransferComplete
  1197. *
  1198. * This is called when the transfer completed successfully, this will save
  1199. * the data out to the proper place.
  1200. *--(samclem)-----------------------------------------------------------------*/
  1201. HRESULT
  1202. CWiaDataTransfer::TransferComplete()
  1203. {
  1204. TraceTag((tagWiaDataTrans, "CWiaDataTransfer::TransferComplete *********" ));
  1205. HANDLE hFile = INVALID_HANDLE_VALUE;
  1206. BOOL bRes = TRUE;
  1207. DWORD cbw = 0;
  1208. HGLOBAL pBuf = NULL;
  1209. BYTE* pbBuf = NULL;
  1210. if ( m_pbBuffer )
  1211. {
  1212. // Check whether we save the data to clipboard or file
  1213. if ( 0 == _wcsicmp( m_bstrOutputFile, CLIPBOARD_STR_W ) )
  1214. {
  1215. pBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, m_sizeBuffer);
  1216. if (!pBuf)
  1217. return E_OUTOFMEMORY;
  1218. if ( bRes = OpenClipboard(NULL) )
  1219. {
  1220. if ( bRes = EmptyClipboard() )
  1221. {
  1222. pbBuf = (BYTE*) GlobalLock(pBuf);
  1223. if ( pbBuf )
  1224. {
  1225. memcpy(pbBuf, m_pbBuffer, m_sizeBuffer);
  1226. // Callback dibs come back as TOPDOWN, so flip
  1227. VerticalFlip(pbBuf);
  1228. GlobalUnlock(pBuf);
  1229. if ( SetClipboardData(CF_DIB, pBuf) == NULL )
  1230. {
  1231. TraceTag((0, "TransferComplete - SetClipboardData failed" ));
  1232. // redundant statement added to get rid of "error C4390: ';' : empty controlled statement found;"
  1233. bRes = FALSE;
  1234. }
  1235. }
  1236. else
  1237. TraceTag((0, "TransferComplete - GlobalLock failed" ));
  1238. }
  1239. else
  1240. {
  1241. TraceTag((0, "TransferComplete - EmptyClipboard failed" ));
  1242. // redundant statement added to get rid of "error C4390: ';' : empty controlled statement found;"
  1243. bRes = FALSE;
  1244. }
  1245. bRes = CloseClipboard();
  1246. if ( !bRes )
  1247. {
  1248. TraceTag((0, "TransferComplete - CloseClipboard failed" ));
  1249. // redundant statement added to get rid of "error C4390: ';' : empty controlled statement found;"
  1250. bRes = FALSE;
  1251. }
  1252. }
  1253. else
  1254. TraceTag((0, "TransferComplete - OpenClipboard failed" ));
  1255. GlobalFree(pBuf);
  1256. }
  1257. m_pItem->SendTransferComplete(m_bstrOutputFile);
  1258. CoTaskMemFree( m_pbBuffer );
  1259. m_pbBuffer = NULL;
  1260. }
  1261. else
  1262. {
  1263. //
  1264. // File transfer complete, so signal the event
  1265. //
  1266. m_pItem->SendTransferComplete(m_bstrOutputFile);
  1267. }
  1268. return S_OK;
  1269. }
  1270. /*-----------------------------------------------------------------------------
  1271. * CWiaDataTransfer::CWiaDataTransfer
  1272. *
  1273. * This creates a new CWiaDataTransfer object. This initializes the member
  1274. * variables of this object to a know state.
  1275. *--(samclem)-----------------------------------------------------------------*/
  1276. CWiaDataTransfer::CWiaDataTransfer()
  1277. : m_pbBuffer( NULL ), m_sizeBuffer( 0 ), m_pItem( NULL )
  1278. {
  1279. TRACK_OBJECT("CWiaDataTransfer")
  1280. }
  1281. /*-----------------------------------------------------------------------------
  1282. * CWiaDataTransfer::FinalRelease
  1283. *
  1284. * This is called when the object is finally released. This is responsible
  1285. * for cleaning up any memory allocated by this object.
  1286. *
  1287. * NOTE: this currently has a hack to get around the fact that the
  1288. * IT_MSG_TERMINATION is not always sent by WIA.
  1289. *--(samclem)-----------------------------------------------------------------*/
  1290. STDMETHODIMP_(void)
  1291. CWiaDataTransfer::FinalRelease()
  1292. {
  1293. // do we have a buffer?
  1294. if ( m_pbBuffer )
  1295. {
  1296. TraceTag((tagError, "CWiaDataTransfer - buffer should have been freed!!!!" ));
  1297. TraceTag((tagError, " **** HACK HACK ***** Calling TansferComplete" ));
  1298. TraceTag((tagError, " **** This could write a bogus file which might be unsable" ));
  1299. TransferComplete();
  1300. }
  1301. if ( m_pItem )
  1302. m_pItem->Release();
  1303. m_pItem = NULL;
  1304. }
  1305. /*-----------------------------------------------------------------------------
  1306. * CWiaDataTransfer::Initialize
  1307. *
  1308. * This handles the internal initialization of the CWiaDataTransfer. This
  1309. * should be called immediatly after it is created but before you attempt
  1310. * to do anything with it.
  1311. *
  1312. * pItem: the CWiaItem that we want to transfer from (AddRef'd)
  1313. * bstrFilename: the file where we want to save the data
  1314. *--(samclem)-----------------------------------------------------------------*/
  1315. HRESULT
  1316. CWiaDataTransfer::Initialize( CWiaItem* pItem, BSTR bstrFilename )
  1317. {
  1318. // copy the filename into our output buffer
  1319. m_bstrOutputFile = bstrFilename;
  1320. // set our owner item, we want to ensure the item exists
  1321. // as long as we do, so we will AddRef here and release
  1322. // in final release.
  1323. m_pItem = pItem;
  1324. m_pItem->AddRef();
  1325. return S_OK;
  1326. }
  1327. /*-----------------------------------------------------------------------------
  1328. * CWiaDataTransfer::BandedDataCallback [IWiaDataTransfer]
  1329. *
  1330. * This is the callback from WIA which tells us what is going on. This
  1331. * copies the memory into our own buffer so that we can eventually save it
  1332. * out. In any error conditions this returns S_FALSE to abort the transfer.
  1333. *
  1334. * lMessage: what is happening one of IT_MSG_xxx values
  1335. * lStatus: Sub status of whats happening
  1336. * lPercentComplete: Percent of the operation that has completed
  1337. * lOffset: the offset inside of pbBuffer where this operation is
  1338. * lLength: The length of the valid data inside of the buffer
  1339. * lReserved: Reserved.
  1340. * lResLength: Reserved.
  1341. * pbBuffer: The buffer we can read from in order to process the
  1342. * data. Exact use depends on lMessage
  1343. *--(samclem)-----------------------------------------------------------------*/
  1344. STDMETHODIMP
  1345. CWiaDataTransfer::BandedDataCallback( LONG lMessage, LONG lStatus, LONG lPercentComplete,
  1346. LONG lOffset, LONG lLength, LONG lReserved, LONG lResLength, BYTE *pbBuffer )
  1347. {
  1348. switch ( lMessage )
  1349. {
  1350. case IT_MSG_DATA:
  1351. TraceTag((tagWiaDataTrans, "IT_MSG_DATA: %ld%% complete", lPercentComplete ));
  1352. if ( m_pbBuffer )
  1353. {
  1354. // copy the data into our buffer
  1355. memcpy( m_pbBuffer + lOffset, pbBuffer, lLength );
  1356. }
  1357. break;
  1358. case IT_MSG_DATA_HEADER:
  1359. {
  1360. TraceTag((tagWiaDataTrans, "IT_MSG_DATA_HEADER" ));
  1361. UNALIGNED WIA_DATA_CALLBACK_HEADER* pHeader =
  1362. reinterpret_cast<WIA_DATA_CALLBACK_HEADER*>(pbBuffer);
  1363. TraceTag((tagWiaDataTrans, "-------> %ld bytes", pHeader->lBufferSize ));
  1364. // allocate our buffer
  1365. m_sizeBuffer = pHeader->lBufferSize;
  1366. m_pbBuffer = static_cast<BYTE*>(CoTaskMemAlloc( pHeader->lBufferSize ));
  1367. if ( !m_pbBuffer )
  1368. return S_FALSE; // abort
  1369. }
  1370. break;
  1371. case IT_MSG_NEW_PAGE:
  1372. TraceTag((tagWiaDataTrans, "IT_MSG_NEW_PAGE" ));
  1373. break;
  1374. case IT_MSG_STATUS:
  1375. TraceTag((tagWiaDataTrans, "IT_MSG_STATUS: %ld%% complete", lPercentComplete ));
  1376. break;
  1377. case IT_MSG_TERMINATION:
  1378. TraceTag((tagWiaDataTrans, "IT_MSG_TERMINATION: %ld%% complete", lPercentComplete ));
  1379. if ( FAILED( THR( TransferComplete() ) ) )
  1380. return S_FALSE;
  1381. break;
  1382. }
  1383. return S_OK;
  1384. }
  1385. /*-----------------------------------------------------------------------------
  1386. * VerticalFlip
  1387. *
  1388. * Vertically flips a DIB buffer. It assumes a non-NULL pointer argument.
  1389. *
  1390. * pBuf: pointer to the DIB image
  1391. *--(byronc)-----------------------------------------------------------------*/
  1392. HRESULT VerticalFlip(
  1393. BYTE *pBuf)
  1394. {
  1395. HRESULT hr = S_OK;
  1396. LONG lHeight;
  1397. LONG lWidth;
  1398. BITMAPINFOHEADER *pbmih;
  1399. PBYTE pTop = NULL;
  1400. PBYTE pBottom = NULL;
  1401. pbmih = (BITMAPINFOHEADER*) pBuf;
  1402. //
  1403. // If not a TOPDOWN dib then no need to flip
  1404. //
  1405. if (pbmih->biHeight > 0) {
  1406. return S_OK;
  1407. }
  1408. //
  1409. // Set Top pointer, width and height. Make sure the bitmap height
  1410. // is positive.
  1411. //
  1412. pTop = pBuf + pbmih->biSize + ((pbmih->biClrUsed) * sizeof(RGBQUAD));
  1413. lWidth = ((pbmih->biWidth * pbmih->biBitCount + 31) / 32) * 4;
  1414. pbmih->biHeight = abs(pbmih->biHeight);
  1415. lHeight = pbmih->biHeight;
  1416. //
  1417. // Allocat a temp scan line buffer
  1418. //
  1419. PBYTE pTempBuffer = (PBYTE)LocalAlloc(LPTR, lWidth);
  1420. if (pTempBuffer) {
  1421. LONG index;
  1422. pBottom = pTop + (lHeight-1) * lWidth;
  1423. for (index = 0;index < (lHeight/2);index++) {
  1424. //
  1425. // Swap Top and Bottom lines
  1426. //
  1427. memcpy(pTempBuffer, pTop, lWidth);
  1428. memcpy(pTop, pBottom, lWidth);
  1429. memcpy(pBottom,pTempBuffer, lWidth);
  1430. pTop += lWidth;
  1431. pBottom -= lWidth;
  1432. }
  1433. LocalFree(pTempBuffer);
  1434. } else {
  1435. hr = E_OUTOFMEMORY;
  1436. }
  1437. return hr;
  1438. }