Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2482 lines
68 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998 - 2000
  4. *
  5. * TITLE: minidrv.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: RickTu
  10. *
  11. * DATE: 9/9/99
  12. *
  13. * DESCRIPTION: This module implements IWiaMiniDrv for this device.
  14. *
  15. *****************************************************************************/
  16. #include <precomp.h>
  17. #pragma hdrstop
  18. #include "wiamindr_i.c"
  19. #include <sddl.h>
  20. #include <shlobj.h>
  21. ///////////////////////////////
  22. // Constants
  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 TAKE_PICTURE_TIMEOUT = 1000 * 15; // 15 seconds
  28. //const UINT DEFAULT_LOCK_TIMEOUT = 1000 * 2; // 2 seconds
  29. // This is the Security Descriptor Language
  30. // - Each ACE (access control entry) is represented in by parentheses.
  31. // - A = Allow ACE (as opposed to a Deny ACE)
  32. // - OICI = Allow Object Inheritance and Container Inheritence
  33. // - GA = Generic All Access (Full Control)
  34. // - SY = System account (SID)
  35. // - BA = Builtin Administrators Group
  36. // - CO = Creator/Owner
  37. // - GR = Generic Read
  38. // - GW = Generic Write
  39. // - GX = Generic Execute.
  40. // - IU = Interactive Users (User's logged on at the computer)
  41. //
  42. // More info, go to http://msdn.microsoft.com/library/psdk/winbase/accctrl_2n1v.htm
  43. //
  44. //
  45. //
  46. const TCHAR *OBJECT_DACLS= TEXT("D:(A;OICI;GA;;;SY)") // SYSTEM
  47. TEXT("(A;OICI;GA;;;BA)") // Admin
  48. TEXT("(A;OICI;GRGWGXDTSDCCLC;;;WD)") // Everyone
  49. TEXT("(A;OICI;GRGWGXDTSDCCLC;;;PU)") // Power Users
  50. TEXT("(A;OICI;GRGWGXDTSDCCLC;;;BU)"); // Users
  51. /*****************************************************************************
  52. DirectoryExists
  53. Checks to see whether the given fully qualified directory exists.
  54. *****************************************************************************/
  55. BOOL DirectoryExists(LPCTSTR pszDirectoryName)
  56. {
  57. BOOL bExists = FALSE;
  58. //
  59. // Try to determine if this directory exists
  60. //
  61. if (pszDirectoryName)
  62. {
  63. DWORD dwFileAttributes = GetFileAttributes(pszDirectoryName);
  64. if (dwFileAttributes == 0xFFFFFFFF ||
  65. !(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  66. {
  67. bExists = FALSE;
  68. }
  69. else
  70. {
  71. bExists = TRUE;
  72. }
  73. }
  74. else
  75. {
  76. bExists = FALSE;
  77. }
  78. return bExists;
  79. }
  80. /*****************************************************************************
  81. RecursiveCreateDirectory
  82. Take a fully qualified path and create the directory in pieces as needed.
  83. *****************************************************************************/
  84. BOOL RecursiveCreateDirectory(CSimpleString *pstrDirectoryName)
  85. {
  86. ASSERT(pstrDirectoryName != NULL);
  87. //
  88. // If this directory already exists, return true.
  89. //
  90. if (DirectoryExists(*pstrDirectoryName))
  91. {
  92. return TRUE;
  93. }
  94. //
  95. // Otherwise try to create it.
  96. //
  97. CreateDirectory(*pstrDirectoryName, NULL );
  98. //
  99. // If it now exists, return true
  100. //
  101. if (DirectoryExists(*pstrDirectoryName))
  102. {
  103. return TRUE;
  104. }
  105. else
  106. {
  107. //
  108. // Remove the last subdir and try again
  109. //
  110. int nFind = pstrDirectoryName->ReverseFind(TEXT('\\'));
  111. if (nFind >= 0)
  112. {
  113. RecursiveCreateDirectory(&(pstrDirectoryName->Left(nFind)));
  114. //
  115. // Now try to create it.
  116. //
  117. CreateDirectory(*pstrDirectoryName, NULL);
  118. }
  119. }
  120. //
  121. //Does it exist now?
  122. //
  123. return DirectoryExists(*pstrDirectoryName);
  124. }
  125. ///////////////////////////////
  126. // SetDirectorySecurity
  127. //
  128. HRESULT SetDirectorySecurity(CSimpleString *pstrDirectoryName)
  129. {
  130. HRESULT hr = S_OK;
  131. BOOL bSuccess = TRUE;
  132. SECURITY_ATTRIBUTES SA;
  133. SA.nLength = sizeof(SECURITY_ATTRIBUTES);
  134. SA.bInheritHandle = TRUE;
  135. if (ConvertStringSecurityDescriptorToSecurityDescriptor(
  136. OBJECT_DACLS,
  137. SDDL_REVISION_1,
  138. &(SA.lpSecurityDescriptor),
  139. NULL))
  140. {
  141. bSuccess = SetFileSecurity(*pstrDirectoryName,
  142. DACL_SECURITY_INFORMATION,
  143. SA.lpSecurityDescriptor);
  144. if (!bSuccess)
  145. {
  146. hr = HRESULT_FROM_WIN32(GetLastError());
  147. }
  148. if (SA.lpSecurityDescriptor)
  149. {
  150. LocalFree(SA.lpSecurityDescriptor);
  151. }
  152. }
  153. else
  154. {
  155. hr = HRESULT_FROM_WIN32(GetLastError());
  156. }
  157. return hr;
  158. }
  159. /*****************************************************************************
  160. CVideoStiUsd::drvInitializeWia [IWiaMiniDrv]
  161. WIA calls this method to ask us to do the following:
  162. * Initialize our mini driver.
  163. * Setup our optional private interface(s).
  164. * Build our device item tree.
  165. During initializiation we:
  166. * Cache the STI device pointer for locking.
  167. * Cache the device ID and root item full item name.
  168. * Initialize and hook up the DirectShow stream.
  169. *****************************************************************************/
  170. STDMETHODIMP
  171. CVideoStiUsd::drvInitializeWia( BYTE *pWiasContext,
  172. LONG lFlags,
  173. BSTR bstrDeviceID,
  174. BSTR bstrRootFullItemName,
  175. IUnknown *pStiDevice,
  176. IUnknown *pIUnknownOuter,
  177. IWiaDrvItem **ppIDrvItemRoot,
  178. IUnknown **ppIUnknownInner,
  179. LONG *plDevErrVal
  180. )
  181. {
  182. HRESULT hr = S_OK;
  183. DBG_FN("CVideoStiUsd::drvInitializeWia");
  184. //
  185. // Initialize return values
  186. //
  187. if (ppIDrvItemRoot)
  188. {
  189. *ppIDrvItemRoot = NULL;
  190. }
  191. if (ppIUnknownInner)
  192. {
  193. *ppIUnknownInner = NULL;
  194. }
  195. if (plDevErrVal)
  196. {
  197. *plDevErrVal = 0;
  198. }
  199. //
  200. // Enter the critical section.
  201. //
  202. EnterCriticalSection(&m_csItemTree);
  203. m_dwConnectedApps++;
  204. DBG_TRC(("CVideoStiUsd::drvInitializeWia - Initializing Video Driver, "
  205. "Num Connected Apps = '%lu', device id = '%ws', Root Item Name = '%ws'",
  206. m_dwConnectedApps,
  207. bstrDeviceID,
  208. bstrRootFullItemName));
  209. if (m_dwConnectedApps == 1)
  210. {
  211. //
  212. // Cache what we need to
  213. //
  214. if (pStiDevice)
  215. {
  216. pStiDevice->QueryInterface( IID_IStiDevice, (void **)&m_pStiDevice );
  217. }
  218. m_strDeviceId.Assign(CSimpleStringWide(bstrDeviceID));
  219. m_strRootFullItemName.Assign(CSimpleStringWide(bstrRootFullItemName));
  220. //
  221. // Set the images directory. The first param is NULL, which indicates
  222. // that a default directory should be set.
  223. //
  224. if (hr == S_OK)
  225. {
  226. hr = SetImagesDirectory(NULL,
  227. pWiasContext,
  228. &m_pRootItem,
  229. plDevErrVal);
  230. }
  231. //
  232. // Enable the take picture event so that an app can send this driver
  233. // the take picture command, and this driver can signal the appliation
  234. // that owns wiavideo to take the picture.
  235. //
  236. if (hr == S_OK)
  237. {
  238. EnableTakePicture(pWiasContext);
  239. }
  240. }
  241. else
  242. {
  243. RefreshTree(m_pRootItem, plDevErrVal);
  244. }
  245. if (ppIDrvItemRoot)
  246. {
  247. *ppIDrvItemRoot = m_pRootItem;
  248. }
  249. //
  250. // Leave the critical section
  251. //
  252. LeaveCriticalSection(&m_csItemTree);
  253. CHECK_S_OK(hr);
  254. return hr;
  255. }
  256. /**************************************************************************\
  257. CVideoStiUsd::drvUnInitializeWia [IWiaMiniDrv]
  258. Gets called when a client connection is going away.
  259. WIA calls this method to ask us to do the following:
  260. * Cleanup any resources that are releated to this client connection
  261. (identified by pWiasContext)
  262. *************************************************************************/
  263. STDMETHODIMP
  264. CVideoStiUsd::drvUnInitializeWia(BYTE *pWiasContext)
  265. {
  266. HRESULT hr = S_OK;
  267. DBG_FN("CVideoStiUsd::drvUnInitializeWia");
  268. EnterCriticalSection(&m_csItemTree);
  269. if (m_dwConnectedApps > 0)
  270. {
  271. m_dwConnectedApps--;
  272. }
  273. DBG_TRC(("CVideoStiUsd::drvUnInitializeWia, Num Connected Apps = '%lu'",
  274. m_dwConnectedApps));
  275. if ((m_dwConnectedApps == 0) && (m_pRootItem))
  276. {
  277. DisableTakePicture(pWiasContext, TRUE);
  278. DBG_TRC(("CVideoStiUsd::drvUnInitializeWia, no more connected apps, deleting tree"));
  279. hr = m_pRootItem->UnlinkItemTree(WiaItemTypeDisconnected);
  280. CHECK_S_OK2(hr,("m_pRootItem->UnlinkItemTree()"));
  281. // Clear the root item
  282. m_pRootItem = NULL;
  283. // Clear the pointer to the STI device we received
  284. m_pStiDevice = NULL;
  285. // reset the num pictures taken to 0.
  286. m_lPicsTaken = 0;
  287. }
  288. LeaveCriticalSection(&m_csItemTree);
  289. CHECK_S_OK(hr);
  290. return hr;
  291. }
  292. /*****************************************************************************
  293. CVideoStiUsd::drvGetDeviceErrorStr [IWiaMiniDrv]
  294. <Notes>
  295. *****************************************************************************/
  296. STDMETHODIMP
  297. CVideoStiUsd::drvGetDeviceErrorStr(LONG lFlags,
  298. LONG lDevErrVal,
  299. LPOLESTR * ppszDevErrStr,
  300. LONG * plDevErr)
  301. {
  302. HRESULT hr = E_NOTIMPL;
  303. DBG_FN("CVideoStiUsd::drvGetDeviceErrorStr");
  304. CHECK_S_OK(hr);
  305. return hr;
  306. }
  307. /*****************************************************************************
  308. CVideoStiUsd::drvDeviceCommand [IWiaMiniDrv]
  309. <Notes>
  310. *****************************************************************************/
  311. STDMETHODIMP
  312. CVideoStiUsd::drvDeviceCommand(BYTE * pWiasContext,
  313. LONG lFlags,
  314. const GUID * pGUIDCommand,
  315. IWiaDrvItem ** ppMiniDrvItem,
  316. LONG * plDevErrVal)
  317. {
  318. HRESULT hr = S_OK;
  319. DBG_FN("CVideoStiUsd::drvDeviceCommand");
  320. if (plDevErrVal)
  321. {
  322. *plDevErrVal = 0;
  323. }
  324. //
  325. // We support "Take snapshot"
  326. //
  327. if (*pGUIDCommand == WIA_CMD_TAKE_PICTURE)
  328. {
  329. DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command "
  330. "WIA_CMD_TAKE_PICTURE"));
  331. //
  332. // Take a picture
  333. //
  334. hr = TakePicture(pWiasContext, ppMiniDrvItem);
  335. }
  336. else if (*pGUIDCommand == WIA_CMD_ENABLE_TAKE_PICTURE)
  337. {
  338. //
  339. // This command doesn't do anything. However WiaVideo still expects
  340. // it to succeed, so if you remove this, remove the call from WiaVideo too.
  341. //
  342. DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command "
  343. "WIA_CMD_ENABLE_TAKE_PICTURE"));
  344. hr = S_OK;
  345. }
  346. else if (*pGUIDCommand == WIA_CMD_DISABLE_TAKE_PICTURE)
  347. {
  348. //
  349. // This command doesn't do anything. However WiaVideo still expects
  350. // it to succeed, so if you remove this, remove the call from WiaVideo too.
  351. //
  352. DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command "
  353. "WIA_CMD_DISABLE_TAKE_PICTURE"));
  354. hr = S_OK;
  355. }
  356. CHECK_S_OK(hr);
  357. return hr;
  358. }
  359. /*****************************************************************************
  360. CVideoStiUsd::ValidateDataTransferContext
  361. <Notes>
  362. *****************************************************************************/
  363. STDMETHODIMP
  364. CVideoStiUsd::ValidateDataTransferContext(
  365. PMINIDRV_TRANSFER_CONTEXT pDataTransferContext)
  366. {
  367. DBG_FN("CVideoStiUsd::ValidateDataTransferContext");
  368. if (pDataTransferContext->lSize != sizeof(MINIDRV_TRANSFER_CONTEXT))
  369. {
  370. DBG_ERR(("invalid data transfer context -- wrong lSize"));
  371. return E_INVALIDARG;;
  372. }
  373. //
  374. // for tymed file or hglobal, only WiaImgFmt_BMP || WiaImgFmt_JPEG
  375. // is allowed
  376. //
  377. if ((pDataTransferContext->tymed == TYMED_FILE) ||
  378. (pDataTransferContext->tymed == TYMED_HGLOBAL)
  379. )
  380. {
  381. if ((pDataTransferContext->guidFormatID != WiaImgFmt_BMP) &&
  382. (pDataTransferContext->guidFormatID != WiaImgFmt_JPEG))
  383. {
  384. DBG_ERR(("invalid format -- asked for TYMED_FILE or TYMED_HGLOBAL "
  385. "but guidFormatID != (WiaImgFmt_BMP | WiaImgFmt_JPEG)"));
  386. return E_INVALIDARG;;
  387. }
  388. }
  389. //
  390. // for tymed CALLBACK, only WiaImgFmt_MEMORYBMP, WiaImgFmt_BMP and
  391. // WiaImgFmt_JPEG are allowed
  392. //
  393. if (pDataTransferContext->tymed == TYMED_CALLBACK)
  394. {
  395. if ((pDataTransferContext->guidFormatID != WiaImgFmt_BMP) &&
  396. (pDataTransferContext->guidFormatID != WiaImgFmt_MEMORYBMP) &&
  397. (pDataTransferContext->guidFormatID != WiaImgFmt_JPEG))
  398. {
  399. DBG_ERR(("invalid format -- asked for TYMED_CALLBACK but "
  400. "guidFormatID != (WiaImgFmt_BMP | WiaImgFmt_MEMORYBMP "
  401. "| WiaImgFmt_JPEG)"));
  402. return E_INVALIDARG;;
  403. }
  404. }
  405. //
  406. // callback is always double buffered, non-callback never is
  407. //
  408. if (pDataTransferContext->pTransferBuffer == NULL)
  409. {
  410. DBG_ERR(("invalid transfer context -- pTransferBuffer is NULL!"));
  411. return E_INVALIDARG;
  412. }
  413. return S_OK;
  414. }
  415. /*****************************************************************************
  416. CVideoStiUsd::SendBitmapHeader
  417. Sends bitmap header during banded transfer
  418. *****************************************************************************/
  419. STDMETHODIMP
  420. CVideoStiUsd::SendBitmapHeader(IWiaDrvItem * pDrvItem,
  421. PMINIDRV_TRANSFER_CONTEXT pTranCtx)
  422. {
  423. HRESULT hr = S_OK;
  424. DBG_FN("CVideoStiUsd::SendBitmapHeader");
  425. //
  426. // driver is sending TOPDOWN data, must swap biHeight
  427. //
  428. // this routine assumes pTranCtx->pHeader points to a
  429. // BITMAPINFO header (TYMED_FILE doesn't use this path
  430. // and DIB is the only format supported now)
  431. //
  432. PBITMAPINFO pbmi = (PBITMAPINFO)pTranCtx->pTransferBuffer;
  433. if (pTranCtx->guidFormatID == WiaImgFmt_MEMORYBMP)
  434. {
  435. pbmi->bmiHeader.biHeight = -pbmi->bmiHeader.biHeight;
  436. }
  437. hr = pTranCtx->pIWiaMiniDrvCallBack->MiniDrvCallback(
  438. IT_MSG_DATA,
  439. IT_STATUS_TRANSFER_TO_CLIENT,
  440. 0,
  441. 0,
  442. pTranCtx->lHeaderSize,
  443. pTranCtx,
  444. 0);
  445. if (hr == S_OK)
  446. {
  447. //
  448. // advance offset for destination copy
  449. //
  450. pTranCtx->cbOffset += pTranCtx->lHeaderSize;
  451. }
  452. CHECK_S_OK(hr);
  453. return hr;
  454. }
  455. /*****************************************************************************
  456. CVideoStiUsd::drvAquireItemData [IWiaMiniDrv]
  457. <Notes>
  458. *****************************************************************************/
  459. STDMETHODIMP
  460. CVideoStiUsd::drvAcquireItemData(BYTE * pWiasContext,
  461. LONG lFlags,
  462. PMINIDRV_TRANSFER_CONTEXT pDataContext,
  463. LONG * plDevErrVal)
  464. {
  465. HRESULT hr = E_NOTIMPL;
  466. DBG_FN("CVideoStiUsd::drvAcquireItemData");
  467. *plDevErrVal = 0;
  468. //
  469. // Get a pointer to the associated driver item.
  470. //
  471. IWiaDrvItem* pDrvItem;
  472. hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
  473. if (FAILED(hr))
  474. {
  475. CHECK_S_OK2(hr, ("wiaGetDrvItem Failed"));
  476. return hr;
  477. }
  478. //
  479. // Validate the data transfer context.
  480. //
  481. hr = ValidateDataTransferContext( pDataContext );
  482. if (FAILED(hr))
  483. {
  484. CHECK_S_OK2(hr, ("ValidateTransferContext failed"));
  485. return hr;
  486. }
  487. #ifdef DEBUG
  488. //
  489. // Dump the request
  490. //
  491. DBG_TRC(("Asking for TYMED of 0x%x", pDataContext->tymed));
  492. if (pDataContext->guidFormatID == WiaImgFmt_BMP)
  493. {
  494. DBG_TRC(("Asking for WiaImgFmt_BMP"));
  495. }
  496. else if (pDataContext->guidFormatID == WiaImgFmt_MEMORYBMP)
  497. {
  498. DBG_TRC(("Asking for WiaImgFmt_MEMORYBMP"));
  499. }
  500. else if (pDataContext->guidFormatID == WiaImgFmt_JPEG)
  501. {
  502. DBG_TRC(("Asking for WiaImgFmt_JPEG"));
  503. }
  504. #endif
  505. //
  506. // get item specific driver data
  507. //
  508. STILLCAM_IMAGE_CONTEXT *pContext;
  509. pDrvItem->GetDeviceSpecContext((BYTE **)&pContext);
  510. if (!pContext)
  511. {
  512. hr = E_INVALIDARG;
  513. CHECK_S_OK2(hr, ("drvAcquireItemData, NULL item context"));
  514. return hr;
  515. }
  516. //
  517. // Use our internal routines to get format specific info...
  518. //
  519. if (pContext->pImage)
  520. {
  521. hr = pContext->pImage->SetItemSize( pWiasContext, pDataContext );
  522. CHECK_S_OK2(hr, ("pContext->pImage->SetItemSize()"));
  523. }
  524. else
  525. {
  526. DBG_ERR(("Couldn't use our internal routines to compute image "
  527. "information, this is bad!"));
  528. //
  529. // As a last resort, use WIA services to fetch format specific info.
  530. //
  531. hr = wiasGetImageInformation(pWiasContext,
  532. 0,
  533. pDataContext);
  534. CHECK_S_OK2(hr,("wiaGetImageInformation()"));
  535. }
  536. if (FAILED(hr))
  537. {
  538. CHECK_S_OK2(hr, ("wiasGetImageInformation failed"));
  539. return hr;
  540. }
  541. //
  542. // determine if this is a callback or buffered transfer
  543. //
  544. if (pDataContext->tymed == TYMED_CALLBACK)
  545. {
  546. DBG_TRC(("Caller wants callback"));
  547. //
  548. // For formats that have a data header, send it to the client
  549. //
  550. if (pDataContext->lHeaderSize > 0)
  551. {
  552. DBG_TRC(("Sending Bitmap Header..."));
  553. hr = SendBitmapHeader( pDrvItem, pDataContext );
  554. CHECK_S_OK2(hr,("SendBitmapHeader( pDrvItem, pDataContext )"));
  555. }
  556. if (hr == S_OK)
  557. {
  558. DBG_TRC(("Calling LoadImageCB..."));
  559. hr = LoadImageCB( pContext, pDataContext, plDevErrVal );
  560. CHECK_S_OK2(hr, ("LoadImageCB( pContext, pDataContext, "
  561. "plDevErrVal"));
  562. }
  563. }
  564. else
  565. {
  566. DBG_TRC(("Caller doesn't want callback"));
  567. //
  568. // inc past header
  569. //
  570. pDataContext->cbOffset += pDataContext->lHeaderSize;
  571. DBG_TRC(("Calling LoadImage..."));
  572. hr = LoadImage( pContext, pDataContext, plDevErrVal );
  573. CHECK_S_OK2(hr, ("LoadImage( pContext, pDataContext, "
  574. "plDevErrVal )"));
  575. }
  576. CHECK_S_OK(hr);
  577. return hr;
  578. }
  579. /*****************************************************************************
  580. CVideoStiUsd::drvInitItemProperties [IWiaMiniDrv]
  581. <Notes>
  582. *****************************************************************************/
  583. STDMETHODIMP
  584. CVideoStiUsd::drvInitItemProperties(BYTE * pWiasContext,
  585. LONG lFlags,
  586. LONG * plDevErrVal)
  587. {
  588. DBG_FN("CVideoStiUsd::drvInitItemProperties");
  589. HRESULT hr = S_OK;
  590. LONG lItemType;
  591. PSTILLCAM_IMAGE_CONTEXT pContext;
  592. IWiaDrvItem * pDrvItem; // This is not a CComPtr because there
  593. // is no addref for us to release
  594. //
  595. // This device doesn't touch hardware to initialize the
  596. // device item properties.
  597. //
  598. *plDevErrVal = 0;
  599. //
  600. // Parameter validation.
  601. //
  602. if (!pWiasContext)
  603. {
  604. DBG_ERR(("drvInitItemProperties, invalid input pointers"));
  605. return E_INVALIDARG;
  606. }
  607. //
  608. // Get a pointer to the associated driver item.
  609. //
  610. if (hr == S_OK)
  611. {
  612. hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
  613. CHECK_S_OK2(hr,("wiaGetDrvItem"));
  614. }
  615. if (hr == S_OK)
  616. {
  617. //
  618. // Root item has the all the device properties
  619. //
  620. hr = pDrvItem->GetItemFlags(&lItemType);
  621. CHECK_S_OK2(hr,("pDrvItem->GetItemFlags"));
  622. }
  623. if (hr == S_OK)
  624. {
  625. if (lItemType & WiaItemTypeRoot)
  626. {
  627. //
  628. // Root item property init finishes here
  629. //
  630. hr = InitDeviceProperties( pWiasContext, plDevErrVal );
  631. CHECK_S_OK2(hr,("InitDeviceProperties for root item"));
  632. }
  633. else if (lItemType & WiaItemTypeFile)
  634. {
  635. //
  636. // If this is a file, init the properties
  637. //
  638. //
  639. // Add the item property names.
  640. //
  641. if (hr == S_OK)
  642. {
  643. hr = wiasSetItemPropNames(pWiasContext,
  644. NUM_CAM_ITEM_PROPS,
  645. gItemPropIDs,
  646. gItemPropNames);
  647. CHECK_S_OK2(hr,("wiaSetItemPropNames for item"));
  648. }
  649. if (hr == S_OK)
  650. {
  651. //
  652. // Use WIA services to set the default item properties.
  653. //
  654. hr = wiasWriteMultiple(pWiasContext,
  655. NUM_CAM_ITEM_PROPS,
  656. gPropSpecDefaults,
  657. (PROPVARIANT*)gPropVarDefaults);
  658. CHECK_S_OK2(hr,("wiaWriteMultiple for item props"));
  659. }
  660. if (hr == S_OK)
  661. {
  662. hr = pDrvItem->GetDeviceSpecContext( (BYTE **)&pContext );
  663. CHECK_S_OK2(hr,("GetDeviceSpecContext"));
  664. }
  665. if (hr == S_OK)
  666. {
  667. hr = InitImageInformation(pWiasContext, pContext, plDevErrVal);
  668. CHECK_S_OK2(hr,("InitImageInformation"));
  669. }
  670. }
  671. }
  672. return hr;
  673. }
  674. /*****************************************************************************
  675. CVideoStiUsd::ValidateItemProperties
  676. <Notes>
  677. *****************************************************************************/
  678. HRESULT
  679. CVideoStiUsd::ValidateItemProperties(BYTE *pWiasContext,
  680. LONG lFlags,
  681. ULONG nPropSpec,
  682. const PROPSPEC *pPropSpec,
  683. LONG *plDevErrVal,
  684. IWiaDrvItem *pDrvItem)
  685. {
  686. DBG_FN("CVideoStiUsd::ValidateFileProperties");
  687. HRESULT hr = S_OK;
  688. if ((pWiasContext == NULL) ||
  689. (pPropSpec == NULL))
  690. {
  691. hr = E_INVALIDARG;
  692. CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateItemProperties received "
  693. "NULL params"));
  694. return hr;
  695. }
  696. STILLCAM_IMAGE_CONTEXT *pContext = NULL;
  697. hr = pDrvItem->GetDeviceSpecContext( (BYTE **)&pContext);
  698. CHECK_S_OK2(hr,("CVideoStiUsd::ValidateItemProperties, "
  699. "GetDeviceSpecContext failed"));
  700. if (SUCCEEDED(hr) && pContext)
  701. {
  702. CImage * pImage = pContext->pImage;
  703. if (pImage)
  704. {
  705. //
  706. // calc item size
  707. //
  708. hr = pImage->SetItemSize( pWiasContext, NULL );
  709. CHECK_S_OK2(hr,("SetItemSize( pWiasContext )"));
  710. }
  711. //
  712. // Change MinBufferSize property. Need to get Tymed and
  713. // ItemSize first, since MinBufferSize in dependant on these
  714. // properties.
  715. //
  716. LONG lTymed;
  717. LONG lItemSize;
  718. LONG lMinBufSize = 0;
  719. hr = wiasReadPropLong(pWiasContext,
  720. WIA_IPA_TYMED,
  721. &lTymed,
  722. NULL,
  723. TRUE);
  724. CHECK_S_OK2(hr, ("wiasReadPropLong( WIA_IPA_TYPMED )"));
  725. if (SUCCEEDED(hr))
  726. {
  727. hr = wiasReadPropLong(pWiasContext,
  728. WIA_IPA_ITEM_SIZE,
  729. &lItemSize,
  730. NULL,
  731. TRUE);
  732. CHECK_S_OK2(hr,("wiasReadPropLong( WIA_IPA_ITEM_SIZE )"));
  733. if (SUCCEEDED(hr))
  734. {
  735. //
  736. // Update the MinBufferSize property.
  737. //
  738. switch (lTymed)
  739. {
  740. case TYMED_CALLBACK:
  741. lMinBufSize = 65535;
  742. break;
  743. default:
  744. lMinBufSize = lItemSize;
  745. break;
  746. }
  747. if (lMinBufSize)
  748. {
  749. hr = wiasWritePropLong(pWiasContext,
  750. WIA_IPA_MIN_BUFFER_SIZE,
  751. lMinBufSize);
  752. CHECK_S_OK2(hr, ("wiasWritePropLong( "
  753. "WIA_IPA_MIN_BUFFER_SIZE )"));
  754. }
  755. DBG_TRC(("WIA_IPA_MIN_BUFFER_SIZE set to %d bytes",
  756. lMinBufSize));
  757. }
  758. }
  759. }
  760. return hr;
  761. }
  762. /*****************************************************************************
  763. CVideoStiUsd::ValidateDeviceProperties
  764. <Notes>
  765. *****************************************************************************/
  766. HRESULT
  767. CVideoStiUsd::ValidateDeviceProperties(BYTE *pWiasContext,
  768. LONG lFlags,
  769. ULONG nPropSpec,
  770. const PROPSPEC *pPropSpec,
  771. LONG *plDevErrVal,
  772. IWiaDrvItem *pDrvItem)
  773. {
  774. DBG_FN("CVideoStiUsd::ValidateRootProperties");
  775. HRESULT hr = S_OK;
  776. //
  777. // Parameter validation.
  778. //
  779. if ((pWiasContext == NULL) ||
  780. (pPropSpec == NULL))
  781. {
  782. hr = E_INVALIDARG;
  783. CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateDeviceProperties received "
  784. "NULL params"));
  785. return hr;
  786. }
  787. for (ULONG i = 0; i < nPropSpec; i++)
  788. {
  789. if ((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  790. (pPropSpec[i].propid == WIA_DPV_LAST_PICTURE_TAKEN))
  791. {
  792. DBG_TRC(("CVideoStiUsd::ValidateDeviceProperties, setting the "
  793. "WIA_DPV_LAST_PICTURE_TAKEN property."));
  794. EnterCriticalSection(&m_csItemTree);
  795. //
  796. // process the last picture taken property change.
  797. //
  798. BSTR bstrLastPictureTaken = NULL;
  799. //
  800. // Read in the value for last picture taken.
  801. //
  802. hr = wiasReadPropStr(pWiasContext,
  803. WIA_DPV_LAST_PICTURE_TAKEN,
  804. &bstrLastPictureTaken,
  805. NULL,
  806. TRUE);
  807. if (hr == S_OK)
  808. {
  809. m_strLastPictureTaken = bstrLastPictureTaken;
  810. DBG_TRC(("CVideoStiUsd::ValidateDeviceProperties, last picture "
  811. "taken = '%ls'", m_strLastPictureTaken.String()));
  812. //
  813. // This will add the new item to the tree and queue an
  814. // ITEM_CREATED event
  815. //
  816. hr = SignalNewImage(bstrLastPictureTaken);
  817. }
  818. // reset the last picture taken value. This is needed because the
  819. // service checks to see if the new value being set is the same as
  820. // the current value, and if it is, it doesn't forward it on to us.
  821. // This is bad in the event of the Scanner and Camera wizard, where
  822. // it takes 1 picture, (so LAST_PICTURE_TAKEN has a value of "Picture 1"),
  823. // then deletes it, then user backs up the wizard, and takes a picture
  824. // again. This new picture will have a value of "Picture 1" but we won't
  825. // add it to the tree because the value of the property hasn't changed
  826. // as far as the wia service is concerned.
  827. //
  828. if (hr == S_OK)
  829. {
  830. //
  831. // Write the Last Picture Taken
  832. //
  833. hr = wiasWritePropStr(pWiasContext,
  834. WIA_DPV_LAST_PICTURE_TAKEN,
  835. CSimpleBStr(TEXT("")));
  836. }
  837. //
  838. // Free the BSTR
  839. //
  840. if (bstrLastPictureTaken)
  841. {
  842. ::SysFreeString(bstrLastPictureTaken);
  843. bstrLastPictureTaken = NULL;
  844. }
  845. LeaveCriticalSection(&m_csItemTree);
  846. }
  847. else if ((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  848. (pPropSpec[i].propid == WIA_DPV_IMAGES_DIRECTORY))
  849. {
  850. //
  851. // DPV_IMAGES_DIRECTORY -
  852. //
  853. hr = E_FAIL;
  854. CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateRootProperties, "
  855. "attempting to validate the Images Directory "
  856. "property, but this is a read-only "
  857. "property"));
  858. }
  859. else if ((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  860. (pPropSpec[i].propid == WIA_DPV_DSHOW_DEVICE_PATH))
  861. {
  862. //
  863. // process the DShowDeviceID change.
  864. //
  865. hr = E_FAIL;
  866. CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateRootProperties, "
  867. "attempting to validate the DShow Device "
  868. "ID property, but this is a read-only "
  869. "property"));
  870. }
  871. }
  872. return hr;
  873. }
  874. /*****************************************************************************
  875. CVideoStiUsd::drvValidateItemProperties [IWiaMiniDrv]
  876. <Notes>
  877. *****************************************************************************/
  878. STDMETHODIMP
  879. CVideoStiUsd::drvValidateItemProperties(BYTE *pWiasContext,
  880. LONG lFlags,
  881. ULONG nPropSpec,
  882. const PROPSPEC *pPropSpec,
  883. LONG *plDevErrVal)
  884. {
  885. HRESULT hr = S_OK;
  886. DBG_FN("CVideoStiUsd::drvValidateItemProperties");
  887. if (plDevErrVal)
  888. {
  889. *plDevErrVal = 0;
  890. }
  891. //
  892. // Parameter validation.
  893. //
  894. if ((pWiasContext == NULL) ||
  895. (pPropSpec == NULL))
  896. {
  897. hr = E_INVALIDARG;
  898. CHECK_S_OK2(hr, ("CVideoStiUsd::drvValidateItemProperties received "
  899. "NULL params"));
  900. return hr;
  901. }
  902. //
  903. // Get item in question
  904. //
  905. //
  906. // not a CComPtr because there isn't an extra ref
  907. // on this guy from the caller
  908. //
  909. IWiaDrvItem* pDrvItem = NULL;
  910. hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
  911. CHECK_S_OK2(hr,("wiasGetDrvItem( pWiasContext, &pDrvItem )"));
  912. if (SUCCEEDED(hr))
  913. {
  914. LONG lItemType = 0;
  915. //
  916. // What kind of item is this?
  917. //
  918. hr = pDrvItem->GetItemFlags(&lItemType);
  919. CHECK_S_OK2(hr,("pDrvItem->GetItemFlags( &lItemType )"));
  920. if (SUCCEEDED(hr))
  921. {
  922. if (lItemType & WiaItemTypeFile)
  923. {
  924. hr = ValidateItemProperties(pWiasContext,
  925. lFlags,
  926. nPropSpec,
  927. pPropSpec,
  928. plDevErrVal,
  929. pDrvItem);
  930. }
  931. else if (lItemType & WiaItemTypeRoot)
  932. {
  933. hr = ValidateDeviceProperties(pWiasContext,
  934. lFlags,
  935. nPropSpec,
  936. pPropSpec,
  937. plDevErrVal,
  938. pDrvItem);
  939. }
  940. }
  941. }
  942. CHECK_S_OK(hr);
  943. return hr;
  944. }
  945. /*****************************************************************************
  946. CVideoStiUsd::drvWriteItemProperties [IWiaMiniDrv]
  947. <Notes>
  948. *****************************************************************************/
  949. STDMETHODIMP
  950. CVideoStiUsd::drvWriteItemProperties(BYTE * pWiasContext,
  951. LONG lFLags,
  952. PMINIDRV_TRANSFER_CONTEXT pmdtc,
  953. LONG * plDevErrVal)
  954. {
  955. HRESULT hr = S_OK;
  956. DBG_FN("CVideoStiUsd::drvWriteItemProperties");
  957. if (plDevErrVal)
  958. {
  959. *plDevErrVal = 0;
  960. }
  961. CHECK_S_OK(hr);
  962. return hr;
  963. }
  964. /*****************************************************************************
  965. CVideoStiUsd::ReadItemProperties
  966. We only support reading thumbnails on demand for items
  967. *****************************************************************************/
  968. HRESULT
  969. CVideoStiUsd::ReadItemProperties(BYTE *pWiasContext,
  970. LONG lFlags,
  971. ULONG nPropSpec,
  972. const PROPSPEC *pPropSpec,
  973. LONG *plDevErrVal,
  974. IWiaDrvItem *pDrvItem)
  975. {
  976. HRESULT hr = S_OK;
  977. STILLCAM_IMAGE_CONTEXT *pContext = NULL;
  978. if ((pPropSpec == NULL) ||
  979. (pDrvItem == NULL))
  980. {
  981. hr = E_INVALIDARG;
  982. CHECK_S_OK2(hr, ("CVideoStiUsd::ReadItemProperties received a "
  983. "NULL param"));
  984. return hr;
  985. }
  986. //
  987. // It's an item, now loop through the requested properties
  988. // and see if they're looking for the Thumbnail
  989. //
  990. for (ULONG i = 0; i < nPropSpec; i++)
  991. {
  992. if (((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  993. (pPropSpec[i].propid == WIA_IPC_THUMBNAIL)) ||
  994. ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) &&
  995. (wcscmp(pPropSpec[i].lpwstr, WIA_IPC_THUMBNAIL_STR) == 0)))
  996. {
  997. //
  998. // They'd like the thumbnail
  999. //
  1000. hr = pDrvItem->GetDeviceSpecContext((BYTE **)&pContext);
  1001. CHECK_S_OK2(hr,("pDrvItem->GetDeviceSpecContext()"));
  1002. if (SUCCEEDED(hr) && pContext)
  1003. {
  1004. if (pContext->pImage)
  1005. {
  1006. //
  1007. // Use our internal routines to load the thumbnail...
  1008. //
  1009. hr = pContext->pImage->LoadThumbnail(pWiasContext);
  1010. break;
  1011. }
  1012. else
  1013. {
  1014. DBG_ERR(("pContext->pImage was NULL!"));
  1015. }
  1016. }
  1017. else
  1018. {
  1019. DBG_ERR(("Couldn't get pContext"));
  1020. }
  1021. }
  1022. }
  1023. return hr;
  1024. }
  1025. /*****************************************************************************
  1026. CVideoStiUsd::ReadDeviceProperties
  1027. We support all our custom properties
  1028. *****************************************************************************/
  1029. HRESULT
  1030. CVideoStiUsd::ReadDeviceProperties(BYTE *pWiasContext,
  1031. LONG lFlags,
  1032. ULONG nPropSpec,
  1033. const PROPSPEC *pPropSpec,
  1034. LONG *plDevErrVal,
  1035. IWiaDrvItem *pDrvItem)
  1036. {
  1037. HRESULT hr = S_OK;
  1038. if ((pPropSpec == NULL) ||
  1039. (pDrvItem == NULL))
  1040. {
  1041. hr = E_INVALIDARG;
  1042. CHECK_S_OK2(hr, ("CVideoStiUsd::ReadItemProperties received a "
  1043. "NULL param"));
  1044. return hr;
  1045. }
  1046. for (ULONG i = 0; i < nPropSpec; i++)
  1047. {
  1048. if (((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  1049. (pPropSpec[i].propid == WIA_DPC_PICTURES_TAKEN)) ||
  1050. ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) &&
  1051. (!wcscmp(pPropSpec[i].lpwstr, WIA_DPC_PICTURES_TAKEN_STR))))
  1052. {
  1053. //
  1054. // Requesting the number of pictures taken.
  1055. //
  1056. DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID "
  1057. "'%lu' (0x%08lx) WIA_DPC_PICTURES_TAKEN = '%lu'",
  1058. pPropSpec[i].propid,
  1059. pPropSpec[i].propid,
  1060. m_lPicsTaken));
  1061. wiasWritePropLong(pWiasContext,
  1062. WIA_DPC_PICTURES_TAKEN,
  1063. m_lPicsTaken);
  1064. }
  1065. else if (((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  1066. (pPropSpec[i].propid == WIA_DPV_DSHOW_DEVICE_PATH)) ||
  1067. ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) &&
  1068. (!wcscmp(pPropSpec[i].lpwstr, WIA_DPV_DSHOW_DEVICE_PATH_STR))))
  1069. {
  1070. //
  1071. // Requesting the DShow Device ID.
  1072. //
  1073. DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID "
  1074. "'%lu' (0x%08lx) WIA_DPV_DSHOW_DEVICE_PATH = '%ls'",
  1075. pPropSpec[i].propid,
  1076. pPropSpec[i].propid,
  1077. m_strDShowDeviceId.String()));
  1078. wiasWritePropStr(pWiasContext,
  1079. WIA_DPV_DSHOW_DEVICE_PATH,
  1080. CSimpleBStr(m_strDShowDeviceId).BString());
  1081. }
  1082. else if (((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  1083. (pPropSpec[i].propid == WIA_DPV_IMAGES_DIRECTORY)) ||
  1084. ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) &&
  1085. (!wcscmp(pPropSpec[i].lpwstr, WIA_DPV_IMAGES_DIRECTORY_STR))))
  1086. {
  1087. //
  1088. // Requesting the Images Directory.
  1089. //
  1090. DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID "
  1091. "'%lu' (0x%08lx) WIA_DPV_IMAGES_DIRECTORY = '%ls'",
  1092. pPropSpec[i].propid,
  1093. pPropSpec[i].propid,
  1094. m_strStillPath.String()));
  1095. wiasWritePropStr(pWiasContext,
  1096. WIA_DPV_IMAGES_DIRECTORY,
  1097. CSimpleBStr(m_strStillPath).BString());
  1098. }
  1099. else if (((pPropSpec[i].ulKind == PRSPEC_PROPID) &&
  1100. (pPropSpec[i].propid == WIA_DPV_LAST_PICTURE_TAKEN)) ||
  1101. ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) &&
  1102. (!wcscmp(pPropSpec[i].lpwstr, WIA_DPV_LAST_PICTURE_TAKEN_STR))))
  1103. {
  1104. //
  1105. // Requesting the last picture taken
  1106. //
  1107. DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID "
  1108. "'%lu' (0x%08lx) WIA_DPV_LAST_PICTURE_TAKEN = '%ls'",
  1109. pPropSpec[i].propid,
  1110. pPropSpec[i].propid,
  1111. m_strLastPictureTaken.String()));
  1112. wiasWritePropStr(pWiasContext,
  1113. WIA_DPV_LAST_PICTURE_TAKEN,
  1114. CSimpleBStr(m_strLastPictureTaken).BString());
  1115. }
  1116. }
  1117. return hr;
  1118. }
  1119. /*****************************************************************************
  1120. CVideoStiUsd::drvReadItemProperties [IWiaMiniDrv]
  1121. We only support reading thumbnails on demand.
  1122. *****************************************************************************/
  1123. STDMETHODIMP
  1124. CVideoStiUsd::drvReadItemProperties(BYTE *pWiasContext,
  1125. LONG lFlags,
  1126. ULONG nPropSpec,
  1127. const PROPSPEC *pPropSpec,
  1128. LONG *plDevErrVal)
  1129. {
  1130. HRESULT hr = S_OK;
  1131. LONG lItemType = 0;
  1132. IWiaDrvItem *pDrvItem = NULL;
  1133. DBG_FN("CVideoStiUsd::drvReadItemProperties");
  1134. //
  1135. // Check for bad args
  1136. //
  1137. if ((nPropSpec == 0) ||
  1138. (pPropSpec == NULL) ||
  1139. (pWiasContext == NULL))
  1140. {
  1141. hr = E_INVALIDARG;
  1142. CHECK_S_OK2(hr, ("CVideoStiUsd::drvReadItemProperties received "
  1143. "NULL params"));
  1144. return hr;
  1145. }
  1146. if (hr == S_OK)
  1147. {
  1148. //
  1149. // Make sure we're dealing with an item, not the root item.
  1150. //
  1151. //
  1152. // Get minidriver item
  1153. //
  1154. hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
  1155. if ((hr == S_OK) && (pDrvItem == NULL))
  1156. {
  1157. hr = E_FAIL;
  1158. }
  1159. CHECK_S_OK2(hr,("CVideoStiUsd::drvReadItemProperties, wiasGetDrvItem "
  1160. "failed"));
  1161. }
  1162. if (hr == S_OK)
  1163. {
  1164. hr = pDrvItem->GetItemFlags(&lItemType);
  1165. CHECK_S_OK2(hr,("pDrvItem->GetItemFlags()"));
  1166. }
  1167. if (hr == S_OK)
  1168. {
  1169. if ((lItemType & WiaItemTypeFile) && (!(lItemType & WiaItemTypeRoot)))
  1170. {
  1171. //
  1172. // If property being requested is a file and it is NOT the root,
  1173. // then read in the item property.
  1174. //
  1175. hr = ReadItemProperties(pWiasContext,
  1176. lFlags,
  1177. nPropSpec,
  1178. pPropSpec,
  1179. plDevErrVal,
  1180. pDrvItem);
  1181. }
  1182. else if ((lItemType & WiaItemTypeFolder) &&
  1183. (lItemType & WiaItemTypeRoot))
  1184. {
  1185. //
  1186. // If the property being requested is the root, then read in
  1187. // the device properties.
  1188. //
  1189. hr = ReadDeviceProperties(pWiasContext,
  1190. lFlags,
  1191. nPropSpec,
  1192. pPropSpec,
  1193. plDevErrVal,
  1194. pDrvItem);
  1195. }
  1196. }
  1197. if (plDevErrVal)
  1198. {
  1199. *plDevErrVal = 0;
  1200. }
  1201. CHECK_S_OK(hr);
  1202. return hr;
  1203. }
  1204. /*****************************************************************************
  1205. CVideoStiUsd::drvLockWiaDevice [IWiaMiniDrv]
  1206. <Notes>
  1207. *****************************************************************************/
  1208. STDMETHODIMP
  1209. CVideoStiUsd::drvLockWiaDevice(BYTE *pWiasContext,
  1210. LONG lFlags,
  1211. LONG *plDevErrVal)
  1212. {
  1213. HRESULT hr = S_OK;
  1214. DBG_FN("CVideoStiUsd::drvLockWiaDevice");
  1215. if (plDevErrVal)
  1216. {
  1217. *plDevErrVal = 0;
  1218. }
  1219. //
  1220. // We are purposely not locking the driver. This driver is thread
  1221. // safe and it looks like with large volumes of images (>1000)
  1222. // you get better performance if the driver manages synchronization.
  1223. //
  1224. // return m_pStiDevice->LockDevice(DEFAULT_LOCK_TIMEOUT);
  1225. return hr;
  1226. }
  1227. /*****************************************************************************
  1228. CVideoStiUsd::drvUnLockWiaDevice [IWiaMiniDrv]
  1229. <Notes>
  1230. *****************************************************************************/
  1231. STDMETHODIMP
  1232. CVideoStiUsd::drvUnLockWiaDevice(BYTE *pWiasContext,
  1233. LONG lFlags,
  1234. LONG *plDevErrVal)
  1235. {
  1236. HRESULT hr = S_OK;
  1237. DBG_FN("CVideoStiUsd::drvUnLockWiaDevice");
  1238. if (plDevErrVal)
  1239. {
  1240. *plDevErrVal = 0;
  1241. }
  1242. //
  1243. // We are purposely not locking the driver. This driver is thread
  1244. // safe and it looks like with large volumes of images (>1000)
  1245. // you get better performance if the driver manages synchronization.
  1246. //
  1247. // return m_pStiDevice->UnLockDevice();
  1248. return hr;
  1249. }
  1250. /*****************************************************************************
  1251. CVideoStiUsd::drvAnalyzeItem [IWiaMiniDrv]
  1252. <Notes>
  1253. *****************************************************************************/
  1254. STDMETHODIMP
  1255. CVideoStiUsd::drvAnalyzeItem(BYTE *pWiasContext,
  1256. LONG lFlags,
  1257. LONG *plDevErrVal)
  1258. {
  1259. HRESULT hr = E_NOTIMPL;
  1260. DBG_FN("CVideoStiUsd::drvAnalyzeItem");
  1261. if (plDevErrVal)
  1262. {
  1263. *plDevErrVal = 0;
  1264. }
  1265. CHECK_S_OK(hr);
  1266. return hr;
  1267. }
  1268. /*****************************************************************************
  1269. CVideoStiUsd::drvDeleteItem [IWiaMiniDrv]
  1270. <Notes>
  1271. *****************************************************************************/
  1272. STDMETHODIMP
  1273. CVideoStiUsd::drvDeleteItem(BYTE *pWiasContext,
  1274. LONG lFlags,
  1275. LONG *plDevErrVal)
  1276. {
  1277. HRESULT hr = E_FAIL;
  1278. DBG_FN("CVideoStiUsd::drvDeleteItem");
  1279. //
  1280. // check for bad params
  1281. //
  1282. if (pWiasContext == NULL)
  1283. {
  1284. DBG_ERR(("pWiasContext is NULL!"));
  1285. return E_INVALIDARG;
  1286. }
  1287. if (plDevErrVal)
  1288. {
  1289. *plDevErrVal = 0;
  1290. }
  1291. EnterCriticalSection(&m_csItemTree);
  1292. //
  1293. // Get a pointer to the associated driver item.
  1294. //
  1295. IWiaDrvItem * pDrvItem = NULL;
  1296. hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
  1297. CHECK_S_OK2(hr,("wiasGetDrvItem"));
  1298. if (SUCCEEDED(hr) && pDrvItem)
  1299. {
  1300. //
  1301. // get item specific driver data
  1302. //
  1303. STILLCAM_IMAGE_CONTEXT *pContext = NULL;
  1304. pDrvItem->GetDeviceSpecContext((BYTE **)&pContext);
  1305. CHECK_S_OK2(hr,("pDrvItem->GetDeviceSpecContext"));
  1306. if (SUCCEEDED(hr) && pContext && pContext->pImage)
  1307. {
  1308. //
  1309. // Delete the file in question
  1310. //
  1311. hr = pContext->pImage->DoDelete();
  1312. CHECK_S_OK2(hr,("pContext->pImage->DoDelete()"));
  1313. //
  1314. // Dec the number of pictures taken
  1315. //
  1316. InterlockedDecrement(&m_lPicsTaken);
  1317. //
  1318. // write out the new amount
  1319. //
  1320. wiasWritePropLong(pWiasContext,
  1321. WIA_DPC_PICTURES_TAKEN,
  1322. m_lPicsTaken);
  1323. if (SUCCEEDED(hr))
  1324. {
  1325. HRESULT hr2;
  1326. BSTR bstrItemName = NULL;
  1327. //
  1328. // Get bstr of full item name
  1329. //
  1330. hr2 = pDrvItem->GetFullItemName(&bstrItemName);
  1331. CHECK_S_OK2(hr2,("pDrvItem->GetFullItemName()"));
  1332. //
  1333. // Send event that item was deleted
  1334. //
  1335. hr2 = wiasQueueEvent(CSimpleBStr(m_strDeviceId),
  1336. &WIA_EVENT_ITEM_DELETED,
  1337. bstrItemName);
  1338. CHECK_S_OK2(hr2,
  1339. ("wiasQueueEvent( WIA_EVENT_ITEM_DELETED )"));
  1340. //
  1341. // Cleanup
  1342. //
  1343. if (bstrItemName)
  1344. {
  1345. SysFreeString(bstrItemName);
  1346. bstrItemName = NULL;
  1347. }
  1348. }
  1349. }
  1350. else
  1351. {
  1352. DBG_ERR(("pContext or pContext->pImage are NULL!"));
  1353. hr = E_FAIL;
  1354. }
  1355. }
  1356. LeaveCriticalSection( &m_csItemTree );
  1357. CHECK_S_OK(hr);
  1358. return hr;
  1359. }
  1360. /*****************************************************************************
  1361. CVideoStiUsd::drvFreeDrvItem [IWiaMiniDrv]
  1362. <Notes>
  1363. *****************************************************************************/
  1364. STDMETHODIMP
  1365. CVideoStiUsd::drvFreeDrvItemContext(LONG lFlags,
  1366. BYTE *pDevContext,
  1367. LONG *plDevErrVal)
  1368. {
  1369. HRESULT hr = S_OK;
  1370. DBG_FN("CVideoStiUsd::drvFreeDrvItemContext");
  1371. PSTILLCAM_IMAGE_CONTEXT pContext = (PSTILLCAM_IMAGE_CONTEXT)pDevContext;
  1372. if (pContext != NULL)
  1373. {
  1374. //
  1375. // delete is safe even if param is NULL.
  1376. //
  1377. delete pContext->pImage;
  1378. pContext->pImage = NULL;
  1379. }
  1380. if (plDevErrVal)
  1381. {
  1382. *plDevErrVal = 0;
  1383. }
  1384. CHECK_S_OK(hr);
  1385. return hr;
  1386. }
  1387. /*****************************************************************************
  1388. CMiniDev::drvGetCapabilities [IWiaMiniDrv]
  1389. Let WIA know what things this driver can do.
  1390. *****************************************************************************/
  1391. STDMETHODIMP
  1392. CVideoStiUsd::drvGetCapabilities(BYTE *pWiasContext,
  1393. LONG lFlags,
  1394. LONG *pCelt,
  1395. WIA_DEV_CAP_DRV **ppCapabilities,
  1396. LONG *plDevErrVal)
  1397. {
  1398. HRESULT hr = S_OK;
  1399. DBG_FN("CVideoStiUsd::drvGetCapabilities");
  1400. if (plDevErrVal)
  1401. {
  1402. *plDevErrVal = 0;
  1403. }
  1404. //
  1405. // Return Commmand and/or Events depending on flags
  1406. //
  1407. switch (lFlags)
  1408. {
  1409. case WIA_DEVICE_COMMANDS:
  1410. //
  1411. // Only commands
  1412. //
  1413. *pCelt = NUM_CAP_ENTRIES - NUM_EVENTS;
  1414. *ppCapabilities = &gCapabilities[NUM_EVENTS];
  1415. break;
  1416. case WIA_DEVICE_EVENTS:
  1417. //
  1418. // Only events
  1419. //
  1420. *pCelt = NUM_EVENTS;
  1421. *ppCapabilities = gCapabilities;
  1422. break;
  1423. case (WIA_DEVICE_COMMANDS | WIA_DEVICE_EVENTS):
  1424. //
  1425. // Both events and commands
  1426. //
  1427. *pCelt = NUM_CAP_ENTRIES;
  1428. *ppCapabilities = gCapabilities;
  1429. break;
  1430. default:
  1431. //
  1432. // Flags is invalid
  1433. //
  1434. DBG_ERR(("drvGetCapabilities, flags was invalid"));
  1435. hr = E_INVALIDARG;
  1436. break;
  1437. }
  1438. CHECK_S_OK(hr);
  1439. return hr;
  1440. }
  1441. /*****************************************************************************
  1442. CVideoStiUsd::drvGetWiaFormatInfo [IWiaMiniDrv]
  1443. <Notes>
  1444. *****************************************************************************/
  1445. STDMETHODIMP
  1446. CVideoStiUsd::drvGetWiaFormatInfo(BYTE *pWiasContext,
  1447. LONG lFlags,
  1448. LONG *pCelt,
  1449. WIA_FORMAT_INFO **ppwfi,
  1450. LONG *plDevErrVal)
  1451. {
  1452. HRESULT hr = S_OK;
  1453. DBG_FN("CVideoStiUsd::drvGetWiaFormatInfo");
  1454. if (plDevErrVal)
  1455. {
  1456. *plDevErrVal = 0;
  1457. }
  1458. //
  1459. // If it hasn't been done already, set up the g_wfiTable table
  1460. //
  1461. if (!m_wfi)
  1462. {
  1463. DBG_ERR(("drvGetWiaFormatInfo, m_wfi is NULL!"));
  1464. return E_OUTOFMEMORY;
  1465. }
  1466. if (pCelt)
  1467. {
  1468. *pCelt = NUM_WIA_FORMAT_INFO;
  1469. }
  1470. if (ppwfi)
  1471. {
  1472. *ppwfi = m_wfi;
  1473. }
  1474. CHECK_S_OK(hr);
  1475. return hr;
  1476. }
  1477. /*****************************************************************************
  1478. CVideoStiUsd::drvNotifyPnpEvent [IWiaMiniDrv]
  1479. <Notes>
  1480. *****************************************************************************/
  1481. STDMETHODIMP
  1482. CVideoStiUsd::drvNotifyPnpEvent(const GUID *pEventGUID,
  1483. BSTR bstrDeviceID,
  1484. ULONG ulReserved)
  1485. {
  1486. HRESULT hr = S_OK;
  1487. DBG_FN("CVideoStiUsd::drvNotifyPnpEvent");
  1488. //
  1489. // CONNECTED event is of no interest, because a new USD is always created
  1490. //
  1491. if (*pEventGUID == WIA_EVENT_DEVICE_DISCONNECTED)
  1492. {
  1493. DBG_TRC(("got a WIA_EVENT_DISCONNECTED"));
  1494. }
  1495. CHECK_S_OK(hr);
  1496. return hr;
  1497. }
  1498. /*****************************************************************************
  1499. CVideoStiUsd::VerifyCorrectImagePath
  1500. <Notes>
  1501. *****************************************************************************/
  1502. HRESULT
  1503. CVideoStiUsd::VerifyCorrectImagePath(BSTR bstrNewImageFullPath)
  1504. {
  1505. DBG_FN("CVideoStiUsd::VerifyCorrectImagePath");
  1506. HRESULT hr = S_OK;
  1507. INT iIndex = 0;
  1508. CSimpleString strImageFullPath;
  1509. if (bstrNewImageFullPath == NULL)
  1510. {
  1511. hr = E_POINTER;
  1512. CHECK_S_OK2(hr, ("CVideoStiUsd::VerifyCorrectImagePath received a NULL pointer"));
  1513. return hr;
  1514. }
  1515. if (hr == S_OK)
  1516. {
  1517. strImageFullPath = CSimpleStringConvert::NaturalString(
  1518. CSimpleStringWide(bstrNewImageFullPath));
  1519. //
  1520. // Get the filename out of the full path. Find the last backslash.
  1521. //
  1522. iIndex = strImageFullPath.ReverseFind('\\');
  1523. strImageFullPath[iIndex] = 0;
  1524. if (strImageFullPath != m_strStillPath)
  1525. {
  1526. hr = E_ACCESSDENIED;
  1527. CHECK_S_OK2(hr, ("CVideoStiUsd::VerifyCorrectImagePath, the file that is "
  1528. "being added to the tree '%ls' is not in the allowed directory, "
  1529. "denying request with an E_ACCESSDENIED",
  1530. CSimpleStringWide(strImageFullPath).String()));
  1531. }
  1532. }
  1533. return hr;
  1534. }
  1535. /*****************************************************************************
  1536. CVideoStiUsd::SignalNewImage
  1537. <Notes>
  1538. *****************************************************************************/
  1539. HRESULT
  1540. CVideoStiUsd::SignalNewImage(BSTR bstrNewImageFullPath)
  1541. {
  1542. DBG_FN("CVideoStiUsd::SignalNewImage");
  1543. HRESULT hr = S_OK;
  1544. CComPtr<IWiaDrvItem> pDrvItem = NULL;
  1545. BSTR bstrFullItemName = NULL;
  1546. CSimpleString strImageFullPath;
  1547. if (hr == S_OK)
  1548. {
  1549. hr = VerifyCorrectImagePath(bstrNewImageFullPath);
  1550. }
  1551. if (hr == S_OK)
  1552. {
  1553. strImageFullPath = CSimpleStringConvert::NaturalString(
  1554. CSimpleStringWide(bstrNewImageFullPath));
  1555. DBG_TRC(("CVideoStiUsd::SignalNewImage, adding image '%ls' to "
  1556. "tree of device '%ls'",
  1557. CSimpleStringWide(strImageFullPath).String(),
  1558. m_strDeviceId.String()));
  1559. // Add the new item to the tree if doesn't already exist
  1560. //
  1561. // Get the filename out of the full path. Find the last backslash and
  1562. // move 1 beyond it.
  1563. //
  1564. INT iIndex = strImageFullPath.ReverseFind('\\') + 1;
  1565. if (!IsFileAlreadyInTree(m_pRootItem, &(strImageFullPath[iIndex])))
  1566. {
  1567. hr = AddTreeItem(&strImageFullPath, &pDrvItem);
  1568. CHECK_S_OK2(hr, ("CVideoStiUsd::SignalNewImage, failed to add "
  1569. "image '%ls' to tree of device '%ls'",
  1570. CSimpleStringWide(strImageFullPath).String(),
  1571. m_strDeviceId.String()));
  1572. if (hr == S_OK)
  1573. {
  1574. //
  1575. // Get the full item name for this item
  1576. //
  1577. m_pLastItemCreated = pDrvItem;
  1578. hr = pDrvItem->GetFullItemName(&bstrFullItemName);
  1579. CHECK_S_OK2(hr,("CVideoStiUsd::SignalNewImage, failed to get Item "
  1580. "name for newly added item"));
  1581. }
  1582. if (hr == S_OK)
  1583. {
  1584. //
  1585. // Queue an event that a new item was created.
  1586. //
  1587. hr = wiasQueueEvent(CSimpleBStr(m_strDeviceId),
  1588. &WIA_EVENT_ITEM_CREATED,
  1589. bstrFullItemName);
  1590. CHECK_S_OK2(hr,("CVideoStiUsd::SignalNewImage, failed to "
  1591. "queue a new WIA_EVENT_ITEM_CREATED event"));
  1592. }
  1593. if (bstrFullItemName)
  1594. {
  1595. SysFreeString(bstrFullItemName);
  1596. bstrFullItemName = NULL;
  1597. }
  1598. }
  1599. else
  1600. {
  1601. DBG_TRC(("CVideoStiUsd::SignalNewImage, item '%ls' is already in the "
  1602. "tree. Probably tree was recently refreshed",
  1603. bstrNewImageFullPath));
  1604. }
  1605. }
  1606. return hr;
  1607. }
  1608. /*****************************************************************************
  1609. CVideoStiUsd::SetImagesDirectory
  1610. <Notes>
  1611. *****************************************************************************/
  1612. HRESULT
  1613. CVideoStiUsd::SetImagesDirectory(BSTR bstrNewImagesDirectory,
  1614. BYTE *pWiasContext,
  1615. IWiaDrvItem **ppIDrvItemRoot,
  1616. LONG *plDevErrVal)
  1617. {
  1618. DBG_FN("CVideoStiUsd::SetImagesDirectory");
  1619. HRESULT hr = S_OK;
  1620. CSimpleString strOriginalDirectory;
  1621. //
  1622. // If we received a NULL Images directory, then build up our own
  1623. // generated one, then build the item tree.
  1624. //
  1625. strOriginalDirectory = m_strStillPath;
  1626. if (bstrNewImagesDirectory == NULL)
  1627. {
  1628. //
  1629. // If this path is not in the registry, we default to constructing
  1630. // a path of this type:
  1631. //
  1632. // %TEMP%\WIA\%DeviceID%
  1633. TCHAR szTempPath[MAX_PATH + 1] = {0};
  1634. hr = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_DEFAULT, szTempPath);
  1635. //
  1636. // We allow for the case of S_FALSE which indicates that the folder doesn't
  1637. // exist. This is fine since we recursively create it below.
  1638. //
  1639. if ((hr == S_OK) || (hr == S_FALSE))
  1640. {
  1641. if (szTempPath[_tcslen(szTempPath) - 1] != '\\')
  1642. {
  1643. _tcscat(szTempPath, TEXT("\\"));
  1644. }
  1645. //
  1646. // Set path to "Documents and Settings\Application Data\Microsoft\Wia\{deviceid}"
  1647. //
  1648. m_strStillPath.Assign(szTempPath);
  1649. m_strStillPath += TEXT("Microsoft\\WIA\\");
  1650. m_strStillPath += m_strDeviceId;
  1651. }
  1652. }
  1653. else
  1654. {
  1655. // we received a valid BSTR, attempt to create the directory.
  1656. m_strStillPath = bstrNewImagesDirectory;
  1657. }
  1658. if (!RecursiveCreateDirectory(&m_strStillPath))
  1659. {
  1660. hr = E_FAIL;
  1661. CHECK_S_OK2(hr, ("RecursiveCreateDirectory( %ws ) failed w/GLE=%d",
  1662. m_strStillPath.String(),
  1663. ::GetLastError() ));
  1664. }
  1665. //
  1666. // Set the security DACL on the directory so that users and power users
  1667. // will be able to write and delete from it too.
  1668. //
  1669. if (hr == S_OK)
  1670. {
  1671. //
  1672. // We only set this directory security if we are using our default directory
  1673. // path. This isn't an issue now since the user cannot update the directory,
  1674. // but in the future if we allow them to, this could expose a security whole.
  1675. //
  1676. if (bstrNewImagesDirectory == NULL)
  1677. {
  1678. hr = SetDirectorySecurity(&m_strStillPath);
  1679. }
  1680. }
  1681. if (hr == S_OK)
  1682. {
  1683. if (m_strStillPath.Length())
  1684. {
  1685. BOOL bSendUpdateEvent = FALSE;
  1686. //
  1687. // If the original directory is different from the new directory
  1688. // and we already have a tree, then we should destroy our
  1689. // existing tree, and recreate it for the new directory.
  1690. //
  1691. if ((strOriginalDirectory.CompareNoCase(m_strStillPath) != 0) &&
  1692. (m_pRootItem != NULL))
  1693. {
  1694. EnterCriticalSection( &m_csItemTree );
  1695. hr = m_pRootItem->UnlinkItemTree(WiaItemTypeDisconnected);
  1696. CHECK_S_OK2(hr,("m_pRootItem->UnlinkItemTree()"));
  1697. if (SUCCEEDED(hr))
  1698. {
  1699. bSendUpdateEvent = TRUE;
  1700. m_pRootItem = NULL;
  1701. }
  1702. LeaveCriticalSection( &m_csItemTree );
  1703. }
  1704. //
  1705. // Build the item tree.
  1706. //
  1707. hr = BuildItemTree(ppIDrvItemRoot, plDevErrVal);
  1708. //
  1709. // write out the new amount of pictures taken
  1710. //
  1711. wiasWritePropLong(pWiasContext,
  1712. WIA_DPC_PICTURES_TAKEN,
  1713. m_lPicsTaken);
  1714. if (bSendUpdateEvent)
  1715. {
  1716. wiasQueueEvent(CSimpleBStr(m_strDeviceId),
  1717. &WIA_EVENT_TREE_UPDATED,
  1718. NULL);
  1719. }
  1720. }
  1721. else
  1722. {
  1723. hr = E_FAIL;
  1724. CHECK_S_OK2(hr,
  1725. ("CVideoStiUsd::SetImagesDirectory, new directory "
  1726. "path has a length of 0, Directory = '%ls'",
  1727. m_strStillPath.String()));
  1728. }
  1729. }
  1730. return hr;
  1731. }
  1732. /*****************************************************************************
  1733. CVideoStiUsd::TakePicture
  1734. <Notes>
  1735. *****************************************************************************/
  1736. HRESULT
  1737. CVideoStiUsd::TakePicture(BYTE *pTakePictureOwner,
  1738. IWiaDrvItem **ppNewDrvItem)
  1739. {
  1740. HRESULT hr = S_OK;
  1741. //
  1742. // Notice that we are allowing multiple applications to call the
  1743. // take picture command, even if they weren't the owns that enabled
  1744. // it.
  1745. //
  1746. DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command "
  1747. "WIA_CMD_TAKE_PICTURE"));
  1748. if ((m_hTakePictureEvent) && (m_hPictureReadyEvent))
  1749. {
  1750. DWORD dwResult = 0;
  1751. m_pLastItemCreated = NULL;
  1752. //
  1753. // Tell the WiaVideo object that pertains to this device ID to
  1754. // take a picture.
  1755. //
  1756. SetEvent(m_hTakePictureEvent);
  1757. // The WiaVideo object has a thread waiting on the
  1758. // m_hTakePictureEvent. When it is signalled, the WiaVideo object
  1759. // takes the picture, then sets the driver's custom
  1760. // "LastPictureTaken" property. This causes the driver to update
  1761. // its tree and queue an ITEM_CREATED event. Once this is complete,
  1762. // the WiaVideo object sets the PictureReady Event, at which point
  1763. // we return from this function call.
  1764. // dwResult = WaitForSingleObject(m_hPictureReadyEvent,
  1765. // TAKE_PICTURE_TIMEOUT);
  1766. if (dwResult == WAIT_OBJECT_0)
  1767. {
  1768. // *ppNewDrvItem = m_pLastItemCreated;
  1769. }
  1770. else
  1771. {
  1772. if (dwResult == WAIT_TIMEOUT)
  1773. {
  1774. hr = E_FAIL;
  1775. CHECK_S_OK2(hr, ("CVideoStiUsd::TakePicture timed out "
  1776. "after waiting for '%lu' seconds for the "
  1777. "WiaVideo object to take a picture",
  1778. TAKE_PICTURE_TIMEOUT));
  1779. }
  1780. else if (dwResult == WAIT_ABANDONED)
  1781. {
  1782. hr = E_FAIL;
  1783. CHECK_S_OK2(hr, ("CVideoStiUsd::TakePicture failed, received "
  1784. "a WAIT_ABANDONED from the Wait function"));
  1785. }
  1786. else
  1787. {
  1788. hr = E_FAIL;
  1789. CHECK_S_OK2(hr, ("CVideoStiUsd::TakePicture failed to take a "
  1790. "picture."));
  1791. }
  1792. }
  1793. }
  1794. else
  1795. {
  1796. DBG_TRC(("CVideoStiUsd::drvDeviceCommand, ignoring "
  1797. "WIA_CMD_TAKE_PICTURE request, events created "
  1798. "by WiaVideo are not open"));
  1799. }
  1800. return hr;
  1801. }
  1802. /*****************************************************************************
  1803. CVideoStiUsd::EnableTakePicture
  1804. <Notes>
  1805. *****************************************************************************/
  1806. HRESULT
  1807. CVideoStiUsd::EnableTakePicture(BYTE *pTakePictureOwner)
  1808. {
  1809. DBG_FN("CVideoStiUsd::EnableTakePicture");
  1810. HRESULT hr = S_OK;
  1811. CSimpleString strTakePictureEvent;
  1812. CSimpleString strPictureReadyEvent;
  1813. CSimpleString strDeviceID;
  1814. SECURITY_ATTRIBUTES SA;
  1815. SA.nLength = sizeof(SECURITY_ATTRIBUTES);
  1816. SA.bInheritHandle = TRUE;
  1817. //
  1818. // Convert to security descriptor
  1819. //
  1820. ConvertStringSecurityDescriptorToSecurityDescriptor(OBJECT_DACLS,
  1821. SDDL_REVISION_1,
  1822. &(SA.lpSecurityDescriptor),
  1823. NULL);
  1824. strDeviceID = CSimpleStringConvert::NaturalString(m_strDeviceId);
  1825. m_pTakePictureOwner = pTakePictureOwner;
  1826. if (hr == S_OK)
  1827. {
  1828. INT iPosition = 0;
  1829. CSimpleString strModifiedDeviceID;
  1830. // Change the device ID from {6B...}\xxxx, to {6B...}_xxxx
  1831. iPosition = strDeviceID.ReverseFind('\\');
  1832. strModifiedDeviceID = strDeviceID.MakeUpper();
  1833. strModifiedDeviceID.SetAt(iPosition, '_');
  1834. //
  1835. // Generate the event names. These names contain the Device ID in
  1836. // them so that they are unique across devices.
  1837. //
  1838. strTakePictureEvent = EVENT_PREFIX_GLOBAL;
  1839. strTakePictureEvent += strModifiedDeviceID;
  1840. strTakePictureEvent += EVENT_SUFFIX_TAKE_PICTURE;
  1841. strPictureReadyEvent = EVENT_PREFIX_GLOBAL;
  1842. strPictureReadyEvent += strModifiedDeviceID;
  1843. strPictureReadyEvent += EVENT_SUFFIX_PICTURE_READY;
  1844. }
  1845. if (hr == S_OK)
  1846. {
  1847. m_hTakePictureEvent = CreateEvent(&SA,
  1848. FALSE,
  1849. FALSE,
  1850. strTakePictureEvent);
  1851. //
  1852. // This is not really an error since the events will not have been created until
  1853. // the WiaVideo object comes up.
  1854. //
  1855. if (m_hTakePictureEvent == NULL)
  1856. {
  1857. hr = E_FAIL;
  1858. DBG_TRC(("CVideoStiUsd::EnableTakePicture, failed to open the "
  1859. "WIA event '%ls', this is not fatal (LastError = '%lu' "
  1860. "(0x%08lx))",
  1861. strTakePictureEvent.String(),
  1862. ::GetLastError(),
  1863. ::GetLastError()));
  1864. }
  1865. }
  1866. if (hr == S_OK)
  1867. {
  1868. m_hPictureReadyEvent = CreateEvent(&SA,
  1869. FALSE,
  1870. FALSE,
  1871. strPictureReadyEvent);
  1872. //
  1873. // This is not really an error since the events will not have been created until
  1874. // the WiaVideo object comes up.
  1875. //
  1876. if (m_hPictureReadyEvent == NULL)
  1877. {
  1878. hr = E_FAIL;
  1879. DBG_TRC(("CVideoStiUsd::EnableTakePicture, failed to open the WIA "
  1880. "event '%ls', this is not fatal (LastError = '%lu' "
  1881. "(0x%08lx))",
  1882. strPictureReadyEvent.String(),
  1883. ::GetLastError(),
  1884. ::GetLastError()));
  1885. }
  1886. }
  1887. if (SA.lpSecurityDescriptor)
  1888. {
  1889. LocalFree(SA.lpSecurityDescriptor);
  1890. }
  1891. return hr;
  1892. }
  1893. /*****************************************************************************
  1894. CVideoStiUsd::DisableTakePicture
  1895. <Notes>
  1896. *****************************************************************************/
  1897. HRESULT
  1898. CVideoStiUsd::DisableTakePicture(BYTE *pTakePictureOwner,
  1899. BOOL bShuttingDown)
  1900. {
  1901. HRESULT hr = S_OK;
  1902. if (m_hTakePictureEvent)
  1903. {
  1904. ::CloseHandle(m_hTakePictureEvent);
  1905. m_hTakePictureEvent = NULL;
  1906. }
  1907. if (m_hPictureReadyEvent)
  1908. {
  1909. ::CloseHandle(m_hPictureReadyEvent);
  1910. m_hPictureReadyEvent = NULL;
  1911. }
  1912. m_pTakePictureOwner = NULL;
  1913. return hr;
  1914. }