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.

882 lines
28 KiB

  1. /*-----------------------------------------------------------------------------
  2. *
  3. * File: wia.cpp
  4. * Author: Samuel Clement
  5. * Date: Thu Aug 12 11:35:38 1999
  6. * Description:
  7. * Implementation of the CWia class
  8. *
  9. * Copyright (c) 1999 Microsoft Corporation
  10. *
  11. * History:
  12. * 12 Aug 1999: Created.
  13. * 27 Aug 1999: Added, _DebugDialog implementation
  14. * 10 Sep 1999: Use CWiaCacheManager when creating devices (samclem)
  15. *----------------------------------------------------------------------------*/
  16. #include "stdafx.h"
  17. // register our window messages
  18. const UINT WEM_TRANSFERCOMPLETE = RegisterWindowMessage( TEXT("wem_transfercomplete") );
  19. // the window property to retrieve the CWia pointer
  20. const TCHAR* CWIA_WNDPROP = TEXT("cwia_ptr");
  21. const TCHAR* CWIA_EVENTWNDCLS = TEXT("cwia hidden window");
  22. /*-----------------------------------------------------------------------------
  23. * CWia::CWia
  24. *
  25. * This creates a new CWia object. this initializes the variables to a
  26. * known state so they can do things.
  27. *--(samclem)-----------------------------------------------------------------*/
  28. CWia::CWia()
  29. : m_pWiaDevMgr( NULL ),
  30. m_pDeviceCollectionCache( NULL ),
  31. m_hwndEvent(NULL),
  32. m_pCWiaEventCallback(NULL)
  33. {
  34. TRACK_OBJECT( "CWia" );
  35. }
  36. /*-----------------------------------------------------------------------------
  37. * CWia::FinalRelease
  38. *
  39. * This is called when we are finally released. this will clear all the
  40. * pointers that we have and set them to null so that we know they were
  41. * released.
  42. *--(samclem)-----------------------------------------------------------------*/
  43. STDMETHODIMP_(void)
  44. CWia::FinalRelease()
  45. {
  46. if ( m_hwndEvent )
  47. DestroyWindow( m_hwndEvent );
  48. //
  49. // Make sure we unregister for WIA Devices. Note that it is safe to call
  50. // unregister multiple times.
  51. //
  52. if (m_pCWiaEventCallback)
  53. {
  54. m_pCWiaEventCallback->UnRegisterForConnectDisconnect();
  55. m_pCWiaEventCallback->setOwner(NULL);
  56. m_pCWiaEventCallback->Release();
  57. }
  58. m_pCWiaEventCallback = NULL;
  59. if ( m_pWiaDevMgr )
  60. m_pWiaDevMgr->Release();
  61. m_pWiaDevMgr = NULL;
  62. if ( m_pDeviceCollectionCache )
  63. m_pDeviceCollectionCache->Release();
  64. m_pDeviceCollectionCache = NULL;
  65. }
  66. /*-----------------------------------------------------------------------------
  67. * CWia::FinalContruct
  68. *
  69. * This creates the IWiaDevMgr that we need to perform our work.
  70. *--(samclem)-----------------------------------------------------------------*/
  71. STDMETHODIMP
  72. CWia::FinalConstruct()
  73. {
  74. HRESULT hr;
  75. WNDCLASSEX wc;
  76. // first we want to create our hidden event window
  77. if ( !GetClassInfoEx( _Module.GetModuleInstance(),
  78. CWIA_EVENTWNDCLS, &wc ) )
  79. {
  80. // we need to register this window
  81. ZeroMemory( &wc, sizeof( wc ) );
  82. wc.cbSize = sizeof( wc );
  83. wc.lpszClassName = CWIA_EVENTWNDCLS;
  84. wc.hInstance = _Module.GetModuleInstance();
  85. wc.lpfnWndProc = CWia::EventWndProc;
  86. if ( !RegisterClassEx( &wc ) )
  87. {
  88. TraceTag(( tagError, "unable to register window class" ));
  89. return E_FAIL;
  90. }
  91. }
  92. // now we can create our window
  93. m_hwndEvent = CreateWindowEx( 0,
  94. CWIA_EVENTWNDCLS,
  95. NULL,
  96. 0,
  97. CW_USEDEFAULT,
  98. CW_USEDEFAULT,
  99. 0,
  100. 0,
  101. NULL,
  102. NULL,
  103. _Module.GetModuleInstance(),
  104. this );
  105. if ( !m_hwndEvent )
  106. {
  107. TraceTag(( tagError, "Error creating the window" ));
  108. return E_FAIL;
  109. }
  110. hr = THR( CoCreateInstance( CLSID_WiaDevMgr,
  111. NULL,
  112. CLSCTX_SERVER,
  113. IID_IWiaDevMgr,
  114. reinterpret_cast<void**>(&m_pWiaDevMgr) ) );
  115. if ( FAILED( hr ) )
  116. {
  117. TraceTag(( tagError, "Failed to create WiaDevMgr instance" ));
  118. return hr;
  119. }
  120. /*
  121. * Setup the event callbacks that this object cares about. we
  122. * register both connect/disconnect on this object. since the
  123. * callback tells us the GUID of the event, we can add
  124. * more logic there. This is more efficent that having a
  125. * proxy object which handles the events.
  126. */
  127. hr = CComObject<CWiaEventCallback>::CreateInstance(&m_pCWiaEventCallback);
  128. if (SUCCEEDED(hr))
  129. {
  130. m_pCWiaEventCallback->AddRef();
  131. m_pCWiaEventCallback->setOwner(this);
  132. hr = m_pCWiaEventCallback->RegisterForConnectDisconnect(m_pWiaDevMgr);
  133. }
  134. else
  135. {
  136. TraceTag(( tagError, "Failed to create WiaEventCallback instance" ));
  137. return hr;
  138. }
  139. if ( FAILED( hr ) )
  140. {
  141. m_pWiaDevMgr->Release();
  142. m_pWiaDevMgr = NULL;
  143. }
  144. return hr;
  145. }
  146. /*-----------------------------------------------------------------------------
  147. * CWia::_DebugDialog
  148. *
  149. * This shows a debugging dialog if you are using the debug build, or simply
  150. * returns S_OK in the retail build.
  151. *
  152. * fWait: true if we want to wait for the dialog to finish in order to
  153. * return. Or false to return immediatly.
  154. *--(samclem)-----------------------------------------------------------------*/
  155. STDMETHODIMP
  156. CWia::_DebugDialog( BOOL fWait )
  157. {
  158. #if defined(_DEBUG)
  159. DoTracePointsDialog( fWait );
  160. #endif //defined(_DEBUG)
  161. return S_OK;
  162. }
  163. /*-----------------------------------------------------------------------------
  164. * CWia::get_Devices
  165. *
  166. * This returns a collection of the devices currently connected. this can
  167. * return an empty collection of there are no devices currently attached.
  168. *
  169. * This will cache the collection object that we create. This allows for
  170. * increased performace since we don't want to recreate it each time, that
  171. * requires called to an Out-Of-Proc server which is expensive. Therefore
  172. * since this method is called a lot, we cache the results in:
  173. *
  174. * m_pDeviceCollectionCache
  175. *
  176. * ppCol: out, a point to recieve the collection interface.
  177. *---------------------------------------------------------------------------*/
  178. STDMETHODIMP
  179. CWia::get_Devices( ICollection** ppCol )
  180. {
  181. HRESULT hr;
  182. CComObject<CCollection>* pCollection = NULL;
  183. IEnumWIA_DEV_INFO* pEnum = NULL;
  184. IWiaPropertyStorage* pWiaStg = NULL;
  185. IDispatch** rgpDispatch = NULL;
  186. CComObject<CWiaDeviceInfo>* pDevInfo = NULL;
  187. unsigned long cDevices = 0;
  188. unsigned long celtFetched = 0;
  189. unsigned long iDevice = 0;
  190. // validate our arguments
  191. if ( NULL == ppCol )
  192. return E_POINTER;
  193. *ppCol = NULL;
  194. // do we already have a collection cache? if so then we want
  195. // to use that.
  196. if ( m_pDeviceCollectionCache )
  197. {
  198. *ppCol = m_pDeviceCollectionCache;
  199. (*ppCol)->AddRef();
  200. return S_OK;
  201. }
  202. // first we need an instance of the collection
  203. hr = THR( CComObject<CCollection>::CreateInstance( &pCollection ) );
  204. if ( FAILED( hr ) )
  205. goto Cleanup;
  206. // are we vaild?
  207. Assert( m_pWiaDevMgr );
  208. hr = THR( m_pWiaDevMgr->EnumDeviceInfo( WIA_DEVINFO_ENUM_LOCAL, &pEnum ) );
  209. if ( FAILED(hr) )
  210. goto Cleanup;
  211. // we can now enumerate over the device info, if we have them
  212. // otherwise we don't want to do anything
  213. hr = THR( pEnum->GetCount( &cDevices ) );
  214. if ( FAILED( hr ) )
  215. goto Cleanup;
  216. if ( cDevices )
  217. {
  218. // we need storage for these items
  219. rgpDispatch = static_cast<IDispatch**>(CoTaskMemAlloc( cDevices * sizeof( IDispatch* ) ));
  220. if ( !rgpDispatch )
  221. {
  222. hr = E_OUTOFMEMORY;
  223. goto Cleanup;
  224. }
  225. ZeroMemory( rgpDispatch, sizeof( IDispatch* ) * cDevices );
  226. while ( SUCCEEDED( hr ) && hr != S_FALSE )
  227. {
  228. // release the old stream if it is hanging around
  229. if ( pWiaStg )
  230. pWiaStg->Release();
  231. pWiaStg = NULL;
  232. hr = THR( pEnum->Next( 1, &pWiaStg, &celtFetched ) );
  233. if ( SUCCEEDED( hr ) && hr == S_OK )
  234. {
  235. // we got this item successfully, so we need to create
  236. // a CWiaDeviceInfo and add it to our dispatch array
  237. Assert( celtFetched == 1 );
  238. hr = THR( CComObject<CWiaDeviceInfo>::CreateInstance( &pDevInfo ) );
  239. if ( FAILED( hr ) )
  240. goto Cleanup;
  241. hr = THR( pDevInfo->AttachTo( pWiaStg, static_cast<IWia*>(this) ) );
  242. if ( FAILED( hr ) )
  243. goto Cleanup;
  244. hr = THR( pDevInfo->QueryInterface( IID_IDispatch,
  245. reinterpret_cast<void**>(&rgpDispatch[iDevice++]) ) );
  246. if ( FAILED( hr ) )
  247. goto Cleanup;
  248. }
  249. }
  250. if( !pCollection->SetDispatchArray(rgpDispatch, cDevices))
  251. {
  252. hr = E_FAIL;
  253. goto Cleanup;
  254. }
  255. }
  256. // fill the out param with the proper value
  257. hr = THR( pCollection->QueryInterface( IID_ICollection,
  258. reinterpret_cast<void**>(&m_pDeviceCollectionCache) ) );
  259. if ( SUCCEEDED( hr ) )
  260. {
  261. *ppCol = m_pDeviceCollectionCache;
  262. (*ppCol)->AddRef();
  263. }
  264. Cleanup:
  265. if ( pEnum )
  266. pEnum->Release();
  267. if ( pWiaStg )
  268. pWiaStg->Release();
  269. if ( FAILED( hr ) )
  270. {
  271. if ( m_pDeviceCollectionCache )
  272. m_pDeviceCollectionCache->Release();
  273. m_pDeviceCollectionCache = NULL;
  274. if ( pCollection )
  275. delete pCollection;
  276. if ( rgpDispatch )
  277. {
  278. for ( unsigned long i = 0; i < cDevices; i++ )
  279. if ( rgpDispatch[i] )
  280. rgpDispatch[i]->Release();
  281. CoTaskMemFree( rgpDispatch );
  282. }
  283. }
  284. return hr;
  285. }
  286. /*-----------------------------------------------------------------------------
  287. * CWia::Create [IWia]
  288. *
  289. * The handles creating a device. This will create a dispatch object which
  290. * can represent the device.
  291. *
  292. * This can take several different paramaters to determine what device to
  293. * create.
  294. *
  295. * VT_UNKNOWN, VT_DISPATCH --> An IWiaDeviceInfo dispatch object which
  296. * holds information about the device.
  297. * VT_BSTR --> The DeviceID of the device to create
  298. * VT_I4 --> The index of the device in the Devices()
  299. * collection.
  300. * VT_xx --> Not currently supported.
  301. *
  302. * pvaDevice: A variant which contains the device to create
  303. * ppDevice: Out, recieves the newly created device object
  304. *--(samclem)-----------------------------------------------------------------*/
  305. STDMETHODIMP
  306. CWia::Create( VARIANT* pvaDevice, IWiaDispatchItem** ppDevice )
  307. {
  308. HRESULT hr = E_NOTIMPL;
  309. IWiaDeviceInfo* pDeviceInfo = NULL;
  310. ICollection* pCollection = NULL;
  311. IDispatch* pDispatch = NULL;
  312. BSTR bstrDeviceId = NULL;
  313. IWiaItem* pWiaItem = NULL;
  314. CComObject<CWiaItem>* pItem = NULL;
  315. CWiaCacheManager* pCache = CWiaCacheManager::GetInstance();
  316. if ( !pvaDevice || !ppDevice )
  317. return E_POINTER;
  318. //BUG (Aug, 18) samclem:
  319. //
  320. // make sure that the variant is the proper type, or at least
  321. // one that we want to deal with. this isn't perfect and probally
  322. // be revistied at some point in life. this will miss handle things
  323. // like:
  324. //
  325. // camera = wiaObject.create( "0" );
  326. //
  327. // If nothing was passed in, we end up showing the selection UI.
  328. // Use an empty BSTR to indicate this. Note that script can also
  329. // pass an empty string ("") to get the selection UI.
  330. if ( pvaDevice->vt == VT_EMPTY || pvaDevice->vt == VT_NULL ||
  331. ( pvaDevice->vt == VT_ERROR && pvaDevice->scode == DISP_E_PARAMNOTFOUND ) )
  332. {
  333. pvaDevice->vt = VT_BSTR;
  334. pvaDevice->bstrVal = NULL;
  335. }
  336. if ( pvaDevice->vt != VT_DISPATCH &&
  337. pvaDevice->vt != VT_UNKNOWN &&
  338. pvaDevice->vt != VT_BSTR )
  339. {
  340. hr = THR( VariantChangeType( pvaDevice, pvaDevice, 0, VT_I4 ) );
  341. if ( FAILED( hr ) )
  342. return hr;
  343. }
  344. if ( pvaDevice->vt == VT_DISPATCH )
  345. {
  346. // pvaDevice->pdispVal == NULL if we're supposed to show WIA's device
  347. // selection, so only QI if pdispVal is valid.
  348. if (pvaDevice->pdispVal != NULL)
  349. {
  350. hr = THR( pvaDevice->pdispVal->QueryInterface( IID_IWiaDeviceInfo,
  351. reinterpret_cast<void**>(&pDeviceInfo) ) );
  352. if ( FAILED( hr ) )
  353. goto Cleanup;
  354. }
  355. }
  356. else if ( pvaDevice->vt == VT_UNKNOWN )
  357. {
  358. hr = THR( pvaDevice->punkVal->QueryInterface( IID_IWiaDeviceInfo,
  359. reinterpret_cast<void**>(&pDeviceInfo) ) );
  360. if ( FAILED( hr ) )
  361. goto Cleanup;
  362. }
  363. else if ( pvaDevice->vt == VT_BSTR )
  364. {
  365. if ( pvaDevice->bstrVal && *pvaDevice->bstrVal )
  366. bstrDeviceId = SysAllocString( pvaDevice->bstrVal );
  367. }
  368. else if ( pvaDevice->vt == VT_I4 )
  369. {
  370. hr = THR( get_Devices( &pCollection ) );
  371. if ( FAILED( hr ) )
  372. goto Cleanup;
  373. // get the item with that index
  374. hr = THR( pCollection->get_Item( pvaDevice->lVal, &pDispatch ) );
  375. if ( FAILED( hr ) )
  376. goto Cleanup;
  377. // did we get an item, if we didn't then we were out of
  378. // range in our collection would return a null dispatch
  379. //BUG (Aug, 18) samclem: Perhaps CCollection::get_Item() should
  380. // return false in this case.
  381. if ( !pDispatch )
  382. goto Cleanup;
  383. hr = THR( pDispatch->QueryInterface( IID_IWiaDeviceInfo,
  384. reinterpret_cast<void**>(&pDeviceInfo) ) );
  385. if ( FAILED( hr ) )
  386. goto Cleanup;
  387. }
  388. else
  389. goto Cleanup;
  390. // if we have a valid IWiaDeviceInfo then we can query that for
  391. // the bstr to create.
  392. if ( pDeviceInfo )
  393. {
  394. hr = THR( pDeviceInfo->get_Id( &bstrDeviceId ) );
  395. if ( FAILED( hr ) )
  396. goto Cleanup;
  397. }
  398. // either we call CreateDevice from the WIA device manager, or we
  399. // bring up WIA's device selection UI to return a IWiaItem interface.
  400. if (bstrDeviceId != NULL)
  401. {
  402. if ( !pCache->GetDevice( bstrDeviceId, &pWiaItem ) )
  403. {
  404. // at this point we should have a valid device id to create
  405. // our device from
  406. hr = THR( m_pWiaDevMgr->CreateDevice( bstrDeviceId, &pWiaItem ) );
  407. if ( FAILED( hr ) )
  408. goto Cleanup;
  409. }
  410. }
  411. else
  412. {
  413. // bring up the selection UI
  414. hr = THR( m_pWiaDevMgr->SelectDeviceDlg(NULL,
  415. 0,
  416. 0,
  417. &bstrDeviceId,
  418. &pWiaItem ) );
  419. // have to check against S_OK since cancel produces S_FALSE
  420. if ( hr != S_OK )
  421. goto Cleanup;
  422. }
  423. // add our created device to our cache so that we don't have
  424. // to create it again.
  425. // NOTE: We effectively disable the device list cache
  426. // by not adding the device here. The cache doesn't really buy us
  427. // anything since the driver caches thumbnails, and you shouldn't cache
  428. // devices, so we simply ignore it here.
  429. //pCache->AddDevice( bstrDeviceId, pWiaItem );
  430. hr = THR( CComObject<CWiaItem>::CreateInstance( &pItem ) );
  431. if ( FAILED( hr ) )
  432. goto Cleanup;
  433. hr = THR( pItem->AttachTo( this, pWiaItem ) );
  434. if ( FAILED( hr ) )
  435. goto Cleanup;
  436. hr = THR( pItem->QueryInterface( IID_IDispatch,
  437. reinterpret_cast<void**>(ppDevice) ) );
  438. Cleanup:
  439. if ( pItem && FAILED( hr ) )
  440. delete pItem;
  441. if ( pDispatch )
  442. pDispatch->Release();
  443. if ( pWiaItem )
  444. pWiaItem->Release();
  445. if ( pDeviceInfo )
  446. pDeviceInfo->Release();
  447. if ( pCollection )
  448. pCollection->Release();
  449. if ( bstrDeviceId )
  450. SysFreeString( bstrDeviceId );
  451. return hr;
  452. }
  453. /*-----------------------------------------------------------------------------
  454. * CWia::ImageEventCallback [IWiaEventCallback]
  455. *
  456. * This is called by Wia when something interesting happens. this is used to
  457. * fire these events off to scripting for them to do do something.
  458. *
  459. * pEventGUID: the GUID of the event which happend
  460. * bstrEventDescription: A string description of the event?? [not in docs]
  461. * bstrDeviceID: The device id of the device?? [not in docs]
  462. * bstrDeviceDescription: The description of the device?? [nid]
  463. * dwDeviceType: ?? [nid]
  464. * pulEventType: ?? [nid]
  465. * Reserved: Reserved (0)
  466. *---------------------------------------------------------------------------*/
  467. STDMETHODIMP
  468. CWia::ImageEventCallback( const GUID* pEventGUID, BSTR bstrEventDescription,
  469. BSTR bstrDeviceID, BSTR bstrDeviceDescription, DWORD dwDeviceType,
  470. BSTR bstrFullItemName,
  471. /*in,out*/ ULONG* pulEventType, ULONG Reserved )
  472. {
  473. #if _DEBUG
  474. USES_CONVERSION;
  475. #endif
  476. if ( m_pDeviceCollectionCache )
  477. {
  478. m_pDeviceCollectionCache->Release();
  479. m_pDeviceCollectionCache = NULL;
  480. }
  481. // we are listening to both connections, and disconnections so we need
  482. // to decice what is happening
  483. //TODO: we want to handle these using the window message not by directly
  484. // sending them through here.
  485. if ( *pEventGUID == WIA_EVENT_DEVICE_CONNECTED )
  486. {
  487. TraceTag((0, "firing event connected: %s", OLE2A( bstrDeviceID )));
  488. Fire_OnDeviceConnected( bstrDeviceID );
  489. }
  490. else if ( *pEventGUID == WIA_EVENT_DEVICE_DISCONNECTED )
  491. {
  492. TraceTag((0, "firing event disconnected: %s", OLE2A( bstrDeviceID )));
  493. CWiaCacheManager::GetInstance()->RemoveDevice( bstrDeviceID );
  494. Fire_OnDeviceDisconnected( bstrDeviceID );
  495. }
  496. else
  497. {
  498. TraceTag((0, "ImageEventCallback -> unexpected event type" ) );
  499. return E_UNEXPECTED;
  500. }
  501. return S_OK;
  502. }
  503. /*-----------------------------------------------------------------------------
  504. * CWia::EventWndProc
  505. *
  506. * This is the window proc that is used for the hidden window which
  507. * handles posting the events. This recieves messages that should be posted
  508. * back to the client. This ensures that the notifications get posted back
  509. * from the expected thread.
  510. *--(samclem)-----------------------------------------------------------------*/
  511. LRESULT CALLBACK CWia::EventWndProc( HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
  512. {
  513. CWia* pWia = reinterpret_cast<CWia*>(GetProp( hwnd, CWIA_WNDPROP ));
  514. switch ( iMsg )
  515. {
  516. case WM_CREATE:
  517. {
  518. LPCREATESTRUCT pcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
  519. pWia = reinterpret_cast<CWia*>(pcs->lpCreateParams);
  520. if ( !pWia )
  521. return -1;
  522. if ( !SetProp( hwnd, CWIA_WNDPROP, reinterpret_cast<HANDLE>(pWia) ) )
  523. return -1;
  524. }
  525. return 0;
  526. case WM_DESTROY:
  527. {
  528. if ( pWia )
  529. RemoveProp( hwnd, CWIA_WNDPROP );
  530. }
  531. return 0;
  532. }
  533. // since our custom window messages are obtained using
  534. // RegisterWindowMessage(), they are not constant and therfore
  535. // can't be processed in a switch() statement.
  536. if ( WEM_TRANSFERCOMPLETE == iMsg )
  537. {
  538. if ( pWia )
  539. {
  540. TraceTag((0, "EventWndProc - firing onTransferComplete"));
  541. pWia->Fire_OnTransferComplete(
  542. reinterpret_cast<IDispatch*>(wParam),
  543. reinterpret_cast<BSTR>(lParam) );
  544. }
  545. if ( lParam )
  546. {
  547. SysFreeString(reinterpret_cast<BSTR>(lParam));
  548. lParam = 0;
  549. }
  550. return 0;
  551. }
  552. return DefWindowProc( hwnd, iMsg, wParam, lParam );
  553. }
  554. /*
  555. *
  556. *
  557. */
  558. CSafeWia::CSafeWia() :
  559. m_pWiaDevMgr( NULL ),
  560. m_pWiaDevConEvent( NULL ),
  561. m_pWiaDevDisEvent( NULL ),
  562. m_pDeviceCollectionCache( NULL ),
  563. m_SafeInstance(TRUE)
  564. {
  565. TRACK_OBJECT( "CSafeWia" );
  566. }
  567. STDMETHODIMP_(void)
  568. CSafeWia::FinalRelease()
  569. {
  570. if ( m_hwndEvent )
  571. DestroyWindow( m_hwndEvent );
  572. if ( m_pWiaDevMgr )
  573. m_pWiaDevMgr->Release();
  574. m_pWiaDevMgr = NULL;
  575. if ( m_pWiaDevConEvent )
  576. m_pWiaDevConEvent->Release();
  577. m_pWiaDevConEvent = NULL;
  578. if ( m_pWiaDevDisEvent )
  579. m_pWiaDevDisEvent->Release();
  580. m_pWiaDevDisEvent = NULL;
  581. if ( m_pDeviceCollectionCache )
  582. m_pDeviceCollectionCache->Release();
  583. m_pDeviceCollectionCache = NULL;
  584. }
  585. /*-----------------------------------------------------------------------------
  586. * CSafeWia::FinalContruct
  587. *
  588. * This creates the IWiaDevMgr that we need to perform our work.
  589. *--(samclem)-----------------------------------------------------------------*/
  590. STDMETHODIMP
  591. CSafeWia::FinalConstruct()
  592. {
  593. HRESULT hr;
  594. hr = THR( CoCreateInstance( CLSID_WiaDevMgr,
  595. NULL,
  596. CLSCTX_SERVER,
  597. IID_IWiaDevMgr,
  598. reinterpret_cast<void**>(&m_pWiaDevMgr) ) );
  599. if ( FAILED( hr ) )
  600. {
  601. TraceTag(( tagError, "Failed to create WiaDevMgr instance" ));
  602. return hr;
  603. }
  604. if ( FAILED( hr ) )
  605. {
  606. if ( m_pWiaDevConEvent )
  607. m_pWiaDevConEvent->Release();
  608. m_pWiaDevConEvent = NULL;
  609. if ( m_pWiaDevDisEvent )
  610. m_pWiaDevDisEvent->Release();
  611. m_pWiaDevDisEvent = NULL;
  612. m_pWiaDevMgr->Release();
  613. m_pWiaDevMgr = NULL;
  614. }
  615. return hr;
  616. }
  617. /*-----------------------------------------------------------------------------
  618. * CSafeWia::_DebugDialog
  619. *
  620. * This shows a debugging dialog if you are using the debug build, or simply
  621. * returns S_OK in the retail build.
  622. *
  623. * fWait: true if we want to wait for the dialog to finish in order to
  624. * return. Or false to return immediatly.
  625. *--(samclem)-----------------------------------------------------------------*/
  626. STDMETHODIMP
  627. CSafeWia::_DebugDialog( BOOL fWait )
  628. {
  629. return S_OK;
  630. }
  631. /*-----------------------------------------------------------------------------
  632. * CSafeWia::get_Devices
  633. *
  634. * This returns a collection of the devices currently connected. this can
  635. * return an empty collection of there are no devices currently attached.
  636. *
  637. * This will cache the collection object that we create. This allows for
  638. * increased performace since we don't want to recreate it each time, that
  639. * requires called to an Out-Of-Proc server which is expensive. Therefore
  640. * since this method is called a lot, we cache the results in:
  641. *
  642. * m_pDeviceCollectionCache
  643. *
  644. * ppCol: out, a point to recieve the collection interface.
  645. *---------------------------------------------------------------------------*/
  646. STDMETHODIMP
  647. CSafeWia::get_Devices( ICollection** ppCol )
  648. {
  649. HRESULT hr;
  650. CComObject<CCollection>* pCollection = NULL;
  651. IEnumWIA_DEV_INFO* pEnum = NULL;
  652. IWiaPropertyStorage* pWiaStg = NULL;
  653. IDispatch** rgpDispatch = NULL;
  654. CComObject<CWiaDeviceInfo>* pDevInfo = NULL;
  655. unsigned long cDevices = 0;
  656. unsigned long celtFetched = 0;
  657. unsigned long iDevice = 0;
  658. // validate our arguments
  659. if ( NULL == ppCol )
  660. return E_POINTER;
  661. *ppCol = NULL;
  662. // do we already have a collection cache? if so then we want
  663. // to use that.
  664. if ( m_pDeviceCollectionCache )
  665. {
  666. *ppCol = m_pDeviceCollectionCache;
  667. (*ppCol)->AddRef();
  668. return S_OK;
  669. }
  670. // first we need an instance of the collection
  671. hr = THR( CComObject<CCollection>::CreateInstance( &pCollection ) );
  672. if ( FAILED( hr ) )
  673. goto Cleanup;
  674. // are we vaild?
  675. Assert( m_pWiaDevMgr );
  676. hr = THR( m_pWiaDevMgr->EnumDeviceInfo( WIA_DEVINFO_ENUM_LOCAL, &pEnum ) );
  677. if ( FAILED(hr) )
  678. goto Cleanup;
  679. // we can now enumerate over the device info, if we have them
  680. // otherwise we don't want to do anything
  681. hr = THR( pEnum->GetCount( &cDevices ) );
  682. if ( FAILED( hr ) )
  683. goto Cleanup;
  684. if ( cDevices )
  685. {
  686. // we need storage for these items
  687. rgpDispatch = static_cast<IDispatch**>(CoTaskMemAlloc( cDevices * sizeof( IDispatch* ) ));
  688. if ( !rgpDispatch )
  689. {
  690. hr = E_OUTOFMEMORY;
  691. goto Cleanup;
  692. }
  693. ZeroMemory( rgpDispatch, sizeof( IDispatch* ) * cDevices );
  694. while ( SUCCEEDED( hr ) && hr != S_FALSE )
  695. {
  696. // release the old stream if it is hanging around
  697. if ( pWiaStg )
  698. pWiaStg->Release();
  699. hr = THR( pEnum->Next( 1, &pWiaStg, &celtFetched ) );
  700. if ( SUCCEEDED( hr ) && hr == S_OK )
  701. {
  702. // we got this item successfully, so we need to create
  703. // a CWiaDeviceInfo and add it to our dispatch array
  704. Assert( celtFetched == 1 );
  705. hr = THR( CComObject<CWiaDeviceInfo>::CreateInstance( &pDevInfo ) );
  706. if ( FAILED( hr ) )
  707. goto Cleanup;
  708. hr = THR( pDevInfo->AttachTo( pWiaStg, static_cast<IWia*>(this) ) );
  709. if ( FAILED( hr ) )
  710. goto Cleanup;
  711. hr = THR( pDevInfo->QueryInterface( IID_IDispatch,
  712. reinterpret_cast<void**>(&rgpDispatch[iDevice++]) ) );
  713. if ( FAILED( hr ) )
  714. goto Cleanup;
  715. }
  716. }
  717. if( !pCollection->SetDispatchArray(rgpDispatch, cDevices))
  718. {
  719. hr = E_FAIL;
  720. goto Cleanup;
  721. }
  722. }
  723. // fill the out param with the proper value
  724. hr = THR( pCollection->QueryInterface( IID_ICollection,
  725. reinterpret_cast<void**>(&m_pDeviceCollectionCache) ) );
  726. if ( SUCCEEDED( hr ) )
  727. {
  728. *ppCol = m_pDeviceCollectionCache;
  729. (*ppCol)->AddRef();
  730. }
  731. Cleanup:
  732. if ( pEnum )
  733. pEnum->Release();
  734. if ( pWiaStg )
  735. pWiaStg->Release();
  736. if ( FAILED( hr ) )
  737. {
  738. if ( m_pDeviceCollectionCache )
  739. m_pDeviceCollectionCache->Release();
  740. m_pDeviceCollectionCache = NULL;
  741. if ( pCollection )
  742. delete pCollection;
  743. if ( rgpDispatch )
  744. {
  745. for ( unsigned long i = 0; i < cDevices; i++ )
  746. if ( rgpDispatch[i] )
  747. rgpDispatch[i]->Release();
  748. CoTaskMemFree( rgpDispatch );
  749. }
  750. }
  751. return hr;
  752. }
  753. STDMETHODIMP
  754. CSafeWia::Create( VARIANT* pvaDevice, IWiaDispatchItem** ppDevice )
  755. {
  756. HRESULT hr = E_NOTIMPL;
  757. #ifdef MAXDEBUG
  758. ::OutputDebugString(TEXT("WIA script object: CSafeWia::Create rejected\n\r "));
  759. #endif
  760. return hr;
  761. }
  762. STDMETHODIMP
  763. CSafeWia::ImageEventCallback( const GUID* pEventGUID, BSTR bstrEventDescription,
  764. BSTR bstrDeviceID, BSTR bstrDeviceDescription, DWORD dwDeviceType,
  765. BSTR bstrFullItemName,
  766. /*in,out*/ ULONG* pulEventType, ULONG Reserved )
  767. {
  768. return S_OK;
  769. }
  770. LRESULT CALLBACK CSafeWia::EventWndProc( HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
  771. {
  772. return DefWindowProc( hwnd, iMsg, wParam, lParam );
  773. }