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.

715 lines
20 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1999-2000
  4. *
  5. * TITLE: WiaLink.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: OrenR
  10. *
  11. * DATE: 2000/11/06
  12. *
  13. * DESCRIPTION: Establishes link between WiaVideo and the WiaVideo Driver
  14. *
  15. *****************************************************************************/
  16. #include <precomp.h>
  17. #pragma hdrstop
  18. //
  19. // These generate 2 event names which are created in the wia video
  20. // driver found in wia\drivers\video\usd. If you must change
  21. // these, they MUST change in the video driver as well. Be warned,
  22. // changing these without knowing what you are doing will lead to problems.
  23. //
  24. const TCHAR* EVENT_PREFIX_GLOBAL = TEXT("Global\\");
  25. const TCHAR* EVENT_SUFFIX_TAKE_PICTURE = TEXT("_TAKE_PICTURE");
  26. const TCHAR* EVENT_SUFFIX_PICTURE_READY = TEXT("_PICTURE_READY");
  27. const UINT THREAD_EXIT_TIMEOUT = 1000 * 5; // 5 seconds
  28. ///////////////////////////////
  29. // CWiaLink Constructor
  30. //
  31. CWiaLink::CWiaLink() :
  32. m_pWiaVideo(NULL),
  33. m_hTakePictureEvent(NULL),
  34. m_hPictureReadyEvent(NULL),
  35. m_hTakePictureThread(NULL),
  36. m_bExitThread(FALSE),
  37. m_bEnabled(FALSE),
  38. m_dwWiaItemCookie(0),
  39. m_dwPropertyStorageCookie(0)
  40. {
  41. DBG_FN("CWiaLink::CWiaLink");
  42. }
  43. ///////////////////////////////
  44. // CWiaLink Constructor
  45. //
  46. CWiaLink::~CWiaLink()
  47. {
  48. DBG_FN("CWiaLink::~CWiaLink");
  49. if (m_bEnabled)
  50. {
  51. Term();
  52. }
  53. }
  54. ///////////////////////////////
  55. // Init
  56. //
  57. HRESULT CWiaLink::Init(const CSimpleString *pstrWiaDeviceID,
  58. CWiaVideo *pWiaVideo)
  59. {
  60. DBG_FN("CWiaLink::Init");
  61. HRESULT hr = S_OK;
  62. CComPtr<IWiaDevMgr> pDevMgr;
  63. CComPtr<IWiaItem> pRootItem;
  64. ASSERT(pstrWiaDeviceID != NULL);
  65. ASSERT(pWiaVideo != NULL);
  66. if ((pstrWiaDeviceID == NULL) ||
  67. (pWiaVideo == NULL))
  68. {
  69. hr = E_POINTER;
  70. CHECK_S_OK2(hr, ("CWiaLink::Init, received NULL params"));
  71. return hr;
  72. }
  73. m_pWiaVideo = pWiaVideo;
  74. m_strDeviceID = *pstrWiaDeviceID;
  75. if (hr == S_OK)
  76. {
  77. hr = CAccessLock::Init(&m_csLock);
  78. }
  79. //
  80. // Create the WiaDevMgr so we can create the Wia Root Item
  81. //
  82. if (hr == S_OK)
  83. {
  84. hr = CWiaUtil::CreateWiaDevMgr(&pDevMgr);
  85. CHECK_S_OK2(hr, ("CWiaLink::Init, failed to Create WiaDevMgr"));
  86. }
  87. //
  88. // This ensures that the WIA Video Driver is initialized and in the
  89. // correct state.
  90. //
  91. if (hr == S_OK)
  92. {
  93. hr = CWiaUtil::CreateRootItem(pDevMgr, pstrWiaDeviceID, &pRootItem);
  94. CHECK_S_OK2(hr, ("CWiaLink::Init, failed to create the WIA "
  95. "Device Root Item for WIA Device ID '%ls'",
  96. CSimpleStringConvert::WideString(*pstrWiaDeviceID)));
  97. }
  98. //
  99. // Create a Global Interface Table object. This will enable us to use
  100. // the root item (IWiaItem pRootItem) above across any thread we wish.
  101. // This is required because if we receive async images (as a result of a
  102. // hardware button event), a random thread will be calling the
  103. // WriteMultiple function on the IWiaItem object.
  104. //
  105. if (hr == S_OK)
  106. {
  107. hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
  108. NULL,
  109. CLSCTX_INPROC_SERVER,
  110. IID_IGlobalInterfaceTable,
  111. (void **)&m_pGIT);
  112. CHECK_S_OK2(hr, ("CWiaUtil::Init, failed to create "
  113. "StdGlobalInterfaceTable used to use the IWiaItem "
  114. "root device item across multiple threads"));
  115. }
  116. //
  117. // Register the WiaItem pointer in a apartment neutral way.
  118. //
  119. if (hr == S_OK)
  120. {
  121. //
  122. // This will AddRef the pointer so no need to add a reference
  123. // to it.
  124. //
  125. hr = m_pGIT->RegisterInterfaceInGlobal(pRootItem,
  126. IID_IWiaItem,
  127. &m_dwWiaItemCookie);
  128. }
  129. //
  130. // Register the IWiaPropertyStorage pointer in an apartment neutral way.
  131. //
  132. if (hr == S_OK)
  133. {
  134. CComQIPtr<IWiaPropertyStorage, &IID_IWiaPropertyStorage>
  135. pProp(pRootItem);
  136. if (pProp)
  137. {
  138. hr = m_pGIT->RegisterInterfaceInGlobal(
  139. pProp,
  140. IID_IPropertyStorage,
  141. &m_dwPropertyStorageCookie);
  142. }
  143. }
  144. if (hr == S_OK)
  145. {
  146. m_bEnabled = TRUE;
  147. }
  148. //
  149. // If we failed in initializing, cleanup anything that we created
  150. //
  151. if (hr != S_OK)
  152. {
  153. Term();
  154. }
  155. return hr;
  156. }
  157. ///////////////////////////////
  158. // Term
  159. //
  160. HRESULT CWiaLink::Term()
  161. {
  162. HRESULT hr = S_OK;
  163. DBG_FN("CWiaLink::Term");
  164. StopMonitoring();
  165. m_strDeviceID = TEXT("");
  166. m_bEnabled = FALSE;
  167. if (m_pGIT)
  168. {
  169. CAccessLock Lock(&m_csLock);
  170. hr = m_pGIT->RevokeInterfaceFromGlobal(m_dwWiaItemCookie);
  171. CHECK_S_OK2(hr,
  172. ("CWiaLink::Term, failed to RevokeInterfaceFromGlobal "
  173. "for WiaItemCookie = '%lu'",
  174. m_dwWiaItemCookie));
  175. hr = m_pGIT->RevokeInterfaceFromGlobal(m_dwPropertyStorageCookie);
  176. CHECK_S_OK2(hr,
  177. ("CWiaLink::Term, failed to RevokeInterfaceFromGlobal "
  178. "for PropertyStorageCookie = '%lu'",
  179. m_dwPropertyStorageCookie));
  180. }
  181. m_pGIT = NULL;
  182. m_dwWiaItemCookie = 0;
  183. m_dwPropertyStorageCookie = 0;
  184. CAccessLock::Term(&m_csLock);
  185. return hr;
  186. }
  187. ///////////////////////////////
  188. // StartMonitoring
  189. //
  190. HRESULT CWiaLink::StartMonitoring()
  191. {
  192. HRESULT hr = S_OK;
  193. if (m_hTakePictureEvent != NULL)
  194. {
  195. DBG_WRN(("CWiaLink::StartMonitoring was called but it is already "
  196. "monitoring TAKE_PICTURE events. Why was it called again, "
  197. "prior to 'StopMonitoring' being called?"));
  198. return S_OK;
  199. }
  200. m_bExitThread = FALSE;
  201. //
  202. // create the event that will be opened by the WIA video driver.
  203. //
  204. if (hr == S_OK)
  205. {
  206. hr = CreateWiaEvents(&m_hTakePictureEvent,
  207. &m_hPictureReadyEvent);
  208. CHECK_S_OK2(hr,
  209. ("CWiaLink::Init, failed to Create WIA Take "
  210. "Picture Events"));
  211. }
  212. //
  213. // Tell the WIA driver to enable the TAKE_PICTURE command.
  214. //
  215. if (hr == S_OK)
  216. {
  217. CComPtr<IWiaItem> pRootItem;
  218. hr = GetDevice(&pRootItem);
  219. if (hr == S_OK)
  220. {
  221. CComPtr<IWiaItem> pUnused;
  222. hr = pRootItem->DeviceCommand(0,
  223. &WIA_CMD_ENABLE_TAKE_PICTURE,
  224. &pUnused);
  225. CHECK_S_OK2(hr, ("CWiaLink::StartMonitoring, failed to send "
  226. "ENABLE_TAKE_PICTURE command to Wia Video "
  227. "Driver"));
  228. }
  229. }
  230. // Start the thread, waiting on the "TakePicture" event.
  231. if (hr == S_OK)
  232. {
  233. DWORD dwThreadID = 0;
  234. DBG_TRC(("CWiaLink::Init, creating TAKE_PICTURE thread..."));
  235. m_hTakePictureThread = CreateThread(NULL,
  236. 0,
  237. CWiaLink::StartThreadProc,
  238. reinterpret_cast<void*>(this),
  239. 0,
  240. &dwThreadID);
  241. if (m_hTakePictureThread == NULL)
  242. {
  243. hr = E_FAIL;
  244. CHECK_S_OK2(hr,
  245. ("CWiaLink::Init, failed to create thread to wait "
  246. "for take picture events from the wia video "
  247. "driver, last error = %lu", GetLastError()));
  248. }
  249. }
  250. return hr;
  251. }
  252. ///////////////////////////////
  253. // StopMonitoring
  254. //
  255. HRESULT CWiaLink::StopMonitoring()
  256. {
  257. HRESULT hr = S_OK;
  258. if (m_hTakePictureThread)
  259. {
  260. DWORD dwThreadResult = 0;
  261. m_bExitThread = TRUE;
  262. SetEvent(m_hTakePictureEvent);
  263. dwThreadResult = WaitForSingleObject(m_hTakePictureThread,
  264. THREAD_EXIT_TIMEOUT);
  265. if (dwThreadResult != WAIT_OBJECT_0)
  266. {
  267. DBG_WRN(("CWiaLink::Term, timed out waiting for take picture "
  268. "thread to terminate, continuing anyway..."));
  269. }
  270. //
  271. // Tell the WIA driver to disable the TAKE_PICTURE command.
  272. //
  273. if (m_dwWiaItemCookie)
  274. {
  275. CComPtr<IWiaItem> pRootItem;
  276. hr = GetDevice(&pRootItem);
  277. if (hr == S_OK)
  278. {
  279. CComPtr<IWiaItem> pUnused;
  280. hr = pRootItem->DeviceCommand(0,
  281. &WIA_CMD_DISABLE_TAKE_PICTURE,
  282. &pUnused);
  283. CHECK_S_OK2(hr, ("CWiaLink::StopMonitoring, failed to send "
  284. "DISABLE_TAKE_PICTURE command to Wia Video "
  285. "Driver"));
  286. }
  287. }
  288. }
  289. //
  290. // Close the Take Picture Event Handles.
  291. //
  292. if (m_hTakePictureEvent)
  293. {
  294. CloseHandle(m_hTakePictureEvent);
  295. m_hTakePictureEvent = NULL;
  296. }
  297. if (m_hPictureReadyEvent)
  298. {
  299. CloseHandle(m_hPictureReadyEvent);
  300. m_hPictureReadyEvent = NULL;
  301. }
  302. if (m_hTakePictureThread)
  303. {
  304. CloseHandle(m_hTakePictureThread);
  305. m_hTakePictureThread = NULL;
  306. }
  307. return hr;
  308. }
  309. ///////////////////////////////
  310. // CreateWiaEvents
  311. //
  312. HRESULT CWiaLink::CreateWiaEvents(HANDLE *phTakePictureEvent,
  313. HANDLE *phPictureReadyEvent)
  314. {
  315. DBG_FN("CWiaLink::CreateWiaEvents");
  316. HRESULT hr = S_OK;
  317. CSimpleString strTakePictureEvent;
  318. CSimpleString strPictureReadyEvent;
  319. ASSERT(phTakePictureEvent != NULL);
  320. ASSERT(phPictureReadyEvent != NULL);
  321. if ((phTakePictureEvent == NULL) ||
  322. (phPictureReadyEvent == NULL))
  323. {
  324. hr = E_POINTER;
  325. CHECK_S_OK2(hr, ("CWiaLink::CreateWiaEvents received a NULL Param"));
  326. }
  327. if (hr == S_OK)
  328. {
  329. INT iPosition = 0;
  330. CSimpleString strModifiedDeviceID;
  331. // Change the device ID from {6B...}\xxxx, to {6B...}_xxxx
  332. iPosition = m_strDeviceID.ReverseFind('\\');
  333. strModifiedDeviceID = m_strDeviceID.MakeUpper();
  334. strModifiedDeviceID.SetAt(iPosition, '_');
  335. //
  336. // Generate the event names. These names contain the Device ID in
  337. // them so that they are unique across devices.
  338. //
  339. strTakePictureEvent = EVENT_PREFIX_GLOBAL;
  340. strTakePictureEvent += strModifiedDeviceID;
  341. strTakePictureEvent += EVENT_SUFFIX_TAKE_PICTURE;
  342. strPictureReadyEvent = EVENT_PREFIX_GLOBAL;
  343. strPictureReadyEvent += strModifiedDeviceID;
  344. strPictureReadyEvent += EVENT_SUFFIX_PICTURE_READY;
  345. }
  346. if (hr == S_OK)
  347. {
  348. *phTakePictureEvent = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE,
  349. FALSE,
  350. strTakePictureEvent);
  351. if (*phTakePictureEvent == NULL)
  352. {
  353. hr = E_FAIL;
  354. CHECK_S_OK2(hr,
  355. ("CWiaLink::CreateWiaEvents, failed to create the "
  356. "WIA event '%s', last error = %lu",
  357. strTakePictureEvent.String(), GetLastError()));
  358. }
  359. else
  360. {
  361. DBG_TRC(("CWiaLink::CreateWiaEvents, created event '%ls'",
  362. strTakePictureEvent.String()));
  363. }
  364. }
  365. if (hr == S_OK)
  366. {
  367. *phPictureReadyEvent = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE,
  368. FALSE,
  369. strPictureReadyEvent);
  370. if (*phPictureReadyEvent == NULL)
  371. {
  372. hr = E_FAIL;
  373. CHECK_S_OK2(hr,
  374. ("CWiaLink::CreateWiaEvents, failed to create the "
  375. "WIA event '%s', last error = %lu",
  376. strPictureReadyEvent.String(), GetLastError()));
  377. }
  378. else
  379. {
  380. DBG_TRC(("CWiaLink::CreateWiaEvents, created event '%ls'",
  381. strPictureReadyEvent.String()));
  382. }
  383. }
  384. return hr;
  385. }
  386. ///////////////////////////////
  387. // ThreadProc
  388. //
  389. HRESULT CWiaLink::ThreadProc(void *pArgs)
  390. {
  391. DBG_FN("CWiaLink::ThreadProc");
  392. HRESULT hr = S_OK;
  393. DBG_TRC(("CWiaLink::ThreadProc, starting TakePicture thread..."));
  394. while (!m_bExitThread)
  395. {
  396. DWORD dwResult = 0;
  397. //
  398. // Reset our HRESULT. Just because we may have failed before,
  399. // does not mean we will fail again.
  400. //
  401. hr = S_OK;
  402. dwResult = WaitForSingleObject(m_hTakePictureEvent, INFINITE);
  403. if (!m_bExitThread)
  404. {
  405. //
  406. // The only error we can get from WaitForSingle object is
  407. // something unexpected, since we can't timeout since we
  408. // are waiting infinitely.
  409. //
  410. if (dwResult != WAIT_OBJECT_0)
  411. {
  412. hr = E_FAIL;
  413. m_bExitThread = TRUE;
  414. CHECK_S_OK2(hr,
  415. ("CWiaLink::ThreadProc, received '%lu' result "
  416. "from WaitForSingleObject, unexpected error, "
  417. "thread is exiting...",
  418. dwResult));
  419. }
  420. else if (m_pWiaVideo == NULL)
  421. {
  422. hr = E_FAIL;
  423. m_bExitThread = TRUE;
  424. CHECK_S_OK2(hr,
  425. ("CWiaLink::ThreadProc, m_pWiaVideo is NULL, "
  426. "cannot take picture unexpected error, thread "
  427. "is exiting...", dwResult));
  428. }
  429. if (hr == S_OK)
  430. {
  431. BSTR bstrNewImageFileName = NULL;
  432. hr = m_pWiaVideo->TakePicture(&bstrNewImageFileName);
  433. if (hr == S_OK)
  434. {
  435. CSimpleStringWide strNewImageFileName(
  436. bstrNewImageFileName);
  437. if (strNewImageFileName.Length() > 0)
  438. {
  439. SignalNewImage(
  440. &(CSimpleStringConvert::NaturalString(
  441. strNewImageFileName)));
  442. }
  443. }
  444. if (bstrNewImageFileName)
  445. {
  446. SysFreeString(bstrNewImageFileName);
  447. bstrNewImageFileName = NULL;
  448. }
  449. }
  450. }
  451. //
  452. // Set this event, regardless of an error because the driver
  453. // will be waiting for this event (with a timeout of course) to
  454. // indicate that it can return from the TAKE_PICTURE request.
  455. //
  456. SetEvent(m_hPictureReadyEvent);
  457. }
  458. DBG_TRC(("CWiaLink::ThreadProc exiting..."));
  459. return hr;
  460. }
  461. ///////////////////////////////
  462. // StartThreadProc
  463. //
  464. // Static Fn.
  465. //
  466. DWORD WINAPI CWiaLink::StartThreadProc(void *pArgs)
  467. {
  468. DBG_FN("CWiaLink::StartThreadProc");
  469. DWORD dwReturn = 0;
  470. if (pArgs)
  471. {
  472. CWiaLink *pWiaLink = reinterpret_cast<CWiaLink*>(pArgs);
  473. if (pWiaLink)
  474. {
  475. pWiaLink->ThreadProc(pArgs);
  476. }
  477. else
  478. {
  479. DBG_ERR(("CWiaLink::StartThreadProc, invalid value for pArgs, "
  480. "this should be the 'this' pointer, unexpected error"));
  481. }
  482. }
  483. else
  484. {
  485. DBG_ERR(("CWiaLink::StartThreadProc, received NULL pArgs, this "
  486. "should be the 'this' pointer, unexpected error"));
  487. }
  488. return dwReturn;
  489. }
  490. ///////////////////////////////
  491. // SignalNewImage
  492. //
  493. HRESULT CWiaLink::SignalNewImage(const CSimpleString *pstrNewImageFileName)
  494. {
  495. HRESULT hr = S_OK;
  496. DBG_FN("CWiaLink::SignalNewImage");
  497. //
  498. // It is possible that this gets called by the Still Image processor if
  499. // we get an unsolicited image (happens when you press external
  500. // hardware button and capture filter has still pin on it).
  501. // However, if user initialized WiaVideo so that it doesn't use
  502. // WIA, simply ignore this request and return.
  503. //
  504. if (!m_bEnabled)
  505. {
  506. DBG_WRN(("CWiaLink::SignalNewImage was called, but WiaLink is NOT "
  507. "enabled"));
  508. return hr;
  509. }
  510. if (pstrNewImageFileName == NULL)
  511. {
  512. hr = E_FAIL;
  513. CHECK_S_OK2(hr, ("CWiaLink::SignalNewImage, received NULL new image "
  514. "file name"));
  515. }
  516. else if (m_dwWiaItemCookie == 0)
  517. {
  518. hr = E_FAIL;
  519. CHECK_S_OK2(hr, ("CWiaLink::SignalNewImage, received WIA root "
  520. "item not available."));
  521. }
  522. if (hr == S_OK)
  523. {
  524. CComPtr<IWiaPropertyStorage> pStorage;
  525. hr = GetDeviceStorage(&pStorage);
  526. if (hr == S_OK)
  527. {
  528. hr = CWiaUtil::SetProperty(pStorage,
  529. WIA_DPV_LAST_PICTURE_TAKEN,
  530. pstrNewImageFileName);
  531. CHECK_S_OK2(hr, ("CWiaLink::SignalNewImage, failed to set Last "
  532. "Picture Taken property for Wia Video Driver"));
  533. }
  534. }
  535. return hr;
  536. }
  537. ///////////////////////////////
  538. // GetDevice
  539. //
  540. HRESULT CWiaLink::GetDevice(IWiaItem **ppWiaRootItem)
  541. {
  542. HRESULT hr = S_OK;
  543. ASSERT(ppWiaRootItem != NULL);
  544. ASSERT(m_pGIT != NULL);
  545. if ((ppWiaRootItem == NULL) ||
  546. (m_pGIT == NULL))
  547. {
  548. hr = E_POINTER;
  549. CHECK_S_OK2(hr, ("CWiaLink::GetDevice, received NULL params"));
  550. return hr;
  551. }
  552. if (hr == S_OK)
  553. {
  554. CAccessLock Lock(&m_csLock);
  555. hr = m_pGIT->GetInterfaceFromGlobal(
  556. m_dwWiaItemCookie,
  557. IID_IWiaItem,
  558. reinterpret_cast<void**>(ppWiaRootItem));
  559. }
  560. return hr;
  561. }
  562. ///////////////////////////////
  563. // GetDeviceStorage
  564. //
  565. HRESULT CWiaLink::GetDeviceStorage(IWiaPropertyStorage **ppPropertyStorage)
  566. {
  567. HRESULT hr = S_OK;
  568. ASSERT(ppPropertyStorage != NULL);
  569. ASSERT(m_pGIT != NULL);
  570. if ((ppPropertyStorage == NULL) ||
  571. (m_pGIT == NULL))
  572. {
  573. hr = E_POINTER;
  574. CHECK_S_OK2(hr, ("CWiaLink::GetDeviceStorage, received NULL params"));
  575. return hr;
  576. }
  577. if (hr == S_OK)
  578. {
  579. CAccessLock Lock(&m_csLock);
  580. hr = m_pGIT->GetInterfaceFromGlobal(
  581. m_dwPropertyStorageCookie,
  582. IID_IWiaPropertyStorage,
  583. reinterpret_cast<void**>(ppPropertyStorage));
  584. }
  585. return hr;
  586. }