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.

4938 lines
135 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1997
  4. *
  5. * TITLE: DevMgr.Cpp
  6. *
  7. * VERSION: 2.0
  8. *
  9. * DATE: 26 Dec, 1997
  10. *
  11. * DESCRIPTION:
  12. * Class implementation for WIA device manager.
  13. *
  14. *******************************************************************************/
  15. #include "precomp.h"
  16. #include "stiexe.h"
  17. #include "wiamindr.h"
  18. #include "wiamdef.h"
  19. #include "wiacfact.h"
  20. #include "devmgr.h"
  21. #include "devinfo.h"
  22. #include "tchar.h"
  23. #include "helpers.h"
  24. #include "ienumdc.h"
  25. #include "shlwapi.h"
  26. #include "device.h"
  27. #include "wiapriv.h"
  28. #include "lockmgr.h"
  29. #ifdef UNICODE
  30. #include "userenv.h"
  31. #endif
  32. #define INITGUID
  33. #include "initguid.h"
  34. #include "wiaevntp.h"
  35. //
  36. // Critical section protecting event node list defined in wiamain.cpp
  37. //
  38. extern CRITICAL_SECTION g_semEventNode;
  39. //
  40. // Since there is only Event Notifier needed, it is staticly allocated
  41. //
  42. CEventNotifier g_eventNotifier;
  43. //
  44. // Private look up function defined in STIDEV.CPP
  45. //
  46. HRESULT
  47. WiaGetDeviceInfo(
  48. LPCWSTR pwszDeviceName,
  49. DWORD *pdwDeviceType,
  50. BSTR *pbstrDeviceDescription,
  51. ACTIVE_DEVICE **ppDevice);
  52. //
  53. // Helper function to look for action events
  54. //
  55. BOOL ActionGuidExists(
  56. BSTR bstrDevId,
  57. const GUID *pEventGUID);
  58. //
  59. // Special handler's class ID {D13E3F25-1688-45A0-9743-759EB35CDF9A}
  60. //
  61. DEFINE_GUID(
  62. CLSID_DefHandler,
  63. 0xD13E3F25, 0x1688, 0x45A0,
  64. 0x97, 0x43, 0x75, 0x9E, 0xB3, 0x5C, 0xDF, 0x9A);
  65. #ifdef UNICODE
  66. void
  67. PrepareCommandline(
  68. BSTR bstrDeviceID,
  69. const GUID &guidEvent,
  70. LPCWSTR pwszOrigCmdline,
  71. LPWSTR pwszCommandline);
  72. #else
  73. void
  74. PrepareCommandline(
  75. BSTR bstrDeviceID,
  76. const GUID &guidEvent,
  77. LPCSTR pwszOrigCmdline,
  78. LPSTR pwszCommandline);
  79. #endif
  80. /**************************************************************************\
  81. * EventThreadProc
  82. *
  83. * Thread is created to send events back to client. !!! may want to
  84. * create a permanent thread to do this instead of creating a new one
  85. * each time
  86. *
  87. * Arguments:
  88. *
  89. * lpParameter - pointer to PWIAEventThreadInfo data
  90. *
  91. * Return Value:
  92. *
  93. * Status
  94. *
  95. * History:
  96. *
  97. * 11/19/1998 Original Version
  98. *
  99. \**************************************************************************/
  100. DWORD WINAPI
  101. EventThreadProc(
  102. LPVOID lpParameter)
  103. {
  104. DBG_FN(::EventThreadProc);
  105. HRESULT hr;
  106. PWIAEventThreadInfo pInfo = (PWIAEventThreadInfo)lpParameter;
  107. DBG_TRC(("Thread callback 0x%lx", pInfo->pIEventCB));
  108. hr = CoInitializeEx(0, COINIT_MULTITHREADED);
  109. if (FAILED(hr)) {
  110. DBG_ERR(("Thread callback, ImageEventCallback failed (0x%X)", hr));
  111. }
  112. hr = pInfo->pIEventCB->ImageEventCallback(
  113. &pInfo->eventGUID,
  114. pInfo->bstrEventDescription,
  115. pInfo->bstrDeviceID,
  116. pInfo->bstrDeviceDescription,
  117. pInfo->dwDeviceType,
  118. pInfo->bstrFullItemName,
  119. &pInfo->ulEventType,
  120. pInfo->ulReserved);
  121. pInfo->pIEventCB->Release();
  122. if (FAILED(hr)) {
  123. DBG_ERR(("Thread callback, ImageEventCallback failed (0x%X)", hr));
  124. }
  125. if (pInfo->bstrDeviceID) {
  126. ::SysFreeString(pInfo->bstrDeviceID);
  127. }
  128. if (pInfo->bstrEventDescription) {
  129. ::SysFreeString(pInfo->bstrEventDescription);
  130. }
  131. if (pInfo->bstrDeviceDescription) {
  132. ::SysFreeString(pInfo->bstrDeviceDescription);
  133. }
  134. if (pInfo->bstrFullItemName) {
  135. ::SysFreeString(pInfo->bstrFullItemName);
  136. }
  137. LocalFree(pInfo);
  138. CoUninitialize();
  139. return 0;
  140. }
  141. /***************************************************************************
  142. *
  143. * CEventNotifier
  144. * ~CEventNotifier
  145. *
  146. * Class constructor/destructors
  147. *
  148. * History:
  149. *
  150. * 9/2/1998 Original Version
  151. *
  152. \**************************************************************************/
  153. CEventNotifier::CEventNotifier()
  154. {
  155. m_ulRef = 0;
  156. m_pEventDestNodes = NULL;
  157. }
  158. CEventNotifier::~CEventNotifier()
  159. {
  160. // Clean up
  161. }
  162. /**************************************************************************\
  163. * CEventNotifier::UnlinkNode
  164. *
  165. * remove node from double linkeed list
  166. *
  167. * Arguments:
  168. *
  169. * pCurNode - node to remove
  170. *
  171. * Return Value:
  172. *
  173. * Status
  174. *
  175. * History:
  176. *
  177. * 5/20/1999 Original Version
  178. *
  179. \**************************************************************************/
  180. VOID
  181. CEventNotifier::UnlinkNode(
  182. PEventDestNode pCurNode)
  183. {
  184. DBG_FN(CEventNotifier::UnlinkNode);
  185. //
  186. // Unlink the current node
  187. //
  188. if (pCurNode->pPrev) {
  189. pCurNode->pPrev->pNext = pCurNode->pNext;
  190. } else {
  191. //
  192. // The head of the list is deleted
  193. //
  194. m_pEventDestNodes = pCurNode->pNext;
  195. }
  196. if (pCurNode->pNext) {
  197. pCurNode->pNext->pPrev = pCurNode->pPrev;
  198. }
  199. }
  200. /**************************************************************************\
  201. *
  202. * CEventNotifier::LinkNode
  203. *
  204. * add the node to the double linked list of nodes
  205. *
  206. * Arguments:
  207. *
  208. * pCurNode - node to add to list
  209. *
  210. * Return Value:
  211. *
  212. * Status
  213. *
  214. * History:
  215. *
  216. * 5/20/1999 Original Version
  217. *
  218. \**************************************************************************/
  219. VOID
  220. CEventNotifier::LinkNode(
  221. PEventDestNode pCurNode)
  222. {
  223. DBG_FN(CEventNotifier::LinkNode);
  224. //
  225. // Put the new node at the head of the list
  226. //
  227. if (m_pEventDestNodes) {
  228. m_pEventDestNodes->pPrev = pCurNode;
  229. }
  230. pCurNode->pNext = m_pEventDestNodes;
  231. pCurNode->pPrev = NULL;
  232. m_pEventDestNodes = pCurNode;
  233. }
  234. /**************************************************************************\
  235. *
  236. * CEventNotifier::FireEventAsync
  237. *
  238. * Fires a Async event
  239. *
  240. * Arguments:
  241. *
  242. * pMasterInfo - Thread information
  243. *
  244. * Return Value:
  245. *
  246. * Status
  247. *
  248. * History:
  249. *
  250. * 8/9/1999 Original Version
  251. *
  252. \**************************************************************************/
  253. HRESULT
  254. CEventNotifier::FireEventAsync(
  255. PWIAEventThreadInfo pMasterInfo)
  256. {
  257. DBG_FN(CEventNotifier::FireEventAsync);
  258. HRESULT hr = E_OUTOFMEMORY;
  259. PWIAEventThreadInfo pInfo = NULL;
  260. DWORD dwThreadID;
  261. HANDLE hThread;
  262. do {
  263. pInfo = (PWIAEventThreadInfo)
  264. LocalAlloc(LPTR, sizeof(WIAEventThreadInfo));
  265. if (! pInfo) {
  266. break;
  267. }
  268. //
  269. // Copy information from the master thread info block
  270. //
  271. pInfo->eventGUID = pMasterInfo->eventGUID;
  272. pInfo->bstrDeviceID =
  273. SysAllocString(pMasterInfo->bstrDeviceID);
  274. if (! pInfo->bstrDeviceID) {
  275. break;
  276. }
  277. pInfo->bstrEventDescription =
  278. SysAllocString(pMasterInfo->bstrEventDescription);
  279. if (! pInfo->bstrEventDescription) {
  280. break;
  281. }
  282. if (pMasterInfo->bstrDeviceDescription) {
  283. pInfo->bstrDeviceDescription =
  284. SysAllocString(pMasterInfo->bstrDeviceDescription);
  285. if (! pInfo->bstrDeviceDescription) {
  286. break;
  287. }
  288. }
  289. if (pMasterInfo->bstrFullItemName) {
  290. pInfo->bstrFullItemName =
  291. SysAllocString(pMasterInfo->bstrFullItemName);
  292. if (! pInfo->bstrFullItemName) {
  293. break;
  294. }
  295. }
  296. pInfo->dwDeviceType = pMasterInfo->dwDeviceType;
  297. pInfo->ulEventType = pMasterInfo->ulEventType;
  298. pInfo->ulReserved = pMasterInfo->ulReserved;
  299. pMasterInfo->pIEventCB->AddRef();
  300. hr = S_OK;
  301. pInfo->pIEventCB = pMasterInfo->pIEventCB;
  302. //
  303. // Fire the event callback
  304. //
  305. hThread = CreateThread(
  306. NULL, 0, EventThreadProc, pInfo, 0, &dwThreadID);
  307. if (hThread) {
  308. //
  309. // Close the handler, so that kernel mode thread object is
  310. // closed when the thread finishes its mission
  311. //
  312. CloseHandle(hThread);
  313. } else {
  314. hr = HRESULT_FROM_WIN32(GetLastError());
  315. }
  316. //
  317. // Don't wait for completion
  318. //
  319. } while (FALSE);
  320. //
  321. // The notification should free the allocated resources
  322. //
  323. if (hr == S_OK) {
  324. return (hr);
  325. }
  326. if (hr == E_OUTOFMEMORY) {
  327. DBG_ERR(("FireEventAsync : Memory alloc failed"));
  328. }
  329. //
  330. // Garbage collection to avoid memory leak
  331. //
  332. if (pInfo) {
  333. if (pInfo->bstrDeviceDescription) {
  334. SysFreeString(pInfo->bstrDeviceDescription);
  335. }
  336. if (pInfo->bstrDeviceID) {
  337. SysFreeString(pInfo->bstrDeviceID);
  338. }
  339. if (pInfo->bstrEventDescription) {
  340. SysFreeString(pInfo->bstrEventDescription);
  341. }
  342. if (pInfo->bstrFullItemName) {
  343. SysFreeString(pInfo->bstrFullItemName);
  344. }
  345. if (pInfo->pIEventCB) {
  346. pInfo->pIEventCB->Release();
  347. }
  348. LocalFree(pInfo);
  349. }
  350. return (hr);
  351. }
  352. /**************************************************************************\
  353. * CEventNotifier::NotifySTIEvent
  354. *
  355. * Search through list of registered events and notify anyone who
  356. * matched current event
  357. *
  358. * Arguments:
  359. *
  360. * pWiaNotify - Event infor
  361. *
  362. * Return Value:
  363. *
  364. * Status
  365. *
  366. * History:
  367. *
  368. * 5/18/1999 Original Version
  369. *
  370. \**************************************************************************/
  371. HRESULT
  372. CEventNotifier::NotifySTIEvent(
  373. PWIANOTIFY pWiaNotify,
  374. ULONG ulEventType,
  375. BSTR bstrFullItemName)
  376. {
  377. DBG_FN(CEventNotifier::NotifySTIEvent);
  378. HRESULT hr = S_FALSE;
  379. EventDestNode *pCurNode;
  380. BOOL bDeviceLocked;
  381. DWORD dwDeviceType;
  382. BSTR bstrDevDescription = NULL;
  383. IWiaMiniDrv *pIWiaMiniDrv = NULL;
  384. WIA_DEV_CAP_DRV *pWiaDrvDevCap = NULL;
  385. BSTR bstrEventDescription = NULL;
  386. LONG lNumEntries = 0;
  387. LONG i = 0;
  388. LONG lDevErrVal;
  389. WIAEventThreadInfo masterInfo;
  390. ULONG ulNumHandlers;
  391. EventDestNode *pDefHandlerNode;
  392. IWiaEventCallback *pIEventCB;
  393. ACTIVE_DEVICE *pDevice = NULL;
  394. ULONG *pulTemp;
  395. WiaEventInfo *pWiaEventInfo = NULL;
  396. do {
  397. ZeroMemory(&masterInfo, sizeof(masterInfo));
  398. //
  399. // Get device information from STI active device list
  400. //
  401. hr = WiaGetDeviceInfo(
  402. pWiaNotify->bstrDevId,
  403. &dwDeviceType,
  404. &bstrDevDescription,
  405. &pDevice);
  406. if (hr != S_OK) {
  407. DBG_ERR(("Failed to get WiaGetDeviceInfo from NotifySTIEvent, 0x%X", hr));
  408. break;
  409. }
  410. //
  411. // Make sure we only grab global event Critical Section AFTER we've released the
  412. // device list Critical Section (used and released in WiaGetDeviceInfo).
  413. //
  414. CWiaCritSect CritSect(&g_semEventNode);
  415. //
  416. // QI for the WIA mini driver interface
  417. //
  418. hr = pDevice->m_DrvWrapper.QueryInterface(
  419. IID_IWiaMiniDrv, (void **)&pIWiaMiniDrv);
  420. if (FAILED(hr)) {
  421. DBG_WRN(("Failed to QI for IWiaMini from NotifySTIEvent (0x%X)", hr));
  422. }
  423. //
  424. // Hardware might be gone, access to it should not be allowed
  425. //
  426. bDeviceLocked = FALSE;
  427. if (SUCCEEDED(hr)) {
  428. __try {
  429. __try {
  430. //
  431. // Notify the mini driver of the new event.
  432. // NOTE: We don't lock here. The event must be delivered
  433. // to the driver regardless. A queued system would
  434. // be better, but it MUST guarantee delivery.
  435. //
  436. hr = pDevice->m_DrvWrapper.WIA_drvNotifyPnpEvent(
  437. &pWiaNotify->stiNotify.guidNotificationCode,
  438. pWiaNotify->bstrDevId,
  439. 0);
  440. if (FAILED(hr)) {
  441. __leave;
  442. }
  443. //
  444. // This is a "work-around" for our in-box HP scanner driver, which
  445. // calls down to the microdriver even after it has been informed
  446. // via drvNotifyPnPEvent that the device no longer exists...
  447. // Only if this is not a disconnect event, do we want to
  448. // call driver
  449. //
  450. if (pWiaNotify->stiNotify.guidNotificationCode != WIA_EVENT_DEVICE_DISCONNECTED) {
  451. //
  452. // Lock the device since the drvInitializeWia may have not been
  453. // called and the IWiaMiniDrv can not lock the device
  454. //
  455. // NOTE: Timeout is 20sec
  456. //
  457. // NOTE: We don't lock serial devices here...
  458. // , this function on a connection should be as fast as possible
  459. //
  460. if (!( pDevice->m_DrvWrapper.getHWConfig() & STI_HW_CONFIG_SERIAL) ||
  461. !IsEqualGUID(pWiaNotify->stiNotify.guidNotificationCode,WIA_EVENT_DEVICE_CONNECTED)
  462. ) {
  463. hr = g_pStiLockMgr->RequestLock(pDevice, 20000);
  464. if (FAILED(hr)) {
  465. __leave;
  466. }
  467. bDeviceLocked = TRUE;
  468. }
  469. //
  470. // Note that a NULL context passed to the minidriver. This should be OK since
  471. // capabilities are not tied to any item context.
  472. //
  473. hr = pDevice->m_DrvWrapper.WIA_drvGetCapabilities(
  474. NULL,
  475. WIA_DEVICE_EVENTS,
  476. &lNumEntries,
  477. &pWiaDrvDevCap,
  478. &lDevErrVal);
  479. }
  480. }
  481. __finally {
  482. //
  483. // Unlock the device first
  484. //
  485. if (bDeviceLocked) {
  486. g_pStiLockMgr->RequestUnlock(pDevice);
  487. bDeviceLocked = FALSE;
  488. }
  489. }
  490. }
  491. __except(EXCEPTION_EXECUTE_HANDLER) {
  492. DBG_ERR(("NotifySTIEvent() : Exception happened in the drvGetCapabilities"));
  493. SysFreeString(bstrDevDescription);
  494. if (pIWiaMiniDrv) {
  495. pIWiaMiniDrv->Release();
  496. }
  497. return (E_FAIL);
  498. }
  499. }
  500. //
  501. // Mini driver failed the operation
  502. //
  503. if (SUCCEEDED(hr)) {
  504. if (pWiaDrvDevCap) {
  505. __try {
  506. //
  507. // Retrieve event related information
  508. //
  509. for (i = 0; i < lNumEntries; i++) {
  510. if (pWiaDrvDevCap[i].guid != NULL) {
  511. if (*pWiaDrvDevCap[i].guid == pWiaNotify->stiNotify.guidNotificationCode) {
  512. if (! ulEventType) {
  513. ulEventType = pWiaDrvDevCap[i].ulFlags;
  514. }
  515. bstrEventDescription = SysAllocString(pWiaDrvDevCap[i].wszDescription);
  516. break;
  517. }
  518. } else {
  519. DBG_WRN(("NotifySTIEvent() : Driver's event guid is NULL, index = %d", i));
  520. }
  521. }
  522. }
  523. __except(EXCEPTION_EXECUTE_HANDLER) {
  524. DBG_ERR(("NotifySTIEvent() : Exception occurred while accessing driver's event array"));
  525. hr = E_FAIL;
  526. }
  527. //
  528. // The device is not supposed to generate this event
  529. //
  530. if ((i == lNumEntries) || (!bstrEventDescription)) {
  531. DBG_ERR(("NotifySTIEvent() : Event description is NULL or Event GUID not found"));
  532. hr = E_FAIL;
  533. }
  534. }
  535. else {
  536. // Minidriver is wrong, claiming success and returning NULL
  537. DBG_ERR(("NotifySTIEvent() got NULL cap list from drivers .") );
  538. hr = E_FAIL;
  539. }
  540. }
  541. //
  542. // Make sure device connected and device disconnected have at least the
  543. // notification bit set.
  544. //
  545. if ((pWiaNotify->stiNotify.guidNotificationCode == WIA_EVENT_DEVICE_CONNECTED) ||
  546. (pWiaNotify->stiNotify.guidNotificationCode == WIA_EVENT_DEVICE_DISCONNECTED))
  547. {
  548. ulEventType |= WIA_NOTIFICATION_EVENT;
  549. }
  550. //
  551. // If the event is a connect or diconnect event, always fire it.
  552. //
  553. if (FAILED(hr) &&
  554. ((pWiaNotify->stiNotify.guidNotificationCode == WIA_EVENT_DEVICE_CONNECTED) ||
  555. (pWiaNotify->stiNotify.guidNotificationCode == WIA_EVENT_DEVICE_DISCONNECTED))) {
  556. DBG_WRN(("NotifySTIEvent() : hr indicates FAILURE, but event is Connect/Disconnect"));
  557. //
  558. // Set the event type and string
  559. //
  560. if (! ulEventType) {
  561. ulEventType = WIA_NOTIFICATION_EVENT;
  562. }
  563. if (pWiaNotify->stiNotify.guidNotificationCode == WIA_EVENT_DEVICE_CONNECTED) {
  564. bstrEventDescription = SysAllocString(WIA_EVENT_DEVICE_CONNECTED_STR);
  565. } else {
  566. bstrEventDescription = SysAllocString(WIA_EVENT_DEVICE_DISCONNECTED_STR);
  567. }
  568. }
  569. //
  570. // Prepare the master thread info block
  571. //
  572. masterInfo.eventGUID = pWiaNotify->stiNotify.guidNotificationCode;
  573. masterInfo.bstrEventDescription = bstrEventDescription;
  574. masterInfo.bstrDeviceID = pWiaNotify->bstrDevId;
  575. masterInfo.bstrDeviceDescription = bstrDevDescription;
  576. masterInfo.dwDeviceType = dwDeviceType;
  577. //
  578. // Retrieve the full item name set by the driver
  579. //
  580. masterInfo.bstrFullItemName = bstrFullItemName;
  581. masterInfo.ulEventType = ulEventType;
  582. masterInfo.ulReserved = 0;
  583. masterInfo.pIEventCB = NULL;
  584. //
  585. // For Notification type of event
  586. //
  587. if (ulEventType & WIA_NOTIFICATION_EVENT) {
  588. //
  589. // We don't need to grab the g_semEventNode critical section for our
  590. // current runtime implementation. So we'll simply create a WiaEventInfo object
  591. // to describe the event, and we'll actually "fire" the event notifications
  592. // after we're out of this block.
  593. //
  594. pWiaEventInfo = new WiaEventInfo();
  595. if (pWiaEventInfo)
  596. {
  597. pWiaEventInfo->setEventGuid(pWiaNotify->stiNotify.guidNotificationCode);
  598. pWiaEventInfo->setDeviceID(pWiaNotify->bstrDevId);
  599. pWiaEventInfo->setEventDescription(bstrEventDescription);
  600. pWiaEventInfo->setDeviceDescription(bstrDevDescription);
  601. pWiaEventInfo->setFullItemName(bstrFullItemName);
  602. pWiaEventInfo->setDeviceType(dwDeviceType);
  603. pWiaEventInfo->setEventType(ulEventType);
  604. }
  605. else
  606. {
  607. DBG_ERR(("Cannot notify clients of runtime event - we appear to be out of memory"));
  608. hr = E_OUTOFMEMORY;
  609. }
  610. /* OLD CODE. Will be removed for .NET Server and replaced with alternate
  611. WIA runtime event behavior.
  612. for (pCurNode = m_pEventDestNodes;
  613. pCurNode; pCurNode = pCurNode->pNext) {
  614. if (! pCurNode->pIEventCB) {
  615. continue;
  616. }
  617. if (
  618. (
  619. (wcscmp(pWiaNotify->bstrDevId, pCurNode->bstrDeviceID) == 0) ||
  620. (wcscmp(L"All", pCurNode->bstrDeviceID) == 0)
  621. ) &&
  622. (pWiaNotify->stiNotify.guidNotificationCode == pCurNode->iidEventGUID)
  623. ) {
  624. masterInfo.pIEventCB = pCurNode->pIEventCB;
  625. DBG_WRN(("NotifySTIEvent() : About to FireEventAsync(...)"));
  626. FireEventAsync(&masterInfo);
  627. }
  628. }
  629. */
  630. }
  631. //
  632. // For Action type of event, find the default handler and fire it
  633. //
  634. if (ulEventType & WIA_ACTION_EVENT) {
  635. #ifndef UNICODE
  636. //
  637. // Get whether there is an user logged in
  638. //
  639. HWND hWin;
  640. hWin = FindWindow("Progman", NULL);
  641. if (! hWin) {
  642. break;
  643. }
  644. #endif
  645. EnterCriticalSection(&g_RpcEvent.cs);
  646. if(g_RpcEvent.pAsync) {
  647. RPC_STATUS status;
  648. int nReply = 1;
  649. g_RpcEvent.pEvent->EventGuid = pWiaNotify->stiNotify.guidNotificationCode;
  650. g_RpcEvent.pEvent->bstrEventDescription = SysAllocString(bstrEventDescription);
  651. g_RpcEvent.pEvent->bstrDeviceID = SysAllocString(pWiaNotify->bstrDevId);
  652. g_RpcEvent.pEvent->bstrDeviceDescription = SysAllocString(bstrDevDescription);
  653. g_RpcEvent.pEvent->dwDeviceType = dwDeviceType;
  654. g_RpcEvent.pEvent->bstrFullItemName = SysAllocString(bstrFullItemName);
  655. g_RpcEvent.pEvent->ulEventType = ulEventType;
  656. status = RpcAsyncCompleteCall(g_RpcEvent.pAsync, &nReply);
  657. if(status) {
  658. DBG_ERR(("RpcAsyncComplete failed with error 0x%x", status));
  659. } else {
  660. DBG_ERR(("Completed RPC call"));
  661. }
  662. g_RpcEvent.pAsync = NULL;
  663. } else {
  664. DBG_ERR(("Did not have pAsync for this event"));
  665. }
  666. LeaveCriticalSection(&g_RpcEvent.cs);
  667. #if 0
  668. GetNumPersistentHandlerAndDefault(
  669. pWiaNotify->bstrDevId,
  670. &pWiaNotify->stiNotify.guidNotificationCode,
  671. &ulNumHandlers,
  672. &pDefHandlerNode);
  673. if (pDefHandlerNode) {
  674. if (pDefHandlerNode->tszCommandline[0] != '\0') {
  675. //
  676. // This is a traditional handler with command line
  677. //
  678. StartCallbackProgram(
  679. pDefHandlerNode, &masterInfo);
  680. } else {
  681. hr = _CoCreateInstanceInConsoleSession(
  682. pDefHandlerNode->ClsID,
  683. NULL,
  684. CLSCTX_LOCAL_SERVER,
  685. IID_IWiaEventCallback,
  686. (void**)&pIEventCB);
  687. if (SUCCEEDED(hr)) {
  688. masterInfo.pIEventCB = pIEventCB;
  689. FireEventAsync(&masterInfo);
  690. //
  691. // Release the callback interface
  692. //
  693. pIEventCB->Release();
  694. } else {
  695. DBG_ERR(("NotifySTIEvent:CoCreateInstance of event callback failed (0x%X)", hr));
  696. }
  697. }
  698. }
  699. #endif
  700. }
  701. } while (FALSE);
  702. //
  703. // Check whether we need to notify runtime clients of event. We know that we need to
  704. // notify clients if pWiaEventInfo is not NULL, since it contains the runtime event info.
  705. //
  706. if (pWiaEventInfo)
  707. {
  708. //
  709. // Notify registered clients of the event.
  710. //
  711. if (g_pWiaEventNotifier)
  712. {
  713. g_pWiaEventNotifier->NotifyClients(pWiaEventInfo);
  714. }
  715. pWiaEventInfo->Release();
  716. pWiaEventInfo = NULL;
  717. }
  718. //
  719. // Release the temporary BSTRs
  720. //
  721. if (bstrDevDescription) {
  722. SysFreeString(bstrDevDescription);
  723. }
  724. if (bstrEventDescription) {
  725. SysFreeString(bstrEventDescription);
  726. }
  727. if (masterInfo.bstrFullItemName) {
  728. SysFreeString(masterInfo.bstrFullItemName);
  729. }
  730. if (pDevice) {
  731. pDevice->Release();
  732. pDevice = NULL;
  733. }
  734. if (pIWiaMiniDrv) {
  735. pIWiaMiniDrv->Release();
  736. pIWiaMiniDrv = NULL;
  737. }
  738. return (hr);
  739. }
  740. /**************************************************************************\
  741. * CEventNotifier::RegisterEventCallback
  742. *
  743. * Register for event callbacks based on an interface
  744. *
  745. * Arguments:
  746. *
  747. * lFlags - op flags, register/unregister
  748. * bstrDeviceID - device ID registering for
  749. * pEventGUID - Event GUID to register for
  750. * pIWiaEventCallback - interface to call with event
  751. * ppEventObj -
  752. *
  753. * Return Value:
  754. *
  755. * Status
  756. *
  757. * History:
  758. *
  759. * 11/19/1998 Original Version
  760. *
  761. \**************************************************************************/
  762. HRESULT
  763. CEventNotifier::RegisterEventCallback(
  764. LONG lFlags,
  765. BSTR bstrDeviceID,
  766. const GUID *pEventGUID,
  767. IWiaEventCallback *pIWiaEventCallback,
  768. IUnknown **ppEventObj)
  769. {
  770. DBG_FN(CEventNotifier::RegisterEventCallback);
  771. HRESULT hr = E_FAIL;
  772. PEventDestNode pEventNode = NULL;
  773. DBG_TRC(("CEventNotifier::RegisterEventCallback flag %d", lFlags));
  774. ASSERT(pIWiaEventCallback != NULL);
  775. ASSERT(ppEventObj != NULL);
  776. ASSERT(pEventGUID != NULL);
  777. //
  778. // must have exclusive access when changing list
  779. //
  780. CWiaCritSect CritSect(&g_semEventNode);
  781. //
  782. // if bstrDeviceID is not NULL, make sure it is a device ID
  783. //
  784. if (bstrDeviceID) {
  785. /* No longer valid
  786. #ifdef WINNT
  787. if (wcslen(bstrDeviceID) != 43) { // {...}\DDDD
  788. #else
  789. if (wcslen(bstrDeviceID) != 10) { // Image\DDDD
  790. #endif
  791. DBG_ERR(("CEventNotifier::RegisterEventCallback: invalid DeviceID"));
  792. return (E_INVALIDARG);
  793. }
  794. */
  795. }
  796. //
  797. // Check whether the same CB interface is already registered
  798. //
  799. pEventNode = FindEventCBNode(FLAG_EN_FINDCB_EXACT_MATCH,bstrDeviceID, pEventGUID, pIWiaEventCallback);
  800. if (! pEventNode) {
  801. hr = RegisterEventCB(
  802. bstrDeviceID,
  803. pEventGUID,
  804. pIWiaEventCallback,
  805. ppEventObj);
  806. }
  807. return (hr);
  808. }
  809. /**************************************************************************\
  810. * CEventNotifier::RegisterEventCallback
  811. *
  812. * Register event based on CLSID
  813. *
  814. * Arguments:
  815. *
  816. * lFlags - op flags, register/unregister, set default
  817. * bstrDeviceID - device ID registering for
  818. * pEventGUID - Event GUID to register for
  819. * pClsid - CLSID to call CoCreateInst on with event
  820. * bstrDescription -
  821. * bstrIcon -
  822. *
  823. * Return Value:
  824. *
  825. * Status
  826. *
  827. * History:
  828. *
  829. * 12/8/1998 Original Version
  830. *
  831. \**************************************************************************/
  832. HRESULT
  833. CEventNotifier::RegisterEventCallback(
  834. LONG lFlags,
  835. BSTR bstrDeviceID,
  836. const GUID *pEventGUID,
  837. const GUID *pClsid,
  838. LPCTSTR ptszCommandline,
  839. BSTR bstrName,
  840. BSTR bstrDescription,
  841. BSTR bstrIcon)
  842. {
  843. DBG_FN(CEventNotifier::RegisterEventCallback (CLSID));
  844. HRESULT hr = S_OK;
  845. SYSTEMTIME sysTime;
  846. FILETIME fileTime;
  847. PEventDestNode pEventNode = NULL;
  848. CLSID clsidApp;
  849. RPC_STATUS rpcStatus;
  850. BOOL bUnRegCOMServer;
  851. BOOL bShowPrompt = FALSE;
  852. ULONG ulNumExistingHandlers = 0;
  853. EventDestNode ednTempNode;
  854. DBG_TRC(("CEventNotifier::RegisterEventCallback flag %d", lFlags));
  855. ASSERT(pEventGUID != NULL);
  856. //DBG_WRN(("RegisterEventCallback: CommandLine=%s"),ptszCommandline);
  857. //
  858. // Must have exclusive access when changing list
  859. //
  860. CWiaCritSect CritSect(&g_semEventNode);
  861. //
  862. // If there is a device ID, check if id looks proper.
  863. //
  864. if (bstrDeviceID) {
  865. //
  866. // An empty device ID is the same as NULL
  867. //
  868. if (wcslen(bstrDeviceID) == 0) {
  869. bstrDeviceID = NULL;
  870. } else {
  871. /* No longer valid
  872. #ifdef WINNT
  873. if (wcslen(bstrDeviceID) != 43) { // {...}\DDDD
  874. #else
  875. if (wcslen(bstrDeviceID) != 10) { // Image\DDDD
  876. #endif
  877. DBG_ERR(("RegisterEventCallback : invalid DeviceID"));
  878. return (E_INVALIDARG);
  879. }
  880. */
  881. }
  882. }
  883. //
  884. // Default handler is per device / per event
  885. //
  886. if ((lFlags == WIA_SET_DEFAULT_HANDLER) && (! bstrDeviceID)) {
  887. DBG_ERR(("RegisterEventCallback : DeviceID required to set default handler"));
  888. return (E_INVALIDARG);
  889. }
  890. //
  891. // Check whether a callback node with the same commandline already exist
  892. //
  893. if (ptszCommandline) {
  894. //
  895. // Do parameter check. Note that we look for >= MAX_PATH because
  896. // we still need space for terminating NULL.
  897. //
  898. if ((lstrlen(ptszCommandline) / sizeof(TCHAR)) >= MAX_PATH) {
  899. DBG_ERR(("RegisterEventCallback: ptszCommandline is greater than MAX_PATH characters!"));
  900. return E_INVALIDARG;
  901. }
  902. hr = FindCLSIDForCommandline(ptszCommandline, &clsidApp);
  903. if (FAILED(hr)) {
  904. //
  905. // Generate a CLSID for the callbacl program
  906. //
  907. rpcStatus = UuidCreate(&clsidApp);
  908. if (FAILED(rpcStatus)) {
  909. return (rpcStatus);
  910. }
  911. }
  912. //
  913. // Assign the faked CLSID for the callback program
  914. //
  915. pClsid = &clsidApp;
  916. }
  917. ASSERT(pClsid != NULL);
  918. switch (lFlags) {
  919. case WIA_REGISTER_EVENT_CALLBACK :
  920. DBG_WRN(("RegisterEventCallback : Setting handler for %S", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  921. //
  922. // REMOVE: This is not actually an error, but we will use error logging to gurantee
  923. // it always get written to the log. This should be removed as soon as we know what
  924. // causes #347835.
  925. //
  926. DBG_ERR(("RegisterEventCallback : Setting handler for %S", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  927. DBG_ERR(("RegisterEventCallback : Handler is %S", (bstrName) ? (bstrName) : L"NULL"));
  928. //
  929. // Name, description, and icon are required
  930. //
  931. if ((! bstrName) || (! bstrDescription) || (! bstrIcon)) {
  932. DBG_ERR(("RegisterEventCallback : Name | Description | Icon are missing"));
  933. return (E_INVALIDARG);
  934. }
  935. //
  936. // Check whether the same CB interface is already registered
  937. //
  938. pEventNode = FindEventCBNode(0,bstrDeviceID, pEventGUID, pClsid);
  939. if (pEventNode) {
  940. break;
  941. }
  942. //
  943. // Find the handler of the CLSID for all the devices
  944. //
  945. pEventNode = FindEventCBNode(0,NULL, pEventGUID, pClsid);
  946. //
  947. // Initialize the time stamp for the registration
  948. //
  949. //GetSystemTime(&sysTime);
  950. //SystemTimeToFileTime(&sysTime, &fileTime);
  951. memset(&fileTime, 0, sizeof(fileTime));
  952. if (! pEventNode) {
  953. hr = RegisterEventCB(
  954. bstrDeviceID,
  955. pEventGUID,
  956. pClsid,
  957. ptszCommandline,
  958. bstrName,
  959. bstrDescription,
  960. bstrIcon,
  961. fileTime);
  962. if (FAILED(hr)) {
  963. break;
  964. }
  965. hr = SavePersistentEventCB(
  966. bstrDeviceID,
  967. pEventGUID,
  968. pClsid,
  969. ptszCommandline,
  970. bstrName,
  971. bstrDescription,
  972. bstrIcon,
  973. NULL,
  974. &ulNumExistingHandlers);
  975. } else {
  976. hr = RegisterEventCB(
  977. bstrDeviceID,
  978. pEventGUID,
  979. pClsid,
  980. pEventNode->tszCommandline,
  981. pEventNode->bstrName,
  982. pEventNode->bstrDescription,
  983. pEventNode->bstrIcon,
  984. fileTime);
  985. if (FAILED(hr)) {
  986. break;
  987. }
  988. hr = SavePersistentEventCB(
  989. bstrDeviceID,
  990. pEventGUID,
  991. pClsid,
  992. pEventNode->tszCommandline,
  993. pEventNode->bstrName,
  994. pEventNode->bstrDescription,
  995. pEventNode->bstrIcon,
  996. NULL,
  997. &ulNumExistingHandlers);
  998. }
  999. //
  1000. // If this is the only event handler, make it the default. This will guarantee that
  1001. // there is always a default handler.
  1002. //
  1003. if (ulNumExistingHandlers == 0) {
  1004. RegisterEventCallback(WIA_SET_DEFAULT_HANDLER,
  1005. bstrDeviceID,
  1006. pEventGUID,
  1007. pClsid,
  1008. ptszCommandline,
  1009. bstrName,
  1010. bstrDescription,
  1011. bstrIcon);
  1012. };
  1013. //
  1014. // Check whether this is a registration for a global handler.
  1015. //
  1016. if (!bstrDeviceID) {
  1017. //
  1018. // This is a global event handler, so find out how many global handlers
  1019. // there are for this event. If there is more than one, make sure
  1020. // the prompt is Registered.
  1021. //
  1022. PEventDestNode pTempEventNode = NULL;
  1023. BSTR bstrGlobalDeviceID = SysAllocString(L"All");
  1024. if (bstrGlobalDeviceID) {
  1025. GetNumPersistentHandlerAndDefault(bstrGlobalDeviceID,
  1026. pEventGUID,
  1027. &ulNumExistingHandlers,
  1028. &pTempEventNode);
  1029. if (ulNumExistingHandlers > 1) {
  1030. //
  1031. // If the number of global handlers is > 1, then we must register the prompt.
  1032. //
  1033. DBG_ERR(("RegisterEventCallback : Registering Prompt Dialog as global handler"));
  1034. BSTR bstrInternalString = SysAllocString(L"Internal");
  1035. if (bstrInternalString) {
  1036. RegisterEventCallback(WIA_REGISTER_EVENT_CALLBACK,
  1037. bstrDeviceID,
  1038. pEventGUID,
  1039. &WIA_EVENT_HANDLER_PROMPT,
  1040. NULL,
  1041. bstrInternalString,
  1042. bstrInternalString,
  1043. bstrInternalString);
  1044. SysFreeString(bstrInternalString);
  1045. } else {
  1046. DBG_ERR(("RegisterEventCallback : Out of memory!"));
  1047. }
  1048. }
  1049. SysFreeString(bstrGlobalDeviceID);
  1050. bstrGlobalDeviceID = NULL;
  1051. }
  1052. }
  1053. break;
  1054. case WIA_SET_DEFAULT_HANDLER :
  1055. DBG_WRN(("RegisterEventCallback (set default) : Setting default handler for for %S", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  1056. //
  1057. // REMOVE: This is not actually an error, but we will use error logging to gurantee
  1058. // it always get written to the log. This should be removed as soon as we know what
  1059. // causes #347835.
  1060. //
  1061. DBG_ERR(("RegisterEventCallback (set default) : Setting handler for %S", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  1062. DBG_ERR(("RegisterEventCallback (set default) : Handler is %S", (bstrName) ? (bstrName) : L"NULL"));
  1063. //
  1064. // Find the handler of the CLSID for this devices. Note that STI proxy event match is considered here
  1065. // to allow for STI handlers to be default.
  1066. //
  1067. //
  1068. DBG_WRN(("RegisterEventCallback (set default): CommandLine=%S \n",ptszCommandline));
  1069. #ifdef DEBUG
  1070. WCHAR wszGUIDStr[40];
  1071. StringFromGUID2(*pEventGUID, wszGUIDStr, 40);
  1072. DBG_WRN(("SetDefaultHandler: DevId=%S EventUID=%S Commandline=%S",
  1073. (bstrDeviceID) ? (bstrDeviceID) : L"*",
  1074. wszGUIDStr,
  1075. ptszCommandline));
  1076. #endif
  1077. {
  1078. //
  1079. // Find the existing default handler node, and clear the flag indicating it is
  1080. // the default, since it will now be replaced by a new default
  1081. //
  1082. ULONG ulNumHandlers = 0;
  1083. PEventDestNode pDefaultNode = NULL;
  1084. hr = GetNumPersistentHandlerAndDefault(bstrDeviceID,
  1085. pEventGUID,
  1086. &ulNumHandlers,
  1087. &pDefaultNode);
  1088. if (SUCCEEDED(hr) && pDefaultNode) {
  1089. //
  1090. // Clear the flag indicating that it is the default handler, since the
  1091. // current node will now replace it as the default.
  1092. //
  1093. pDefaultNode->bDeviceDefault = FALSE;
  1094. }
  1095. }
  1096. pEventNode = FindEventCBNode(0,bstrDeviceID, pEventGUID, pClsid);
  1097. if (! pEventNode) {
  1098. //
  1099. // Find the handler of the CLSID for all the devices
  1100. //
  1101. pEventNode = FindEventCBNode(0,NULL, pEventGUID, pClsid);
  1102. if (! pEventNode) {
  1103. //
  1104. // We couldn't find an existing node for this handler, so fill in
  1105. // information to the temporary event node so we can register this
  1106. // new one anyway.
  1107. //
  1108. memset(&ednTempNode, 0, sizeof(ednTempNode));
  1109. if (ptszCommandline) {
  1110. lstrcpy(ednTempNode.tszCommandline, ptszCommandline);
  1111. }
  1112. ednTempNode.bstrName = bstrName;
  1113. ednTempNode.bstrDescription = bstrDescription;
  1114. ednTempNode.bstrIcon = bstrIcon;
  1115. pEventNode = &ednTempNode;
  1116. }
  1117. //
  1118. // Register the handler of the CLSID for this device
  1119. //
  1120. GetSystemTime(&sysTime);
  1121. SystemTimeToFileTime(&sysTime, &fileTime);
  1122. DBG_WRN(("SetDefaultHandler:Found event node EvName=%S CommandLine=%S",
  1123. pEventNode->bstrName,
  1124. pEventNode->tszCommandline));
  1125. hr = RegisterEventCB(
  1126. bstrDeviceID,
  1127. pEventGUID,
  1128. pClsid,
  1129. pEventNode->tszCommandline,
  1130. pEventNode->bstrName,
  1131. pEventNode->bstrDescription,
  1132. pEventNode->bstrIcon,
  1133. fileTime,
  1134. TRUE);
  1135. if (FAILED(hr)) {
  1136. DBG_WRN(("RegisterEventCallback : RegisterEventCB for %S failed", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  1137. break;
  1138. }
  1139. } else {
  1140. //
  1141. // Change the time stamp so that it is regarded as default
  1142. //
  1143. GetSystemTime(&sysTime);
  1144. SystemTimeToFileTime(&sysTime, &pEventNode->timeStamp);
  1145. //
  1146. // NOTE: Timestamps not valid on Win9x, so use a flag to indicate default handler.
  1147. // Change this node's flag to indicate this is the default
  1148. //
  1149. pEventNode->bDeviceDefault = TRUE;
  1150. DBG_WRN(("RegisterEventCallback : Resetting default handler for %S", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  1151. }
  1152. //
  1153. // Save the persistent event callback node. Note that we specify TRUE as the last
  1154. // parameter to indicate that the default handler is now this node. This will
  1155. // cause a registry entry to be written that indicates this as the default handler.
  1156. //
  1157. hr = SavePersistentEventCB(
  1158. bstrDeviceID,
  1159. pEventGUID,
  1160. pClsid,
  1161. pEventNode->tszCommandline,
  1162. pEventNode->bstrName,
  1163. pEventNode->bstrDescription,
  1164. pEventNode->bstrIcon,
  1165. &bShowPrompt,
  1166. &ulNumExistingHandlers,
  1167. TRUE);
  1168. if (FAILED(hr)) {
  1169. DBG_ERR(("SetDefaultHandler:SavePers CommandLine=%S failed with hr = 0x%08X!!!!",pEventNode->tszCommandline, hr));
  1170. }
  1171. break;
  1172. case WIA_UNREGISTER_EVENT_CALLBACK :
  1173. hr = UnregisterEventCB(
  1174. bstrDeviceID, pEventGUID, pClsid, &bUnRegCOMServer);
  1175. if (FAILED(hr)) {
  1176. DBG_ERR(("CEventNotifier::RegisterEventCallback, UnregisterEventCB failed"));
  1177. break;
  1178. }
  1179. hr = DelPersistentEventCB(
  1180. bstrDeviceID, pEventGUID, pClsid, bUnRegCOMServer);
  1181. if (FAILED(hr)) {
  1182. DBG_ERR(("CEventNotifier::RegisterEventCallback, DelPersistentEventCB failed"));
  1183. }
  1184. break;
  1185. default:
  1186. hr = E_FAIL;
  1187. break;
  1188. }
  1189. if (bShowPrompt && (*pClsid != WIA_EVENT_HANDLER_PROMPT)) {
  1190. //
  1191. // This is a new event handler being registered. Our semantics are as follows:
  1192. // The new application may not simply override any existing handlers. Therefore,
  1193. // if a default handler already exists for this device, we must show a prompt.
  1194. //
  1195. if (ulNumExistingHandlers > 0) {
  1196. //
  1197. // This is a new default event registration, so
  1198. // we must show Prompt dialog
  1199. //
  1200. DBG_WRN(("RegisterEventCallback : About to Register Prompt Dialog for device %S", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  1201. BSTR bstrInternalString = SysAllocString(L"Internal");
  1202. if (bstrInternalString) {
  1203. RegisterEventCallback(WIA_SET_DEFAULT_HANDLER,
  1204. bstrDeviceID,
  1205. pEventGUID,
  1206. &WIA_EVENT_HANDLER_PROMPT,
  1207. NULL,
  1208. bstrInternalString,
  1209. bstrInternalString,
  1210. bstrInternalString);
  1211. SysFreeString(bstrInternalString);
  1212. }
  1213. DBG_WRN(("RegisterEventCallback : Registered Prompt Dialog for device %S", (bstrDeviceID) ? (bstrDeviceID) : L"*"));
  1214. }
  1215. }
  1216. return (hr);
  1217. }
  1218. /**************************************************************************\
  1219. * CEventNotifier::RegisterEventCB
  1220. *
  1221. * add event notify to list
  1222. *
  1223. * Arguments:
  1224. *
  1225. * bstrDeviceID - device event is being registered to monitor
  1226. * pEventGUID - guid that defines device event of interest
  1227. * pIWiaEventCallback - app's event interface
  1228. *
  1229. * Return Value:
  1230. *
  1231. * Status
  1232. *
  1233. * History:
  1234. *
  1235. * 11/4/1998 Original Version
  1236. *
  1237. \**************************************************************************/
  1238. HRESULT
  1239. CEventNotifier::RegisterEventCB(
  1240. BSTR bstrDeviceID,
  1241. const GUID *pEventGUID,
  1242. IWiaEventCallback *pIWiaEventCallback,
  1243. IUnknown **ppIEventObj)
  1244. {
  1245. DBG_FN(CEventNotifier::RegisterEventCB);
  1246. HRESULT hr;
  1247. PEventDestNode pEventDestNode = NULL;
  1248. ASSERT(pIWiaEventCallback != NULL);
  1249. ASSERT(pEventGUID != NULL);
  1250. if (!pEventGUID || !pIWiaEventCallback) {
  1251. return E_POINTER;
  1252. }
  1253. //
  1254. // Allocate and initialize the new node
  1255. //
  1256. pEventDestNode = (EventDestNode *)LocalAlloc(LPTR, sizeof(EventDestNode));
  1257. if (! pEventDestNode) {
  1258. DBG_ERR(("RegisterEventCB: Out of memory"));
  1259. return (E_OUTOFMEMORY);
  1260. }
  1261. // Initialize default flag
  1262. pEventDestNode->bDeviceDefault = FALSE;
  1263. //
  1264. // is a device name given? If not then match all devices
  1265. //
  1266. if (bstrDeviceID == NULL) {
  1267. pEventDestNode->bstrDeviceID = SysAllocString(L"All");
  1268. } else {
  1269. pEventDestNode->bstrDeviceID = SysAllocString(bstrDeviceID);
  1270. }
  1271. //
  1272. // check allocs
  1273. //
  1274. if (pEventDestNode->bstrDeviceID == NULL) {
  1275. LocalFree(pEventDestNode);
  1276. DBG_ERR(("RegisterEventCB: Out of memory"));
  1277. return (E_OUTOFMEMORY);
  1278. }
  1279. //
  1280. // create an object to track the lifetime of this event
  1281. //
  1282. CWiaInterfaceEvent *pEventObj = new CWiaInterfaceEvent(pEventDestNode);
  1283. if (pEventObj == NULL) {
  1284. DBG_ERR(("RegisterEventCB: Out of memory"));
  1285. SysFreeString(pEventDestNode->bstrDeviceID);
  1286. LocalFree(pEventDestNode);
  1287. return (E_OUTOFMEMORY);
  1288. }
  1289. //
  1290. // get simple iunknown from object
  1291. //
  1292. hr = pEventObj->QueryInterface(IID_IUnknown,(void **)ppIEventObj);
  1293. if (FAILED(hr)) {
  1294. DBG_ERR(("RegisterEventCB: QI of pEventObj failed"));
  1295. delete pEventObj;
  1296. SysFreeString(pEventDestNode->bstrDeviceID);
  1297. LocalFree(pEventDestNode);
  1298. return (hr);
  1299. }
  1300. //
  1301. // add info to event list
  1302. //
  1303. pEventDestNode->iidEventGUID = *pEventGUID;
  1304. pIWiaEventCallback->AddRef();
  1305. pEventDestNode->pIEventCB = pIWiaEventCallback;
  1306. memset(&pEventDestNode->ClsID, 0, sizeof(pEventDestNode->ClsID));
  1307. //
  1308. // Put the new node at the head of the list
  1309. //
  1310. LinkNode(pEventDestNode);
  1311. return (S_OK);
  1312. }
  1313. /**************************************************************************\
  1314. * RegisterEventCB
  1315. *
  1316. *
  1317. *
  1318. * Arguments:
  1319. *
  1320. *
  1321. *
  1322. * Return Value:
  1323. *
  1324. * Status
  1325. *
  1326. * History:
  1327. *
  1328. * 12/8/1998 Original Version
  1329. *
  1330. \**************************************************************************/
  1331. HRESULT
  1332. CEventNotifier::RegisterEventCB(
  1333. BSTR bstrDeviceID,
  1334. const GUID *pEventGUID,
  1335. const GUID *pClsID,
  1336. LPCTSTR ptszCommandline,
  1337. BSTR bstrName,
  1338. BSTR bstrDescription,
  1339. BSTR bstrIcon,
  1340. FILETIME &timeStamp,
  1341. BOOL bIsDeafult) // = FALSE
  1342. {
  1343. DBG_FN(CEventNotifier::RegisterEventCB);
  1344. HRESULT hr = E_OUTOFMEMORY;
  1345. EventDestNode *pEventDestNode = NULL;
  1346. ASSERT(pClsID != NULL);
  1347. ASSERT(pEventGUID != NULL);
  1348. if (!pEventGUID || !pClsID) {
  1349. return E_POINTER;
  1350. }
  1351. do {
  1352. //
  1353. // Do parameter check. Note that we look for >= MAX_PATH because
  1354. // we still need space for terminating NULL.
  1355. //
  1356. if ((lstrlen(ptszCommandline) / sizeof(TCHAR)) >= MAX_PATH) {
  1357. DBG_ERR(("CEventNotifier::RegisterEventCB: ptszCommandline is greater than MAX_PATH characters!"));
  1358. hr = E_INVALIDARG;
  1359. break;
  1360. }
  1361. //
  1362. // Allocate and initialize the new node
  1363. //
  1364. pEventDestNode = (EventDestNode *)LocalAlloc(LPTR, sizeof(EventDestNode));
  1365. if (! pEventDestNode) {
  1366. DBG_ERR(("CEventNotifier::RegisterEventCB: Out of memory"));
  1367. break;
  1368. }
  1369. //
  1370. // Is a device name given ? If not then match all devices
  1371. //
  1372. if (bstrDeviceID == NULL) {
  1373. pEventDestNode->bstrDeviceID = SysAllocString(L"All");
  1374. } else {
  1375. pEventDestNode->bstrDeviceID = SysAllocString(bstrDeviceID);
  1376. }
  1377. //
  1378. // Check callback node allocation
  1379. //
  1380. if (pEventDestNode->bstrDeviceID == NULL) {
  1381. DBG_ERR(("CEventNotifier::RegisterEventCB: Out of memory"));
  1382. break;
  1383. }
  1384. //
  1385. // Add info to event callback node
  1386. //
  1387. pEventDestNode->iidEventGUID = *pEventGUID;
  1388. pEventDestNode->pIEventCB = NULL;
  1389. pEventDestNode->ClsID = *pClsID;
  1390. pEventDestNode->bstrName = SysAllocString(bstrName);
  1391. if (! pEventDestNode->bstrName) {
  1392. break;
  1393. }
  1394. pEventDestNode->bstrDescription = SysAllocString(bstrDescription);
  1395. if (! pEventDestNode->bstrDescription) {
  1396. break;
  1397. }
  1398. pEventDestNode->bstrIcon = SysAllocString(bstrIcon);
  1399. if (! pEventDestNode->bstrIcon) {
  1400. break;
  1401. }
  1402. //
  1403. // Copy the commandline of the callback app
  1404. //
  1405. if ((ptszCommandline) && (ptszCommandline[0])) {
  1406. _tcscpy(pEventDestNode->tszCommandline, ptszCommandline);
  1407. } else {
  1408. pEventDestNode->tszCommandline[0] = '\0';
  1409. }
  1410. //
  1411. // Set the time stamp of registration
  1412. //
  1413. pEventDestNode->timeStamp = timeStamp;
  1414. //
  1415. // Set whether this is the default event handler
  1416. //
  1417. if (bIsDeafult) {
  1418. pEventDestNode->bDeviceDefault = TRUE;
  1419. }
  1420. hr = S_OK;
  1421. } while (FALSE);
  1422. //
  1423. // Unwind the partial created node in case of failure
  1424. //
  1425. if (hr != S_OK) {
  1426. if (pEventDestNode) {
  1427. if (pEventDestNode->bstrDeviceID) {
  1428. SysFreeString(pEventDestNode->bstrDeviceID);
  1429. }
  1430. if (pEventDestNode->bstrName) {
  1431. SysFreeString(pEventDestNode->bstrName);
  1432. }
  1433. if (pEventDestNode->bstrDescription) {
  1434. SysFreeString(pEventDestNode->bstrDescription);
  1435. }
  1436. if (pEventDestNode->bstrIcon) {
  1437. SysFreeString(pEventDestNode->bstrIcon);
  1438. }
  1439. LocalFree(pEventDestNode);
  1440. }
  1441. return (hr);
  1442. }
  1443. //
  1444. // Put the new node at the header of the list
  1445. //
  1446. LinkNode(pEventDestNode);
  1447. return (S_OK);
  1448. }
  1449. /**************************************************************************\
  1450. * CEventNotifier::UnregisterEventCB
  1451. *
  1452. * Unregister the specified Event Callback
  1453. *
  1454. * Arguments:
  1455. *
  1456. *
  1457. *
  1458. * Return Value:
  1459. *
  1460. * Status
  1461. *
  1462. * History:
  1463. *
  1464. * 11/4/1998 Original Version
  1465. *
  1466. \**************************************************************************/
  1467. HRESULT
  1468. CEventNotifier::UnregisterEventCB(
  1469. PEventDestNode pCurNode)
  1470. {
  1471. DBG_FN(CEventNotifier::UnregisterEventCB);
  1472. ASSERT(pCurNode != NULL);
  1473. if (!pCurNode) {
  1474. return E_POINTER;
  1475. }
  1476. UnlinkNode(pCurNode);
  1477. //
  1478. // Free the node
  1479. //
  1480. if (pCurNode->bstrDeviceID) {
  1481. SysFreeString(pCurNode->bstrDeviceID);
  1482. }
  1483. if (pCurNode->bstrDescription) {
  1484. SysFreeString(pCurNode->bstrDescription);
  1485. }
  1486. if (pCurNode->bstrIcon) {
  1487. SysFreeString(pCurNode->bstrIcon);
  1488. }
  1489. pCurNode->pIEventCB->Release();
  1490. LocalFree(pCurNode);
  1491. return (S_OK);
  1492. }
  1493. /**************************************************************************\
  1494. * CEventNotifier::UnregisterEventCB
  1495. *
  1496. * Unregister the specified Event Callback
  1497. *
  1498. * Arguments:
  1499. *
  1500. *
  1501. *
  1502. * Return Value:
  1503. *
  1504. * Status
  1505. *
  1506. * History:
  1507. *
  1508. * 11/4/1998 Original Version
  1509. *
  1510. \**************************************************************************/
  1511. HRESULT
  1512. CEventNotifier::UnregisterEventCB(
  1513. BSTR bstrDeviceID,
  1514. const GUID *pEventGUID,
  1515. const GUID *pClsID,
  1516. BOOL *pbUnRegCOMServer)
  1517. {
  1518. DBG_FN(CEventNotifier::UnregisterEventCB);
  1519. HRESULT hr = E_INVALIDARG;
  1520. EventDestNode *pCurNode, *pNextNode;
  1521. int nHandlerRef;
  1522. //
  1523. // Clear out the return value
  1524. //
  1525. *pbUnRegCOMServer = FALSE;
  1526. //
  1527. // Delete the handler(s) from the list
  1528. //
  1529. pCurNode = m_pEventDestNodes;
  1530. while (pCurNode) {
  1531. if ((bstrDeviceID) &&
  1532. (lstrcmpiW(pCurNode->bstrDeviceID, bstrDeviceID))) {
  1533. pCurNode = pCurNode->pNext;
  1534. continue;
  1535. }
  1536. if ((*pEventGUID != pCurNode->iidEventGUID) ||
  1537. (*pClsID != pCurNode->ClsID)) {
  1538. pCurNode = pCurNode->pNext;
  1539. continue;
  1540. }
  1541. //
  1542. // Unlink the current node if it is not busy
  1543. //
  1544. pNextNode = pCurNode->pNext;
  1545. UnlinkNode(pCurNode);
  1546. //
  1547. // Need to consider deleteing the faked server
  1548. //
  1549. if (pCurNode->tszCommandline[0] != '\0') {
  1550. *pbUnRegCOMServer = TRUE;
  1551. }
  1552. //
  1553. // Free the node
  1554. //
  1555. if (pCurNode->bstrDeviceID) {
  1556. SysFreeString(pCurNode->bstrDeviceID);
  1557. }
  1558. if (pCurNode->bstrDescription) {
  1559. SysFreeString(pCurNode->bstrDescription);
  1560. }
  1561. if (pCurNode->bstrIcon) {
  1562. SysFreeString(pCurNode->bstrIcon);
  1563. }
  1564. LocalFree(pCurNode);
  1565. hr = S_OK;
  1566. //
  1567. // Delete the event handler for specific device
  1568. //
  1569. if (bstrDeviceID) {
  1570. break;
  1571. }
  1572. //
  1573. // Move on to the next node
  1574. //
  1575. pCurNode = pNextNode;
  1576. }
  1577. //
  1578. // The faked COM server should not be removed if it is still in use
  1579. //
  1580. if (*pbUnRegCOMServer) {
  1581. nHandlerRef = 0;
  1582. for (pCurNode = m_pEventDestNodes;
  1583. pCurNode;
  1584. pCurNode = pCurNode->pNext) {
  1585. //
  1586. // Ignode the callback interface pointers
  1587. //
  1588. if (*pClsID == pCurNode->ClsID) {
  1589. nHandlerRef++;
  1590. }
  1591. }
  1592. if (nHandlerRef) {
  1593. *pbUnRegCOMServer = FALSE;
  1594. } else {
  1595. *pbUnRegCOMServer = TRUE;
  1596. }
  1597. }
  1598. //
  1599. // Indicate that the IWiaEventCallback is not found.
  1600. //
  1601. return (hr);
  1602. }
  1603. /**************************************************************************\
  1604. * CEventNotifier::FindEventCBNode
  1605. *
  1606. * Check whether the specified Event Callback is already registered
  1607. *
  1608. * Arguments:
  1609. *
  1610. *
  1611. *
  1612. * Return Value:
  1613. *
  1614. * Status
  1615. *
  1616. * History:
  1617. *
  1618. * 11/4/1998 Original Version
  1619. *
  1620. \**************************************************************************/
  1621. PEventDestNode
  1622. CEventNotifier::FindEventCBNode(
  1623. UINT uiFlags,
  1624. BSTR bstrDeviceID,
  1625. const GUID *pEventGUID,
  1626. IWiaEventCallback *pIWiaEventCallback)
  1627. {
  1628. DBG_FN(CEventNotifier::FindEventCBNode);
  1629. HRESULT hr;
  1630. EventDestNode *pCurNode;
  1631. IUnknown *pICurUnk, *pINewUnk;
  1632. //
  1633. // Retrieve the IUnknown of the new Event Callback
  1634. //
  1635. hr = pIWiaEventCallback->QueryInterface(IID_IUnknown, (void **)&pINewUnk);
  1636. if (FAILED(hr)) {
  1637. DBG_ERR(("CEventNotifier::IsDupEventCB, QI for IID_IUnknown failed"));
  1638. return (NULL);
  1639. }
  1640. for (pCurNode = m_pEventDestNodes; pCurNode; pCurNode = pCurNode->pNext) {
  1641. if (wcscmp(
  1642. pCurNode->bstrDeviceID,
  1643. bstrDeviceID ? bstrDeviceID : L"All") != 0) {
  1644. continue;
  1645. }
  1646. if (pCurNode->iidEventGUID != *pEventGUID) {
  1647. //
  1648. // If we are instructed to allow STI proxy event matches - check node GUID against STI event proxy GUID
  1649. // If exact match is required - continue without checking
  1650. //
  1651. if ( (uiFlags & FLAG_EN_FINDCB_EXACT_MATCH ) ||
  1652. (pCurNode->iidEventGUID != WIA_EVENT_STI_PROXY)) {
  1653. continue;
  1654. }
  1655. }
  1656. if (pCurNode->pIEventCB) {
  1657. hr = pCurNode->pIEventCB->QueryInterface(
  1658. IID_IUnknown, (void **)&pICurUnk);
  1659. if (FAILED(hr)) {
  1660. pINewUnk->Release();
  1661. return (NULL);
  1662. }
  1663. //
  1664. // COM can only guarantee that IUnknowns are the same
  1665. //
  1666. if (pICurUnk == pINewUnk) {
  1667. pICurUnk->Release();
  1668. pINewUnk->Release();
  1669. return (pCurNode);
  1670. } else {
  1671. pICurUnk->Release();
  1672. }
  1673. }
  1674. }
  1675. pINewUnk->Release();
  1676. return (NULL);
  1677. }
  1678. /**************************************************************************\
  1679. * CEventNotifier::FindEventCBNode
  1680. *
  1681. * Check whether the specified Event Callback is already registered
  1682. *
  1683. * Arguments:
  1684. *
  1685. *
  1686. *
  1687. * Return Value:
  1688. *
  1689. * Status
  1690. *
  1691. * History:
  1692. *
  1693. * 11/4/1998 Original Version
  1694. *
  1695. \**************************************************************************/
  1696. PEventDestNode
  1697. CEventNotifier::FindEventCBNode(
  1698. UINT uiFlags,
  1699. BSTR bstrDeviceID,
  1700. const GUID *pEventGUID,
  1701. const GUID *pClsID)
  1702. {
  1703. DBG_FN(CEventNotifier::FindEventCBNode);
  1704. PEventDestNode pCurNode;
  1705. for (pCurNode = m_pEventDestNodes; pCurNode; pCurNode = pCurNode->pNext) {
  1706. if (wcscmp(
  1707. pCurNode->bstrDeviceID,
  1708. bstrDeviceID ? bstrDeviceID : L"All") != 0) {
  1709. continue;
  1710. }
  1711. if (pCurNode->iidEventGUID != *pEventGUID) {
  1712. //
  1713. // If we are instructed to allow STI proxy event matches - check node GUID against STI event proxy GUID
  1714. // If exact match is required - continue without checking
  1715. //
  1716. if ( (uiFlags & FLAG_EN_FINDCB_EXACT_MATCH ) ||
  1717. (pCurNode->iidEventGUID != WIA_EVENT_STI_PROXY)) {
  1718. continue;
  1719. }
  1720. }
  1721. if ((! pCurNode->pIEventCB) && (pCurNode->ClsID == *pClsID)) {
  1722. return (pCurNode);
  1723. }
  1724. }
  1725. return (NULL);
  1726. }
  1727. /**************************************************************************\
  1728. * CEventNotifier::FindCLSIDForCommandline
  1729. *
  1730. * Find the CLSID for the specified commandline
  1731. *
  1732. * Arguments:
  1733. *
  1734. *
  1735. *
  1736. * Return Value:
  1737. *
  1738. * Status
  1739. *
  1740. * History:
  1741. *
  1742. * 11/4/1998 Original Version
  1743. *
  1744. \**************************************************************************/
  1745. HRESULT
  1746. CEventNotifier::FindCLSIDForCommandline(
  1747. LPCTSTR ptszCommandline,
  1748. CLSID *pClsID)
  1749. {
  1750. DBG_FN(CEventNotifier::FindCLSIDForCommandline);
  1751. PEventDestNode pCurNode;
  1752. for (pCurNode = m_pEventDestNodes; pCurNode; pCurNode = pCurNode->pNext) {
  1753. if ((pCurNode->tszCommandline[0] != '\0') &&
  1754. (_tcsicmp(pCurNode->tszCommandline, ptszCommandline) == 0)) {
  1755. *pClsID = pCurNode->ClsID;
  1756. return (S_OK);
  1757. }
  1758. }
  1759. return (E_FAIL);
  1760. }
  1761. /**************************************************************************\
  1762. * CEventNotifier::RestoreAllPersistentCBs
  1763. *
  1764. * Restore all the persistent Event Callbacks
  1765. *
  1766. * Arguments:
  1767. *
  1768. *
  1769. *
  1770. * Return Value:
  1771. *
  1772. * Status
  1773. *
  1774. * History:
  1775. *
  1776. * 12/1/1998 Original Version
  1777. *
  1778. \**************************************************************************/
  1779. HRESULT
  1780. CEventNotifier::RestoreAllPersistentCBs()
  1781. {
  1782. DBG_FN(CEventNotifier::RestoreAllPresistentCBs);
  1783. HKEY hStillImage = NULL;
  1784. HKEY hMSCDevList = NULL;
  1785. DWORD dwIndex;
  1786. HRESULT hr = S_OK;
  1787. DWORD dwError = 0;
  1788. //
  1789. // Restore device specific handlers
  1790. //
  1791. g_pDevMan->ForEachDeviceInList(DEV_MAN_OP_DEV_RESTORE_EVENT, 0);
  1792. CWiaCritSect CritSect(&g_semEventNode);
  1793. //
  1794. // Restore device events for MSC Cameras under Control\StillImage\MSCDevList
  1795. //
  1796. dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  1797. REGSTR_PATH_WIA_MSCDEVICES_W,
  1798. 0,
  1799. KEY_READ,
  1800. &hMSCDevList);
  1801. if (dwError == ERROR_SUCCESS) {
  1802. for (dwIndex = 0; ;dwIndex++) {
  1803. WCHAR wszDeviceName[STI_MAX_INTERNAL_NAME_LENGTH];
  1804. FILETIME fileTime;
  1805. HKEY hKeyDev = NULL;
  1806. DWORD dwSize = sizeof(wszDeviceName) / sizeof(wszDeviceName[0]);
  1807. dwError = RegEnumKeyExW(hMSCDevList,
  1808. dwIndex,
  1809. wszDeviceName,
  1810. &dwSize,
  1811. 0,
  1812. NULL,
  1813. 0,
  1814. &fileTime);
  1815. if (dwError != ERROR_SUCCESS) {
  1816. //
  1817. // No more keys to enumerate
  1818. //
  1819. break;
  1820. }
  1821. wszDeviceName[STI_MAX_INTERNAL_NAME_LENGTH - 1] = L'\0';
  1822. //
  1823. // Open the device key
  1824. //
  1825. dwError = RegOpenKeyExW(hMSCDevList,
  1826. wszDeviceName,
  1827. 0,
  1828. KEY_READ,
  1829. &hKeyDev);
  1830. if (dwError != ERROR_SUCCESS) {
  1831. //
  1832. // Skip this key
  1833. //
  1834. continue;
  1835. }
  1836. //
  1837. // Restore the event hanlders for this device
  1838. //
  1839. RestoreDevPersistentCBs(hKeyDev);
  1840. RegCloseKey(hKeyDev);
  1841. }
  1842. RegCloseKey(hMSCDevList);
  1843. hMSCDevList = NULL;
  1844. }
  1845. //
  1846. // Restore the global event callback under the Control\StillImage
  1847. //
  1848. dwError = RegOpenKeyEx(
  1849. HKEY_LOCAL_MACHINE,
  1850. REG_PATH_STILL_IMAGE_CONTROL,
  1851. 0,
  1852. KEY_READ,
  1853. &hStillImage);
  1854. if (dwError != ERROR_SUCCESS) {
  1855. //
  1856. // The registry entry for the STI is corrupted
  1857. //
  1858. DBG_ERR(("CEventNotifier::RestoreAllPersistentCBs : Can not open STI control key."));
  1859. hr = (HRESULT_FROM_WIN32(dwError));
  1860. } else {
  1861. RestoreDevPersistentCBs(hStillImage);
  1862. //
  1863. // Close the STI control key (Control\StillImage)
  1864. //
  1865. RegCloseKey(hStillImage);
  1866. }
  1867. return S_OK;
  1868. }
  1869. /**************************************************************************\
  1870. * CEventNotifier::RestoreAllPersistentCBs
  1871. *
  1872. * Restore specific devices' persistent Event Callbacks
  1873. *
  1874. * Arguments:
  1875. *
  1876. * hParentOfEventKey - This is either the device key or the still
  1877. * image key. Either way, the key must have a
  1878. * "Events" subkey.
  1879. *
  1880. * Return Value:
  1881. *
  1882. * Status
  1883. *
  1884. * History:
  1885. *
  1886. * 12/1/1998 Original Version
  1887. *
  1888. \**************************************************************************/
  1889. HRESULT
  1890. CEventNotifier::RestoreDevPersistentCBs(
  1891. HKEY hParentOfEventKey)
  1892. {
  1893. DBG_FN(CEventNotifier::RestoreDevPresistantCBs);
  1894. #ifdef UNICODE
  1895. WCHAR tszBuf[MAX_PATH];
  1896. #else
  1897. CHAR tszBuf[MAX_PATH];
  1898. #endif
  1899. LPTSTR ptszEvents = tszBuf;
  1900. LONG lRet;
  1901. HKEY hEvents;
  1902. DWORD dwIndex;
  1903. LPTSTR ptszEventName = tszBuf;
  1904. DWORD dwEventNameLen;
  1905. FILETIME fileTime;
  1906. HKEY hEvent;
  1907. HKEY hCBCLSID;
  1908. DWORD dwValueType;
  1909. LPTSTR ptszGUIDStr = tszBuf;
  1910. GUID eventGUID;
  1911. GUID guidDefaultDevHandler;
  1912. BOOL bIsDefault = FALSE;
  1913. DWORD dwCLSIDIndex;
  1914. DWORD dwGUIDStrLen;
  1915. LPTSTR ptszCBCLSIDStr = tszBuf;
  1916. CLSID callbackCLSID;
  1917. TCHAR tszDeviceID[STI_MAX_INTERNAL_NAME_LENGTH];
  1918. #ifdef UNICODE
  1919. LPWSTR pwszGUIDStr = tszBuf;
  1920. LPWSTR pwszCBCLSIDStr = tszBuf;
  1921. #else
  1922. WCHAR wszBuf[MAX_PATH];
  1923. LPWSTR pwszGUIDStr = wszBuf;
  1924. LPWSTR pwszCBCLSIDStr = wszBuf;
  1925. #endif
  1926. DWORD dwValueLen;
  1927. BSTR bstrName, bstrDescription;
  1928. SYSTEMTIME sysTime;
  1929. TCHAR tszCommandline[MAX_PATH];
  1930. DWORD dwType = REG_SZ;
  1931. DWORD dwSize = sizeof(tszDeviceID);
  1932. DWORD dwError = 0;
  1933. HRESULT hr = E_FAIL;
  1934. BSTR bstrDeviceID = NULL;
  1935. lstrcpy(ptszEvents, EVENTS);
  1936. //
  1937. // Attempt to read the DeviceID
  1938. //
  1939. dwError = RegQueryValueEx(hParentOfEventKey,
  1940. REGSTR_VAL_DEVICE_ID,
  1941. NULL,
  1942. &dwType,
  1943. (LPBYTE)tszDeviceID,
  1944. &dwSize);
  1945. if (dwError == ERROR_SUCCESS) {
  1946. bstrDeviceID = SysAllocString(T2W(tszDeviceID));
  1947. if (!bstrDeviceID) {
  1948. DBG_ERR(("CEventNotifier::RestoreDevPersistentCBs, Out of memory!"));
  1949. return E_OUTOFMEMORY;
  1950. }
  1951. } else {
  1952. bstrDeviceID = NULL;
  1953. }
  1954. //
  1955. // Open the Events subkey
  1956. //
  1957. lRet = RegOpenKeyEx(
  1958. hParentOfEventKey,
  1959. ptszEvents,
  1960. 0,
  1961. KEY_READ,
  1962. &hEvents);
  1963. if (lRet != ERROR_SUCCESS) {
  1964. return (HRESULT_FROM_WIN32(lRet)); // Events may not exist
  1965. }
  1966. //
  1967. // Enumerate all the events under the "Events" subkey
  1968. //
  1969. for (dwIndex = 0; ;dwIndex++) {
  1970. dwEventNameLen = sizeof(tszBuf)/sizeof(TCHAR);
  1971. lRet = RegEnumKeyEx(
  1972. hEvents,
  1973. dwIndex,
  1974. ptszEventName,
  1975. &dwEventNameLen,
  1976. NULL,
  1977. NULL,
  1978. NULL,
  1979. &fileTime);
  1980. if (lRet != ERROR_SUCCESS) {
  1981. break;
  1982. }
  1983. //
  1984. // Open the event subkey
  1985. //
  1986. lRet = RegOpenKeyEx(
  1987. hEvents,
  1988. ptszEventName,
  1989. 0,
  1990. KEY_READ,
  1991. &hEvent);
  1992. if (lRet != ERROR_SUCCESS) {
  1993. continue;
  1994. }
  1995. //
  1996. // Get GUID of the default handler (if present), and save it in
  1997. // guidDefaultDevHandler
  1998. //
  1999. dwValueLen = sizeof(tszBuf);
  2000. lRet = RegQueryValueEx(
  2001. hEvent,
  2002. DEFAULT_HANDLER_VAL,
  2003. NULL,
  2004. &dwValueType,
  2005. (LPBYTE)ptszGUIDStr,
  2006. &dwValueLen);
  2007. if ((lRet == ERROR_SUCCESS) && (dwValueType == REG_SZ)) {
  2008. WCHAR wszDefGUIDStr[MAX_PATH];
  2009. #ifndef UNICODE
  2010. MultiByteToWideChar(CP_ACP,
  2011. 0,
  2012. ptszGUIDStr,
  2013. -1,
  2014. wszDefGUIDStr,
  2015. sizeof(wszDefGUIDStr) / sizeof(WCHAR));
  2016. pwszGUIDStr[38] = 0;
  2017. #else
  2018. lstrcpyW(wszDefGUIDStr, ptszGUIDStr);
  2019. #endif
  2020. if (SUCCEEDED(CLSIDFromString(wszDefGUIDStr, &guidDefaultDevHandler))) {
  2021. DBG_TRC(("CEventNotifier::RestoreDevPersistentCBs, Default guid: %S",
  2022. ptszGUIDStr));
  2023. }
  2024. } else {
  2025. //
  2026. // We zero out guidDefaultDevHandler to make sure we don't accidentaly hit
  2027. // a match later...
  2028. //
  2029. ::ZeroMemory(&guidDefaultDevHandler,sizeof(guidDefaultDevHandler));
  2030. }
  2031. //
  2032. // Retrieve the GUID of the event
  2033. //
  2034. dwGUIDStrLen = 39*sizeof(TCHAR); // GUID string is 38 characters long
  2035. lRet = RegQueryValueEx(
  2036. hEvent,
  2037. TEXT("GUID"),
  2038. NULL,
  2039. &dwValueType,
  2040. (LPBYTE)ptszGUIDStr,
  2041. &dwGUIDStrLen);
  2042. if ((lRet != ERROR_SUCCESS) || (dwValueType != REG_SZ)) {
  2043. //
  2044. // Junk event found, skip to the next
  2045. //
  2046. DBG_TRC(("CEventNotifier::RestoreDevPersistentCBs, Junk event %S found", ptszEventName));
  2047. continue;
  2048. }
  2049. #ifndef UNICODE
  2050. mbstowcs(pwszGUIDStr, ptszGUIDStr, 38);
  2051. pwszGUIDStr[38] = 0;
  2052. #endif
  2053. if (FAILED(CLSIDFromString(pwszGUIDStr, &eventGUID))) {
  2054. //
  2055. // Invalid event GUID found, skip to the next
  2056. //
  2057. DBG_TRC(("CEventNotifier::RestoreDevPersistentCBs, invalid event GUID %S found", ptszGUIDStr));
  2058. continue;
  2059. }
  2060. //
  2061. // Enumerate all the event handler CLSIDs under this event
  2062. //
  2063. for (dwCLSIDIndex = 0; ;dwCLSIDIndex++) {
  2064. dwGUIDStrLen = 39; // CLSID string is 38 character long.
  2065. lRet = RegEnumKeyEx(
  2066. hEvent,
  2067. dwCLSIDIndex,
  2068. ptszCBCLSIDStr,
  2069. &dwGUIDStrLen,
  2070. NULL,
  2071. NULL, // All the other information is not interesting
  2072. NULL,
  2073. &fileTime);
  2074. if (lRet != ERROR_SUCCESS) {
  2075. break; // End enumeration
  2076. }
  2077. #ifndef UNICODE
  2078. mbstowcs(pwszCBCLSIDStr, ptszCBCLSIDStr, 38);
  2079. pwszCBCLSIDStr[38] = 0;
  2080. #endif
  2081. //
  2082. // Convert CLSID and register this callback
  2083. //
  2084. if (SUCCEEDED(CLSIDFromString(pwszCBCLSIDStr, &callbackCLSID))) {
  2085. hCBCLSID = NULL;
  2086. bstrName = NULL;
  2087. bstrDescription = NULL;
  2088. do {
  2089. //
  2090. // Open the event handler CLSID subkey
  2091. //
  2092. lRet = RegOpenKeyEx(
  2093. hEvent,
  2094. ptszCBCLSIDStr,
  2095. 0,
  2096. KEY_QUERY_VALUE,
  2097. &hCBCLSID);
  2098. if (lRet != ERROR_SUCCESS) {
  2099. DBG_ERR(("CEventNotifier::RestoreDevPersistentCBs, RegOpenKeyEx() for CLSID failed."));
  2100. break;
  2101. }
  2102. //
  2103. // Retrieve the name, description and icon
  2104. //
  2105. dwValueLen = sizeof(tszBuf);
  2106. lRet = RegQueryValueEx(
  2107. hCBCLSID,
  2108. NAME_VAL,
  2109. NULL,
  2110. &dwValueType,
  2111. (LPBYTE)tszBuf,
  2112. &dwValueLen);
  2113. if ((lRet != ERROR_SUCCESS) || (dwValueType != REG_SZ)) {
  2114. DBG_ERR(("CEventNotifier::RestoreDevPersistentCBs, RegQueryValueEx() for Name failed."));
  2115. break;
  2116. }
  2117. #ifndef UNICODE
  2118. MultiByteToWideChar(CP_ACP,
  2119. 0,
  2120. tszBuf,
  2121. -1,
  2122. wszBuf,
  2123. MAX_PATH);
  2124. bstrName = SysAllocString(wszBuf);
  2125. #else
  2126. bstrName = SysAllocString(tszBuf);
  2127. #endif
  2128. if (! bstrName) {
  2129. break;
  2130. }
  2131. dwValueLen = sizeof(tszBuf);
  2132. lRet = RegQueryValueEx(
  2133. hCBCLSID,
  2134. DESC_VAL,
  2135. NULL,
  2136. &dwValueType,
  2137. (LPBYTE)tszBuf,
  2138. &dwValueLen);
  2139. if ((lRet != ERROR_SUCCESS) || (dwValueType != REG_SZ)) {
  2140. DBG_ERR(("CEventNotifier::RestoreDevPersistentCBs, RegQueryValueEx() for Desc failed."));
  2141. break;
  2142. }
  2143. #ifndef UNICODE
  2144. MultiByteToWideChar(CP_ACP,
  2145. 0,
  2146. tszBuf,
  2147. -1,
  2148. wszBuf,
  2149. MAX_PATH);
  2150. bstrDescription = SysAllocString(wszBuf);
  2151. #else
  2152. bstrDescription = SysAllocString(tszBuf);
  2153. #endif
  2154. if (! bstrDescription) {
  2155. break;
  2156. }
  2157. dwValueLen = sizeof(tszBuf);
  2158. lRet = RegQueryValueEx(
  2159. hCBCLSID,
  2160. ICON_VAL,
  2161. NULL,
  2162. &dwValueType,
  2163. (LPBYTE)tszBuf,
  2164. &dwValueLen);
  2165. if ((lRet != ERROR_SUCCESS) || (dwValueType != REG_SZ)) {
  2166. DBG_ERR(("CEventNotifier::RestoreDevPersistentCBs, RegQueryValueEx() for Desc failed."));
  2167. break;
  2168. }
  2169. #ifndef UNICODE
  2170. MultiByteToWideChar(CP_ACP,
  2171. 0,
  2172. tszBuf,
  2173. -1,
  2174. wszBuf,
  2175. MAX_PATH);
  2176. #endif
  2177. //
  2178. // Retrieve the command line, it may not exist
  2179. //
  2180. dwValueLen = sizeof(tszCommandline);
  2181. lRet = RegQueryValueEx(
  2182. hCBCLSID,
  2183. CMDLINE_VAL,
  2184. NULL,
  2185. &dwValueType,
  2186. (LPBYTE)tszCommandline,
  2187. &dwValueLen);
  2188. if ((lRet != ERROR_SUCCESS) || (dwValueType != REG_SZ)) {
  2189. //
  2190. // Initialize the commandline to null
  2191. //
  2192. tszCommandline[0] = '\0';
  2193. }
  2194. #ifdef DEBUG
  2195. FileTimeToSystemTime(&fileTime, &sysTime);
  2196. #endif
  2197. //
  2198. // Register the callback without the persistent flag
  2199. //
  2200. //
  2201. // Check whether this is the default...
  2202. //
  2203. if (callbackCLSID == guidDefaultDevHandler) {
  2204. bIsDefault = TRUE;
  2205. } else {
  2206. bIsDefault = FALSE;
  2207. }
  2208. //DBG_WRN(("=> Restoring CBs for Device %S, Program named %S",
  2209. // bstrDeviceID ? bstrDeviceID : L"NULL",
  2210. // bstrName));
  2211. DBG_TRC(("CEventNotifier::RestoreDevPersistentCBs, Restoring CBs for Device %S, Program named %S",
  2212. bstrDeviceID ? bstrDeviceID : L"NULL",
  2213. bstrName));
  2214. #ifdef UNICODE
  2215. BSTR bstrIcon = SysAllocString(tszBuf);
  2216. if (FAILED(RegisterEventCB(
  2217. bstrDeviceID,
  2218. &eventGUID,
  2219. &callbackCLSID,
  2220. tszCommandline,
  2221. bstrName,
  2222. bstrDescription,
  2223. bstrIcon,
  2224. fileTime,
  2225. bIsDefault))) {
  2226. DBG_ERR(("CEventNotifier::RestoreDevPersistentCBs, RegisterEventCB() failed."));
  2227. }
  2228. SysFreeString(bstrIcon);
  2229. bstrIcon = NULL;
  2230. #else
  2231. if (FAILED(RegisterEventCB(
  2232. bstrDeviceID,
  2233. &eventGUID,
  2234. &callbackCLSID,
  2235. tszCommandline,
  2236. bstrName,
  2237. bstrDescription,
  2238. wszBuf,
  2239. fileTime,
  2240. bIsDefault))) {
  2241. DBG_ERR(("CEventNotifier::RestoreDevPersistentCBs, RegisterEventCB() failed."));
  2242. }
  2243. #endif
  2244. } while (FALSE);
  2245. //
  2246. // Close the subkey for the event handler CLSID
  2247. //
  2248. if (hCBCLSID) {
  2249. RegCloseKey(hCBCLSID);
  2250. }
  2251. if (bstrName) {
  2252. SysFreeString(bstrName);
  2253. }
  2254. if (bstrDescription) {
  2255. SysFreeString(bstrDescription);
  2256. }
  2257. }
  2258. }
  2259. //
  2260. // Close the key for the specific event
  2261. //
  2262. RegCloseKey(hEvent);
  2263. }
  2264. //
  2265. // Close the event subkey
  2266. //
  2267. RegCloseKey(hEvents);
  2268. //
  2269. // Free the deviceID, if one was allocated
  2270. //
  2271. if (bstrDeviceID) {
  2272. SysFreeString(bstrDeviceID);
  2273. bstrDeviceID = NULL;
  2274. }
  2275. return (S_OK);
  2276. }
  2277. /**************************************************************************\
  2278. * CEventNotifier::SavePersistentEventCB
  2279. *
  2280. * Save the persistent Event Callbacks CLSID for the Device ID / Event GUID
  2281. *
  2282. * Arguments:
  2283. *
  2284. *
  2285. *
  2286. * Return Value:
  2287. *
  2288. * Status
  2289. *
  2290. * History:
  2291. *
  2292. * 12/1/1998 Original Version
  2293. *
  2294. \**************************************************************************/
  2295. HRESULT
  2296. CEventNotifier::SavePersistentEventCB(
  2297. BSTR bstrDeviceID,
  2298. const GUID *pEventGUID,
  2299. const GUID *pClsid,
  2300. LPCTSTR ptszCommandline,
  2301. BSTR bstrName,
  2302. BSTR bstrDescription,
  2303. BSTR bstrIcon,
  2304. BOOL *pbCreatedKey,
  2305. ULONG *pulNumExistingHandlers,
  2306. BOOL bMakeDefault // = FALSE
  2307. )
  2308. {
  2309. DBG_FN(CEventNotifier::SavePresistentEventCB);
  2310. HRESULT hr;
  2311. HKEY hEvent, hCBCLSID;
  2312. LONG lRet;
  2313. DWORD dwDisposition;
  2314. WCHAR wszCBClsIDStr[40];
  2315. #ifndef UNICODE
  2316. CHAR szCBClsIDStr[40];
  2317. CHAR szString[MAX_PATH];
  2318. #endif
  2319. HKEY hClsid;
  2320. HKEY hCOMServerCLSID;
  2321. HKEY hLocalServer;
  2322. //
  2323. // Initialize the resources to NULL
  2324. //
  2325. hEvent = NULL;
  2326. hCBCLSID = NULL;
  2327. hClsid = NULL;
  2328. hCOMServerCLSID = NULL;
  2329. hLocalServer = NULL;
  2330. if (pbCreatedKey) {
  2331. *pbCreatedKey = FALSE;
  2332. }
  2333. do {
  2334. //
  2335. //
  2336. // Find the event subkey
  2337. //
  2338. hr = FindEventByGUID(bstrDeviceID, pEventGUID, &hEvent);
  2339. if (hr != S_OK) {
  2340. LPOLESTR wstrGuid = NULL;
  2341. HRESULT hres;
  2342. hres = StringFromCLSID(*pEventGUID,
  2343. &wstrGuid);
  2344. if (hres == S_OK) {
  2345. DBG_ERR(("CEventNotifier::SavePersistentEventCB() FindEventByGUID() failed, GUID=%S, hr=0x%08X", wstrGuid, hr));
  2346. CoTaskMemFree(wstrGuid);
  2347. } else {
  2348. DBG_ERR(("CEventNotifier::SavePersistentEventCB() FindEventByGUID() failed, hr=0x%08X", hr));
  2349. }
  2350. break;
  2351. }
  2352. //
  2353. // If asked, let's find out how many handlers already exist for this event
  2354. //
  2355. if (pulNumExistingHandlers) {
  2356. *pulNumExistingHandlers = 0;
  2357. lRet = RegQueryInfoKey(hEvent,
  2358. NULL,
  2359. NULL,
  2360. NULL,
  2361. pulNumExistingHandlers,
  2362. NULL,
  2363. NULL,
  2364. NULL,
  2365. NULL,
  2366. NULL,
  2367. NULL,
  2368. NULL);
  2369. }
  2370. //
  2371. // Convert the Event Callback CLSID as a string value
  2372. //
  2373. StringFromGUID2(*pClsid, wszCBClsIDStr, 40);
  2374. #ifndef UNICODE
  2375. //
  2376. // Convert the CLSID to ANSI string (including terminating NULL)
  2377. //
  2378. WideCharToMultiByte(CP_ACP,
  2379. 0,
  2380. wszCBClsIDStr,
  2381. -1,
  2382. szCBClsIDStr,
  2383. 40,
  2384. NULL,
  2385. NULL);
  2386. #endif
  2387. //
  2388. // Open / Create the Event Handler CLSID subkey
  2389. //
  2390. lRet = RegCreateKeyEx(
  2391. hEvent,
  2392. #ifdef UNICODE
  2393. wszCBClsIDStr,
  2394. #else
  2395. szCBClsIDStr,
  2396. #endif
  2397. 0,
  2398. NULL, // Mysterious class string
  2399. REG_OPTION_NON_VOLATILE,
  2400. KEY_SET_VALUE | KEY_READ | KEY_WRITE,
  2401. NULL, // Use default security descriptor
  2402. &hCBCLSID,
  2403. &dwDisposition);
  2404. if (lRet != ERROR_SUCCESS) {
  2405. DBG_ERR(("SavePersistentEventCB() RegCreateKeyEx() failed for CallbackCLSIDs subkey. lRet = %d", lRet));
  2406. hr = HRESULT_FROM_WIN32(lRet);
  2407. break;
  2408. }
  2409. if ((dwDisposition == REG_CREATED_NEW_KEY) && (pbCreatedKey)) {
  2410. *pbCreatedKey = TRUE;
  2411. }
  2412. //
  2413. // Set the event handler description value
  2414. //
  2415. #ifndef UNICODE
  2416. WideCharToMultiByte(CP_ACP,
  2417. 0,
  2418. bstrName,
  2419. -1,
  2420. szString,
  2421. MAX_PATH,
  2422. NULL,
  2423. NULL);
  2424. #endif
  2425. lRet = RegSetValueEx(
  2426. hCBCLSID,
  2427. NAME_VAL,
  2428. 0,
  2429. REG_SZ,
  2430. #ifdef UNICODE
  2431. (const PBYTE)bstrName,
  2432. (wcslen(bstrName) + 1) << 1);
  2433. #else
  2434. (const PBYTE)szString,
  2435. strlen(szString) + 1);
  2436. #endif
  2437. if (lRet != ERROR_SUCCESS) {
  2438. DBG_ERR(("SavePersistentEventCB() RegSetValueEx() failed for name"));
  2439. hr = HRESULT_FROM_WIN32(lRet);
  2440. break;
  2441. }
  2442. #ifndef UNICODE
  2443. WideCharToMultiByte(CP_ACP,
  2444. 0,
  2445. bstrDescription,
  2446. -1,
  2447. szString,
  2448. MAX_PATH,
  2449. NULL,
  2450. NULL);
  2451. #endif
  2452. lRet = RegSetValueEx(
  2453. hCBCLSID,
  2454. DESC_VAL,
  2455. 0,
  2456. REG_SZ,
  2457. #ifdef UNICODE
  2458. (const PBYTE)bstrDescription,
  2459. (wcslen(bstrDescription) + 1) << 1);
  2460. #else
  2461. (const PBYTE)szString,
  2462. strlen(szString) + 1);
  2463. #endif
  2464. if (lRet != ERROR_SUCCESS) {
  2465. DBG_ERR(("SavePersistentEventCB() RegSetValueEx() failed for description"));
  2466. hr = HRESULT_FROM_WIN32(lRet);
  2467. break;
  2468. }
  2469. //
  2470. // Set the event handler icon value
  2471. //
  2472. #ifndef UNICODE
  2473. WideCharToMultiByte(CP_ACP,
  2474. 0,
  2475. bstrIcon,
  2476. -1,
  2477. szString,
  2478. MAX_PATH,
  2479. NULL,
  2480. NULL);
  2481. #endif
  2482. lRet = RegSetValueEx(
  2483. hCBCLSID,
  2484. ICON_VAL,
  2485. 0,
  2486. REG_SZ,
  2487. #ifdef UNICODE
  2488. (const PBYTE)bstrIcon,
  2489. (wcslen(bstrIcon) + 1) << 1);
  2490. #else
  2491. (const PBYTE)szString,
  2492. strlen(szString) + 1);
  2493. #endif
  2494. if (lRet != ERROR_SUCCESS) {
  2495. DBG_ERR(("SavePersistentEventCB() RegSetValueEx() failed for icon"));
  2496. hr = HRESULT_FROM_WIN32(lRet);
  2497. break;
  2498. }
  2499. //
  2500. // Set the command line and fake the program as COM local server
  2501. //
  2502. if ((ptszCommandline) && (ptszCommandline[0])) {
  2503. lRet = RegSetValueEx(
  2504. hCBCLSID,
  2505. CMDLINE_VAL,
  2506. 0,
  2507. REG_SZ,
  2508. (PBYTE)ptszCommandline,
  2509. (_tcslen(ptszCommandline) + 1)*sizeof(TCHAR));
  2510. if (lRet != ERROR_SUCCESS) {
  2511. DBG_ERR(("SavePersistentEventCB() RegSetValueEx() failed for cmdline"));
  2512. hr = HRESULT_FROM_WIN32(lRet);
  2513. break;
  2514. }
  2515. /* //Why is this here?
  2516. lRet = RegCreateKeyEx(
  2517. HKEY_CLASSES_ROOT,
  2518. TEXT("CLSID"),
  2519. 0,
  2520. NULL, // Mysterious class string
  2521. REG_OPTION_NON_VOLATILE,
  2522. KEY_SET_VALUE | KEY_READ | KEY_WRITE,
  2523. NULL, // Use default security descriptor
  2524. &hClsid,
  2525. &dwDisposition);
  2526. if (lRet != ERROR_SUCCESS) {
  2527. //Remove:
  2528. Trace("SavePersistentEventCB(), could not open CLSID under HKEY_CLASSES_ROOT");
  2529. hr = HRESULT_FROM_WIN32(lRet);
  2530. break;
  2531. }
  2532. lRet = RegCreateKeyEx(
  2533. hClsid,
  2534. #ifdef UNICODE
  2535. wszCBClsIDStr,
  2536. #else
  2537. szCBClsIDStr,
  2538. #endif
  2539. 0,
  2540. NULL, // Mysterious class string
  2541. REG_OPTION_NON_VOLATILE,
  2542. KEY_SET_VALUE | KEY_READ | KEY_WRITE,
  2543. NULL, // Use default security descriptor
  2544. &hCOMServerCLSID,
  2545. &dwDisposition);
  2546. if (lRet != ERROR_SUCCESS) {
  2547. //Remove:
  2548. Trace("SavePersistentEventCB(), could not save persistent event data (%ws) for %ws", wszCBClsIDStr, bstrName);
  2549. hr = HRESULT_FROM_WIN32(lRet);
  2550. break;
  2551. }
  2552. lRet = RegCreateKeyEx(
  2553. hCOMServerCLSID,
  2554. TEXT("LocalServer32"),
  2555. 0,
  2556. NULL, // Mysterious class string
  2557. REG_OPTION_NON_VOLATILE,
  2558. KEY_SET_VALUE | KEY_READ | KEY_WRITE,
  2559. NULL, // Use default security descriptor
  2560. &hLocalServer,
  2561. &dwDisposition);
  2562. if (lRet != ERROR_SUCCESS) {
  2563. hr = HRESULT_FROM_WIN32(lRet);
  2564. //Remove:
  2565. Trace("SavePersistentEventCB(), could not save persistent event data (LocalServer) for %ws", bstrName);
  2566. break;
  2567. }
  2568. lRet = RegSetValueEx(
  2569. hLocalServer,
  2570. NULL,
  2571. 0,
  2572. REG_SZ,
  2573. (PBYTE)ptszCommandline,
  2574. (_tcslen(ptszCommandline) + 1)*sizeof(TCHAR));
  2575. hr = HRESULT_FROM_WIN32(lRet);
  2576. */
  2577. }
  2578. //
  2579. // If asked - set as default handler for current device/event pair
  2580. //
  2581. if ( bMakeDefault ) {
  2582. DBG_WRN(("CEventNotifier::SavePersistentEventCB, Writing DEFAULT_HANDLER_VAL"));
  2583. lRet = ::RegSetValueEx(
  2584. hEvent,
  2585. DEFAULT_HANDLER_VAL,
  2586. 0,
  2587. REG_SZ,
  2588. #ifdef UNICODE
  2589. (PBYTE)wszCBClsIDStr,
  2590. (lstrlen(wszCBClsIDStr) + 1)*sizeof(TCHAR));
  2591. #else
  2592. (PBYTE)szCBClsIDStr,
  2593. (lstrlen(szCBClsIDStr) + 1)*sizeof(TCHAR));
  2594. #endif
  2595. #ifdef UNICODE
  2596. DBG_TRC(("SavePersCB:: Setting default == %S lRet=%d",
  2597. wszCBClsIDStr, lRet));
  2598. #else
  2599. DBG_TRC(("SavePersCB:: Setting default == %s lRet=%d",
  2600. szCBClsIDStr, lRet));
  2601. #endif
  2602. } // endif bMakeDefault
  2603. } while (FALSE);
  2604. //
  2605. // Close the registry keys
  2606. //
  2607. if (hCBCLSID) {
  2608. RegCloseKey(hCBCLSID);
  2609. }
  2610. if (hCOMServerCLSID) {
  2611. RegCloseKey(hCOMServerCLSID);
  2612. }
  2613. if (hLocalServer) {
  2614. RegCloseKey(hLocalServer);
  2615. }
  2616. if (hEvent) {
  2617. if (FAILED(hr)) {
  2618. //
  2619. // Unwind the whole thing
  2620. //
  2621. #ifdef UNICODE
  2622. RegDeleteKey(hEvent, wszCBClsIDStr);
  2623. #else
  2624. RegDeleteKey(hEvent, szCBClsIDStr);
  2625. #endif
  2626. }
  2627. RegCloseKey(hEvent);
  2628. }
  2629. if (hClsid) {
  2630. if (FAILED(hr)) {
  2631. //
  2632. // Unwind the whole thing
  2633. //
  2634. #ifdef UNICODE
  2635. RegDeleteKey(hEvent, wszCBClsIDStr);
  2636. #else
  2637. RegDeleteKey(hEvent, szCBClsIDStr);
  2638. #endif
  2639. }
  2640. RegCloseKey(hClsid);
  2641. }
  2642. return (hr);
  2643. }
  2644. /**************************************************************************\
  2645. * CEventNotifier::DelPersistentEventCB(
  2646. *
  2647. * Delete the persistent Event Callback CLSID for the Device ID / Event GUID
  2648. *
  2649. * Arguments:
  2650. *
  2651. *
  2652. *
  2653. * Return Value:
  2654. *
  2655. * Status
  2656. *
  2657. * History:
  2658. *
  2659. * 12/1/1998 Original Version
  2660. *
  2661. \**************************************************************************/
  2662. HRESULT
  2663. CEventNotifier::DelPersistentEventCB(
  2664. BSTR bstrDeviceID,
  2665. const GUID *pEventGUID,
  2666. const GUID *pClsid,
  2667. BOOL bUnRegCOMServer)
  2668. {
  2669. DBG_FN(CEventNotifier::DelPersistentEventCB);
  2670. HRESULT hr;
  2671. HKEY hStillImage, hEvent;
  2672. TCHAR tcSubkeyName[8];
  2673. DWORD dwIndex, dwSubkeyNameLen;
  2674. LONG lRet;
  2675. WCHAR wszCBClsIDStr[40];
  2676. #ifndef UNICODE
  2677. CHAR szCBClsIDStr[40];
  2678. #endif
  2679. WCHAR wszDeviceID[50];
  2680. FILETIME fileTime;
  2681. HKEY hClsid;
  2682. //
  2683. // Find the event subkey
  2684. //
  2685. hr = FindEventByGUID(bstrDeviceID, pEventGUID, &hEvent);
  2686. if (hr != S_OK) {
  2687. DBG_ERR(("DelPersistentEventCB() FindEventByGUID() failed, hr=0x%08X", hr));
  2688. return (hr);
  2689. }
  2690. StringFromGUID2(*pClsid, wszCBClsIDStr, 40);
  2691. #ifndef UNICODE
  2692. //
  2693. // Convert the CLSID to ANSI string (including terminating NULL)
  2694. //
  2695. WideCharToMultiByte(CP_ACP,
  2696. 0,
  2697. wszCBClsIDStr,
  2698. -1,
  2699. szCBClsIDStr,
  2700. 40,
  2701. NULL,
  2702. NULL);
  2703. #endif
  2704. //
  2705. // Delete the corresponding event handler CLSID key
  2706. //
  2707. lRet = RegDeleteKey(
  2708. hEvent,
  2709. #ifdef UNICODE
  2710. wszCBClsIDStr);
  2711. #else
  2712. szCBClsIDStr);
  2713. #endif
  2714. if ((lRet != ERROR_SUCCESS) && (lRet != ERROR_FILE_NOT_FOUND)) {
  2715. DBG_ERR(("DelPersistentEventCB() RegDeleteValue() failed, lRet = 0x%08X", lRet));
  2716. }
  2717. //
  2718. // Close the registry keys
  2719. //
  2720. RegCloseKey(hEvent);
  2721. if (bstrDeviceID) {
  2722. return (HRESULT_FROM_WIN32(lRet));
  2723. }
  2724. //
  2725. // Delete the event handler clsid from under devices
  2726. //
  2727. lRet = RegOpenKeyEx(
  2728. HKEY_LOCAL_MACHINE,
  2729. REG_PATH_STILL_IMAGE_CLASS,
  2730. 0,
  2731. KEY_READ | KEY_WRITE,
  2732. &hStillImage);
  2733. if (lRet != ERROR_SUCCESS) {
  2734. DBG_ERR(("DelPersistentEventCBs : Can not open Image device class key."));
  2735. hr = (HRESULT_FROM_WIN32(lRet));
  2736. } else {
  2737. //
  2738. // Enumerate all the subkey
  2739. //
  2740. for (dwIndex = 0; ;dwIndex++) {
  2741. dwSubkeyNameLen = sizeof(tcSubkeyName)/sizeof(TCHAR);
  2742. lRet = RegEnumKeyEx(
  2743. hStillImage,
  2744. dwIndex,
  2745. tcSubkeyName,
  2746. &dwSubkeyNameLen,
  2747. NULL,
  2748. NULL,
  2749. NULL,
  2750. &fileTime);
  2751. if (lRet == ERROR_SUCCESS) {
  2752. //
  2753. // Make up the device ID
  2754. //
  2755. CSimpleStringWide cswDeviceID;
  2756. cswDeviceID = L"{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}\\";
  2757. cswDeviceID += tcSubkeyName;
  2758. //
  2759. // bstrDeviceID is NULL if we're here, so let's use it to hold our
  2760. // actual device id.
  2761. //
  2762. bstrDeviceID = SysAllocString(cswDeviceID.String());
  2763. if (bstrDeviceID)
  2764. {
  2765. hr = FindEventByGUID(bstrDeviceID, pEventGUID, &hEvent);
  2766. SysFreeString(bstrDeviceID);
  2767. bstrDeviceID = NULL;
  2768. }
  2769. else
  2770. {
  2771. hr = E_OUTOFMEMORY;
  2772. }
  2773. //
  2774. // This event key may not exist under specific device
  2775. //
  2776. if (hr != S_OK) {
  2777. continue;
  2778. }
  2779. //
  2780. // Delete the corresponding event handler CLSID key
  2781. //
  2782. lRet = RegDeleteKey(
  2783. hEvent,
  2784. #ifdef UNICODE
  2785. wszCBClsIDStr);
  2786. #else
  2787. szCBClsIDStr);
  2788. #endif
  2789. if ((lRet != ERROR_SUCCESS) && (lRet != ERROR_FILE_NOT_FOUND)) {
  2790. DBG_ERR(("DelPersistentEventCB() RegDeleteValue() failed, lRet = 0x%08X", lRet));
  2791. }
  2792. //
  2793. // Close event key and device key
  2794. //
  2795. RegCloseKey(hEvent);
  2796. } else {
  2797. break;
  2798. }
  2799. }
  2800. }
  2801. //
  2802. // Close the image class key
  2803. //
  2804. RegCloseKey(hStillImage);
  2805. //
  2806. // If the fake COM server should be unregistered
  2807. //
  2808. if (bUnRegCOMServer) {
  2809. lRet = RegOpenKeyEx(
  2810. HKEY_CLASSES_ROOT,
  2811. TEXT("CLSID"),
  2812. 0,
  2813. KEY_WRITE,
  2814. &hClsid);
  2815. if (lRet != ERROR_SUCCESS) {
  2816. //
  2817. // Unable to recover data anyway
  2818. //
  2819. return (S_OK);
  2820. }
  2821. #ifndef UNICODE
  2822. lRet = RegDeleteKey(
  2823. hClsid,
  2824. szCBClsIDStr);
  2825. #else
  2826. lRet = SHDeleteKey(
  2827. hClsid,
  2828. wszCBClsIDStr);
  2829. #endif
  2830. }
  2831. return (S_OK);
  2832. }
  2833. /**************************************************************************\
  2834. * CEventNotifier::FindEventByGUID(
  2835. *
  2836. * Find the registry key for DeviceID / Event GUID pair
  2837. *
  2838. * Arguments:
  2839. *
  2840. *
  2841. *
  2842. * Return Value:
  2843. *
  2844. * Status
  2845. *
  2846. * History:
  2847. *
  2848. * 12/1/1998 Original Version
  2849. *
  2850. \**************************************************************************/
  2851. HRESULT
  2852. CEventNotifier::FindEventByGUID(
  2853. BSTR bstrDeviceID,
  2854. const GUID *pEventGUID,
  2855. HKEY *phEventKey)
  2856. {
  2857. DBG_FN(CEventNotifier::FindEventByGUID);
  2858. TCHAR tszBuf[96];
  2859. LPTSTR ptszEventName = tszBuf;
  2860. LONG lRet;
  2861. HKEY hEvents, hEvent;
  2862. DWORD dwSubKeyIndex, dwEventNameLen;
  2863. DWORD dwGUIDStrLen, dwValueType, dwDisp;
  2864. FILETIME fileTime;
  2865. GUID eventGUID;
  2866. #ifdef UNICODE
  2867. LPWSTR pwszGUIDStr = tszBuf;
  2868. #else
  2869. WCHAR wszGUIDStr[39]; // {CLSID} + NULL
  2870. LPWSTR pwszGUIDStr = wszGUIDStr;
  2871. #endif
  2872. HRESULT hr = E_FAIL;
  2873. //
  2874. //
  2875. //
  2876. if (!pEventGUID) {
  2877. DBG_WRN(("CEventNotifier::FindEventByGUID, Event pointer is NULL"));
  2878. return E_INVALIDARG;
  2879. }
  2880. //
  2881. // Initialize the return value
  2882. //
  2883. *phEventKey = NULL;
  2884. //
  2885. // Prepare the event path
  2886. //
  2887. if (bstrDeviceID) {
  2888. //
  2889. // Open the device's event sub-key
  2890. //
  2891. hEvents = g_pDevMan->GetDeviceHKey(bstrDeviceID,
  2892. EVENTS);
  2893. if (!IsValidHANDLE(hEvents)) {
  2894. DBG_TRC(("CEventNotifier::FindEventByGUID() Couldn't open Events subkey, on device %S", bstrDeviceID));
  2895. return hr;
  2896. } else {
  2897. DBG_TRC(("CEventNotifier::FindEventByGUID() Found Events key on device %S", bstrDeviceID));
  2898. hr = S_OK;
  2899. }
  2900. } else {
  2901. //
  2902. // If there's no Device ID, look under StillImage
  2903. //
  2904. _tcscpy(tszBuf, REG_PATH_STILL_IMAGE_CONTROL);
  2905. _tcscat(tszBuf, TEXT("\\Events"));
  2906. //
  2907. // Open the device specific or the global Events subkey
  2908. //
  2909. lRet = RegCreateKeyEx(
  2910. HKEY_LOCAL_MACHINE,
  2911. tszBuf,
  2912. 0,
  2913. NULL,
  2914. REG_OPTION_NON_VOLATILE,
  2915. KEY_READ | KEY_WRITE,
  2916. NULL,
  2917. &hEvents,
  2918. &dwDisp);
  2919. if (lRet != ERROR_SUCCESS) {
  2920. #ifdef UNICODE
  2921. DBG_WRN(("CEventNotifier::FindEventByGUID() Couldn't find Events subkey, named %S", tszBuf));
  2922. #else
  2923. DBG_WRN(("CEventNotifier::FindEventByGUID() Couldn't find Events subkey, named %s", tszBuf));
  2924. #endif
  2925. return (HRESULT_FROM_WIN32(lRet));
  2926. }
  2927. }
  2928. //
  2929. // Enumerate all the events under Events subkey
  2930. //
  2931. for (dwSubKeyIndex = 0; ;dwSubKeyIndex++) {
  2932. dwEventNameLen = sizeof(tszBuf)/sizeof(TCHAR) - 1;
  2933. lRet = RegEnumKeyEx(
  2934. hEvents,
  2935. dwSubKeyIndex,
  2936. ptszEventName,
  2937. &dwEventNameLen,
  2938. NULL,
  2939. NULL,
  2940. NULL,
  2941. &fileTime);
  2942. if (lRet != ERROR_SUCCESS) {
  2943. break;
  2944. }
  2945. //
  2946. // Open the event subkey
  2947. //
  2948. dwEventNameLen = sizeof(tszBuf);
  2949. lRet = RegOpenKeyEx(
  2950. hEvents,
  2951. ptszEventName,
  2952. 0,
  2953. KEY_READ | KEY_WRITE,
  2954. &hEvent);
  2955. if (lRet != ERROR_SUCCESS) {
  2956. continue;
  2957. }
  2958. //
  2959. // Query the GUID value
  2960. //
  2961. dwGUIDStrLen = sizeof(tszBuf);
  2962. lRet = RegQueryValueEx(
  2963. hEvent,
  2964. TEXT("GUID"),
  2965. NULL,
  2966. &dwValueType,
  2967. (LPBYTE)tszBuf,
  2968. &dwGUIDStrLen);
  2969. if ((lRet != ERROR_SUCCESS) || (dwValueType != REG_SZ)) {
  2970. if (hEvent) {
  2971. RegCloseKey(hEvent);
  2972. hEvent = NULL;
  2973. }
  2974. //
  2975. // Junk event found, skip to the next
  2976. //
  2977. #ifdef UNICODE
  2978. DBG_WRN(("CEventNotifier::FindEventByGUID() Junk event %S found", ptszEventName));
  2979. #else
  2980. DBG_WRN("CEventNotifier::FindEventByGUID() Junk event %s found", ptszEventName));
  2981. #endif
  2982. continue;
  2983. }
  2984. #ifndef UNICODE
  2985. //
  2986. // Convert the CLSID into UNICODE including the terminating NULL
  2987. //
  2988. mbstowcs(wszGUIDStr, tszBuf, 39);
  2989. #endif
  2990. if (SUCCEEDED(CLSIDFromString(pwszGUIDStr, &eventGUID))) {
  2991. if (eventGUID == *pEventGUID) {
  2992. RegCloseKey(hEvents);
  2993. *phEventKey = hEvent;
  2994. return (S_OK);
  2995. }
  2996. }
  2997. if (hEvent) {
  2998. RegCloseKey(hEvent);
  2999. hEvent = NULL;
  3000. }
  3001. } // End of for (...)
  3002. DBG_WRN(("CEventNotifier::FindEventByGUID() Event GUID not found in reg key enumeration, creating one..."));
  3003. if (ActionGuidExists(bstrDeviceID, pEventGUID)) {
  3004. //
  3005. // Someone forgot to add the EVENT entry to their INF, so create a
  3006. // sub-key with the event GUID as a value
  3007. //
  3008. #define DEFAULT_EVENT_STR TEXT("Event")
  3009. #define GUID_STR TEXT("GUID")
  3010. TCHAR Name[MAX_PATH];
  3011. HKEY hEventName = NULL;
  3012. WCHAR *wsGUID = NULL;
  3013. USES_CONVERSION;
  3014. #ifdef UNICODE
  3015. wsprintf(Name, L"%ws%d", DEFAULT_EVENT_STR, dwSubKeyIndex);
  3016. #else
  3017. sprintf(Name, "%s%d", DEFAULT_EVENT_STR, dwSubKeyIndex);
  3018. #endif
  3019. lRet = RegCreateKeyEx(
  3020. hEvents,
  3021. Name,
  3022. 0,
  3023. NULL,
  3024. REG_OPTION_NON_VOLATILE,
  3025. KEY_READ | KEY_WRITE,
  3026. NULL,
  3027. &hEvent,
  3028. &dwDisp);
  3029. if (lRet == ERROR_SUCCESS) {
  3030. hr = StringFromCLSID(*pEventGUID, &wsGUID);
  3031. if (hr == S_OK) {
  3032. lRet = RegSetValueEx(
  3033. hEvent,
  3034. GUID_STR,
  3035. 0,
  3036. REG_SZ,
  3037. (BYTE*) W2T(wsGUID),
  3038. (lstrlen(W2T(wsGUID)) * sizeof(TCHAR)) + sizeof(TEXT('\0')));
  3039. if (lRet == ERROR_SUCCESS) {
  3040. *phEventKey = hEvent;
  3041. hr = S_OK;
  3042. } else {
  3043. hr = E_FAIL;
  3044. }
  3045. CoTaskMemFree(wsGUID);
  3046. wsGUID = NULL;
  3047. }
  3048. }
  3049. }
  3050. //
  3051. // Close Events key
  3052. //
  3053. RegCloseKey(hEvents);
  3054. if (FAILED(hr)) {
  3055. if (hEvent) {
  3056. RegCloseKey(hEvent);
  3057. }
  3058. }
  3059. return hr;
  3060. }
  3061. /**************************************************************************\
  3062. * CEventNotifier::CreateEnumEventInfo
  3063. *
  3064. * Build enumerator for specific device's persistent handlers
  3065. *
  3066. * Arguments:
  3067. *
  3068. *
  3069. *
  3070. * Return Value:
  3071. *
  3072. * Status
  3073. *
  3074. * History:
  3075. *
  3076. * 8/8/1999 Original Version
  3077. *
  3078. \**************************************************************************/
  3079. HRESULT
  3080. CEventNotifier::CreateEnumEventInfo(
  3081. BSTR bstrDeviceID,
  3082. const GUID *pEventGUID,
  3083. IEnumWIA_DEV_CAPS **ppIEnumDevCap)
  3084. {
  3085. DBG_FN(CEventNotifier::CreateEnumEventInfo);
  3086. HRESULT hr;
  3087. EventDestNode *pCurNode;
  3088. EventDestNode *pDefDevHandlerNode;
  3089. ULONG numHandlers, i;
  3090. WIA_EVENT_HANDLER *pEventHandlers, *pHandler;
  3091. CEnumDC *pEnumDC;
  3092. TCHAR tszCommandline[MAX_PATH];
  3093. #ifndef UNICODE
  3094. WCHAR wszBuf[MAX_PATH];
  3095. #endif
  3096. CWiaCritSect CritSect(&g_semEventNode);
  3097. ASSERT(bstrDeviceID);
  3098. //
  3099. // Clear the returned value
  3100. //
  3101. *ppIEnumDevCap = NULL;
  3102. //
  3103. // Find the number of handlers
  3104. //
  3105. GetNumPersistentHandlerAndDefault(
  3106. bstrDeviceID, pEventGUID, &numHandlers, &pDefDevHandlerNode);
  3107. //
  3108. // Build the enumerator
  3109. //
  3110. pEnumDC = new CEnumDC;
  3111. if (! pEnumDC) {
  3112. return (E_OUTOFMEMORY);
  3113. }
  3114. //
  3115. // If there is no handler registered for this event
  3116. //
  3117. if (! numHandlers) {
  3118. DBG_TRC(("CreateEnumEventInfo() : No handler registered for this event"));
  3119. //
  3120. // Trivial case
  3121. //
  3122. pEnumDC->Initialize(0, (WIA_EVENT_HANDLER*)NULL);
  3123. return (pEnumDC->QueryInterface(
  3124. IID_IEnumWIA_DEV_CAPS, (void **)ppIEnumDevCap));
  3125. }
  3126. //
  3127. // Prepare the Event Handler information
  3128. //
  3129. pEventHandlers =
  3130. (WIA_EVENT_HANDLER *)LocalAlloc(
  3131. LPTR, sizeof(WIA_EVENT_HANDLER)*numHandlers);
  3132. if (! pEventHandlers) {
  3133. delete pEnumDC;
  3134. return (E_OUTOFMEMORY);
  3135. }
  3136. memset(pEventHandlers, 0, sizeof(WIA_EVENT_HANDLER) * numHandlers);
  3137. pHandler = pEventHandlers;
  3138. hr = S_OK;
  3139. for (pCurNode = m_pEventDestNodes, i = 0;
  3140. pCurNode && (i <numHandlers);
  3141. pCurNode = pCurNode->pNext) {
  3142. //
  3143. // If this handler is a callback interface ponter
  3144. //
  3145. if (pCurNode->pIEventCB) {
  3146. continue;
  3147. }
  3148. //
  3149. // If this handler can not handle this event
  3150. //
  3151. if (( pCurNode->iidEventGUID != *pEventGUID) &&
  3152. (pCurNode->iidEventGUID != WIA_EVENT_STI_PROXY) ) {
  3153. continue;
  3154. }
  3155. //
  3156. // If this is generic fallback handler
  3157. //
  3158. if (wcscmp(pCurNode->bstrDeviceID, L"All") != 0) {
  3159. //
  3160. // If this handler is not for this device
  3161. //
  3162. if (wcscmp(pCurNode->bstrDeviceID, bstrDeviceID) != 0) {
  3163. continue;
  3164. }
  3165. } else {
  3166. //
  3167. // If this handler was registered for this device as default
  3168. //
  3169. if (FindEventCBNode(0,bstrDeviceID, pEventGUID, &pCurNode->ClsID)) {
  3170. continue;
  3171. }
  3172. }
  3173. //
  3174. // Copy the information from the current node
  3175. //
  3176. pHandler->guid = pCurNode->ClsID;
  3177. pHandler->bstrName = SysAllocString(pCurNode->bstrName);
  3178. pHandler->bstrDescription = SysAllocString(pCurNode->bstrDescription);
  3179. pHandler->bstrIcon = SysAllocString(pCurNode->bstrIcon);
  3180. if (pCurNode->tszCommandline[0] != '\0') {
  3181. #ifdef UNICODE
  3182. PrepareCommandline(
  3183. bstrDeviceID,
  3184. *pEventGUID,
  3185. pCurNode->tszCommandline,
  3186. tszCommandline);
  3187. pHandler->bstrCommandline =
  3188. SysAllocString(tszCommandline);
  3189. #else
  3190. PrepareCommandline(
  3191. bstrDeviceID,
  3192. *pEventGUID,
  3193. pCurNode->tszCommandline,
  3194. tszCommandline);
  3195. MultiByteToWideChar(CP_ACP,
  3196. 0,
  3197. tszCommandline,
  3198. -1,
  3199. wszBuf,
  3200. MAX_PATH);
  3201. pHandler->bstrCommandline = SysAllocString(wszBuf);
  3202. #endif
  3203. }
  3204. //
  3205. // Check whether the copy is successful
  3206. //
  3207. if ((! pHandler->bstrName) ||
  3208. (! pHandler->bstrDescription) ||
  3209. (! pHandler->bstrIcon) ||
  3210. ((pCurNode->tszCommandline[0] != '\0') && (! pHandler->bstrCommandline))) {
  3211. hr = E_OUTOFMEMORY;
  3212. break;
  3213. }
  3214. //
  3215. // Set the flag if this handler is the default one
  3216. //
  3217. if (pCurNode == pDefDevHandlerNode) {
  3218. pHandler->ulFlags = WIA_IS_DEFAULT_HANDLER;
  3219. }
  3220. pHandler++;
  3221. i++;
  3222. }
  3223. //
  3224. // Unwind the partial result if error occured
  3225. //
  3226. if (FAILED(hr)) {
  3227. for (i = 0, pHandler = pEventHandlers;
  3228. i < numHandlers; i++, pHandler++) {
  3229. if (pHandler->bstrName) {
  3230. SysFreeString(pHandler->bstrName);
  3231. }
  3232. if (pHandler->bstrDescription) {
  3233. SysFreeString(pHandler->bstrDescription);
  3234. }
  3235. if (pHandler->bstrIcon) {
  3236. SysFreeString(pHandler->bstrIcon);
  3237. }
  3238. }
  3239. LocalFree(pEventHandlers);
  3240. delete pEnumDC;
  3241. return (hr);
  3242. }
  3243. //
  3244. // Initilization will never fail
  3245. //
  3246. pEnumDC->Initialize(numHandlers, pEventHandlers);
  3247. return (pEnumDC->QueryInterface(
  3248. IID_IEnumWIA_DEV_CAPS, (void **)ppIEnumDevCap));
  3249. }
  3250. /**************************************************************************\
  3251. * CEventNotifier::GetNumPersistentHandlerAndDefault
  3252. *
  3253. * Find the total number of persistent handlers and the default
  3254. *
  3255. * Arguments:
  3256. *
  3257. *
  3258. *
  3259. * Return Value:
  3260. *
  3261. * Status
  3262. *
  3263. * History:
  3264. *
  3265. * 8/8/1999 Original Version
  3266. *
  3267. \**************************************************************************/
  3268. HRESULT
  3269. CEventNotifier::GetNumPersistentHandlerAndDefault(
  3270. BSTR bstrDeviceID,
  3271. const GUID *pEventGUID,
  3272. ULONG *pulNumHandlers,
  3273. EventDestNode **ppDefaultNode)
  3274. {
  3275. DBG_FN(CEventNotifier::GetNumPersistentHandlerAndDefault);
  3276. EventDestNode *pCurNode;
  3277. EventDestNode *pDefDevHandlerNode, *pDefGenHandlerNode, *pTempNode;
  3278. *pulNumHandlers = 0;
  3279. pDefDevHandlerNode = NULL;
  3280. pDefGenHandlerNode = NULL;
  3281. for (pCurNode = m_pEventDestNodes; pCurNode; pCurNode = pCurNode->pNext) {
  3282. //
  3283. // If this handler is a callback interface ponter
  3284. //
  3285. if (pCurNode->pIEventCB) {
  3286. continue;
  3287. }
  3288. //
  3289. // If this handler can not handle this event and this handler is not proxy for STI handlers
  3290. //
  3291. if ( (pCurNode->iidEventGUID != *pEventGUID) &&
  3292. (pCurNode->iidEventGUID != WIA_EVENT_STI_PROXY) ) {
  3293. //
  3294. // If the pEventGUID is the STI Proxy GUID, then we need to
  3295. // include WIA Global event handlers i.e. those with
  3296. // DeviceIDs of "ALL".
  3297. // Otherwise, just skip it.
  3298. //
  3299. if ((*pEventGUID == WIA_EVENT_STI_PROXY) && (lstrcmpW(bstrDeviceID, L"All") == 0)) {
  3300. (*pulNumHandlers)++;
  3301. }
  3302. continue;
  3303. }
  3304. if (wcscmp(pCurNode->bstrDeviceID, L"All") != 0) {
  3305. //
  3306. // If this handler is not for this device
  3307. //
  3308. if (wcscmp(pCurNode->bstrDeviceID, bstrDeviceID) != 0) {
  3309. continue;
  3310. }
  3311. //
  3312. // Remember the default handler's node
  3313. //
  3314. if (! pDefDevHandlerNode) {
  3315. pDefDevHandlerNode = pCurNode;
  3316. } else {
  3317. /* Original code
  3318. if (CompareFileTime(
  3319. &pCurNode->timeStamp,
  3320. &pDefDevHandlerNode->timeStamp) > 0) {
  3321. pDefDevHandlerNode = pCurNode;
  3322. }
  3323. */
  3324. //
  3325. // Timestamps are not valid on Win9x, so use the flag which indicates
  3326. // whether this is the default handler for this device.
  3327. //
  3328. if (pCurNode->bDeviceDefault) {
  3329. pDefDevHandlerNode = pCurNode;
  3330. }
  3331. }
  3332. } else {
  3333. //
  3334. // If this handler was registered for this device as default, then skip it
  3335. // since we'll hit the device specific registration on our pass anyway.
  3336. //
  3337. if (FindEventCBNode(0,bstrDeviceID, pEventGUID, &pCurNode->ClsID)) {
  3338. if (lstrcmpW(bstrDeviceID, L"All") == 0) {
  3339. //
  3340. // If the request is for ALL devices, then we're simply being asked to count the number
  3341. // of global handlers.
  3342. //
  3343. (*pulNumHandlers)++;
  3344. }
  3345. continue;
  3346. }
  3347. //
  3348. // If no device specific handler is found, then we want to go with a global one.
  3349. //
  3350. if (! pDefDevHandlerNode) {
  3351. if (! pDefGenHandlerNode) {
  3352. //
  3353. // We found our first global Handler
  3354. //
  3355. pDefGenHandlerNode = pCurNode;
  3356. } else {
  3357. //
  3358. // Since there is more than one global handler, let's use the "Prompt", if we can find it.
  3359. // NOTE: We assume that on registration of more than one global handler, the "Prompt" handler
  3360. // will be registered; so if we don't find it, this would generally indicate a problem during
  3361. // registration. However, in cases of upgrade, this is possible, and entirely normal, so we
  3362. // don't flag it as an error here, since it's not fatal anyway.
  3363. //
  3364. pTempNode = FindEventCBNode(0, NULL, pEventGUID, &WIA_EVENT_HANDLER_PROMPT);
  3365. if (pTempNode) {
  3366. pDefGenHandlerNode = pTempNode;
  3367. }
  3368. }
  3369. }
  3370. }
  3371. (*pulNumHandlers)++;
  3372. }
  3373. //
  3374. // If there is no device specific default handler, fall back
  3375. //
  3376. if (! pDefDevHandlerNode) {
  3377. *ppDefaultNode = pDefGenHandlerNode;
  3378. } else {
  3379. *ppDefaultNode = pDefDevHandlerNode;
  3380. }
  3381. return (S_OK);
  3382. }
  3383. /**************************************************************************\
  3384. * CEventNotifier::StartCallbackProgram
  3385. *
  3386. * Start the callback program in security context of the user who logged on
  3387. *
  3388. * Arguments:
  3389. *
  3390. *
  3391. *
  3392. * Return Value:
  3393. *
  3394. * Status
  3395. *
  3396. * History:
  3397. *
  3398. * 8/8/1999 Original Version
  3399. *
  3400. \**************************************************************************/
  3401. HRESULT
  3402. CEventNotifier::StartCallbackProgram(
  3403. EventDestNode *pCBNode,
  3404. PWIAEventThreadInfo pMasterInfo)
  3405. #ifndef UNICODE
  3406. {
  3407. STARTUPINFO startupInfo;
  3408. PROCESS_INFORMATION processInfo;
  3409. int nCmdLineLen;
  3410. BOOL bRet;
  3411. CHAR szCommandline[MAX_PATH];
  3412. do {
  3413. //
  3414. // Set up start up info
  3415. //
  3416. ZeroMemory(&startupInfo, sizeof(startupInfo));
  3417. startupInfo.cb = sizeof(startupInfo);
  3418. startupInfo.wShowWindow = SW_SHOWNORMAL;
  3419. //
  3420. // Set up the command line
  3421. // program /StiDevice Image\NNNN /StiEvent {GUID}
  3422. //
  3423. ZeroMemory(szCommandline, sizeof(szCommandline));
  3424. nCmdLineLen = strlen(pCBNode->tszCommandline);
  3425. if ((MAX_PATH - nCmdLineLen) < (1 + 11 + 10 + 1 + 10 + 38 + 1)) {
  3426. break;
  3427. }
  3428. //
  3429. // Prepare the command line
  3430. // Nb: It may be important to pick up event GUID from master info block, not from event callback node, because
  3431. // GUID match could've been found against STI proxy event GUID, in which case callback node would contain
  3432. // STI proxy event GUID, not the hardware event GUID, which we need
  3433. //
  3434. PrepareCommandline(
  3435. pMasterInfo->bstrDeviceID,
  3436. pMasterInfo->eventGUID,
  3437. //pCBNode->iidEventGUID,
  3438. pCBNode->tszCommandline,
  3439. szCommandline);
  3440. //
  3441. // Create the process in user's context
  3442. //
  3443. bRet = CreateProcess(
  3444. NULL, // Application name
  3445. szCommandline,
  3446. NULL, // Process attributes
  3447. NULL, // Thread attributes
  3448. FALSE, // Handle inheritance
  3449. 0, // Creation flag
  3450. NULL, // Environment
  3451. NULL, // Current directory
  3452. &startupInfo,
  3453. &processInfo);
  3454. if (! bRet) {
  3455. break;
  3456. }
  3457. //
  3458. // Close the handle passed back
  3459. //
  3460. CloseHandle(processInfo.hProcess);
  3461. CloseHandle(processInfo.hThread);
  3462. } while (FALSE);
  3463. return (HRESULT_FROM_WIN32(::GetLastError()));
  3464. }
  3465. #else
  3466. {
  3467. HANDLE hTokenUser;
  3468. STARTUPINFO startupInfo;
  3469. PROCESS_INFORMATION processInfo;
  3470. LPVOID pEnvBlock;
  3471. int nCmdLineLen;
  3472. BOOL bRet;
  3473. WCHAR wszCommandline[MAX_PATH];
  3474. hTokenUser = NULL;
  3475. pEnvBlock = NULL;
  3476. do {
  3477. nCmdLineLen = wcslen(pCBNode->tszCommandline);
  3478. if ((MAX_PATH - nCmdLineLen) < (1 + 11 + 43 + 1 + 10 + 38 + 1)) {
  3479. break;
  3480. }
  3481. //
  3482. // Get interactive user's token
  3483. //
  3484. hTokenUser = GetUserTokenForConsoleSession();
  3485. //
  3486. // Maybe nobody is loggon in
  3487. //
  3488. if (! hTokenUser) {
  3489. break;
  3490. }
  3491. //
  3492. // Set up start up info
  3493. //
  3494. ZeroMemory(&startupInfo, sizeof(startupInfo));
  3495. startupInfo.lpDesktop = L"WinSta0\\Default";
  3496. startupInfo.cb = sizeof(startupInfo);
  3497. startupInfo.wShowWindow = SW_SHOWNORMAL;
  3498. //
  3499. // Create the user's environment block
  3500. //
  3501. bRet = CreateEnvironmentBlock(
  3502. &pEnvBlock,
  3503. hTokenUser,
  3504. FALSE);
  3505. if (! bRet) {
  3506. DBG_WRN(("CEventNotifier::StartCallbackProgram, CreateEnvironmentBlock failed! GetLastError() = 0x%08X", GetLastError()));
  3507. break;
  3508. }
  3509. //
  3510. // Prepare the command line. Make sure we pass in the EVENT guid, not the STI proxy guid.
  3511. //
  3512. PrepareCommandline(
  3513. pMasterInfo->bstrDeviceID,
  3514. pMasterInfo->eventGUID,
  3515. pCBNode->tszCommandline,
  3516. wszCommandline);
  3517. //
  3518. // Create the process in user's context
  3519. //
  3520. bRet = CreateProcessAsUser(
  3521. hTokenUser,
  3522. NULL, // Application name
  3523. wszCommandline,
  3524. NULL, // Process attributes
  3525. NULL, // Thread attributes
  3526. FALSE, // Handle inheritance
  3527. NORMAL_PRIORITY_CLASS |
  3528. CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP,
  3529. pEnvBlock, // Environment
  3530. NULL, // Current directory
  3531. &startupInfo,
  3532. &processInfo);
  3533. if (! bRet) {
  3534. DBG_WRN(("CEventNotifier::StartCallbackProgram, CreateProcessAsUser failed! GetLastError() = 0x%08X", GetLastError()));
  3535. break;
  3536. }
  3537. //
  3538. // Close the handle passed back
  3539. //
  3540. CloseHandle(processInfo.hProcess);
  3541. CloseHandle(processInfo.hThread);
  3542. } while (FALSE);
  3543. //
  3544. // Garbage collection
  3545. //
  3546. if (hTokenUser) {
  3547. CloseHandle(hTokenUser);
  3548. }
  3549. if (pEnvBlock) {
  3550. DestroyEnvironmentBlock(pEnvBlock);
  3551. }
  3552. return (HRESULT_FROM_WIN32(::GetLastError()));
  3553. }
  3554. #endif
  3555. /**************************************************************************\
  3556. * QueryInterface
  3557. * AddRef
  3558. * Release
  3559. *
  3560. * CWiaInterfaceEvent IUnknown Interface
  3561. *
  3562. * Arguments:
  3563. *
  3564. *
  3565. *
  3566. * Return Value:
  3567. *
  3568. *
  3569. *
  3570. * History:
  3571. *
  3572. * 9/2/1998 Original Version
  3573. *
  3574. \**************************************************************************/
  3575. HRESULT __stdcall
  3576. CWiaInterfaceEvent::QueryInterface(const IID& iid, void** ppv)
  3577. {
  3578. *ppv = NULL;
  3579. if (iid == IID_IUnknown) {
  3580. *ppv = (IUnknown*) this;
  3581. }
  3582. else {
  3583. return E_NOINTERFACE;
  3584. }
  3585. AddRef();
  3586. return S_OK;
  3587. }
  3588. ULONG __stdcall
  3589. CWiaInterfaceEvent::AddRef()
  3590. {
  3591. InterlockedIncrement((long*) &m_cRef);
  3592. return m_cRef;
  3593. }
  3594. ULONG __stdcall
  3595. CWiaInterfaceEvent::Release()
  3596. {
  3597. ULONG ulRefCount = m_cRef - 1;
  3598. if (InterlockedDecrement((long*) &m_cRef) == 0) {
  3599. delete this;
  3600. return 0;
  3601. }
  3602. return ulRefCount;
  3603. }
  3604. /*******************************************************************************
  3605. *
  3606. * CWiaInterfaceEvent
  3607. * ~CWiaInterfaceEvent
  3608. *
  3609. * CWiaInterfaceEvent Constructor/Destructor Methods.
  3610. *
  3611. * History:
  3612. *
  3613. * 9/2/1998 Original Version
  3614. *
  3615. \**************************************************************************/
  3616. CWiaInterfaceEvent::CWiaInterfaceEvent(PEventDestNode pEventDestNode)
  3617. {
  3618. ASSERT(pEventDestNode != NULL);
  3619. m_cRef = 0;
  3620. m_pEventDestNode = pEventDestNode;
  3621. }
  3622. CWiaInterfaceEvent::~CWiaInterfaceEvent()
  3623. {
  3624. //
  3625. // must have exclusive access when changing list
  3626. //
  3627. CWiaCritSect CritSect(&g_semEventNode);
  3628. //
  3629. // make sure registered event is removed
  3630. //
  3631. if (m_pEventDestNode != NULL) {
  3632. g_eventNotifier.UnregisterEventCB(m_pEventDestNode);
  3633. }
  3634. }
  3635. /**************************************************************************\
  3636. * QueryInterface
  3637. * AddRef
  3638. * Release
  3639. *
  3640. * CWiaEventContext IUnknown Interface
  3641. *
  3642. * Arguments:
  3643. *
  3644. *
  3645. *
  3646. * Return Value:
  3647. *
  3648. *
  3649. *
  3650. * History:
  3651. *
  3652. * 1/6/2000 Original Version
  3653. *
  3654. \**************************************************************************/
  3655. HRESULT __stdcall
  3656. CWiaEventContext::QueryInterface(const IID& iid, void** ppv)
  3657. {
  3658. *ppv = NULL;
  3659. if (iid == IID_IUnknown) {
  3660. *ppv = (IUnknown*) this;
  3661. }
  3662. else {
  3663. return E_NOINTERFACE;
  3664. }
  3665. AddRef();
  3666. return S_OK;
  3667. }
  3668. ULONG __stdcall
  3669. CWiaEventContext::AddRef()
  3670. {
  3671. InterlockedIncrement((long*) &m_cRef);
  3672. return m_cRef;
  3673. }
  3674. ULONG __stdcall
  3675. CWiaEventContext::Release()
  3676. {
  3677. ULONG ulRefCount = m_cRef - 1;
  3678. if (InterlockedDecrement((long*) &m_cRef) == 0) {
  3679. delete this;
  3680. return 0;
  3681. }
  3682. return ulRefCount;
  3683. }
  3684. /*******************************************************************************
  3685. *
  3686. * CWiaEventContext
  3687. * ~CWiaEventContext
  3688. *
  3689. * CWiaEventContext Constructor/Destructor Methods.
  3690. *
  3691. * History:
  3692. *
  3693. * 1/6/2000 Original Version
  3694. *
  3695. \**************************************************************************/
  3696. CWiaEventContext::CWiaEventContext(
  3697. BSTR bstrDeviceID,
  3698. const GUID *pGuidEvent,
  3699. BSTR bstrFullItemName)
  3700. {
  3701. //
  3702. // Reference count initialized to 1
  3703. //
  3704. m_cRef = 1;
  3705. m_ulEventType = 0;
  3706. m_guidEvent = *pGuidEvent;
  3707. m_bstrFullItemName = bstrFullItemName;
  3708. m_bstrDeviceId = bstrDeviceID;
  3709. }
  3710. CWiaEventContext::~CWiaEventContext()
  3711. {
  3712. //
  3713. // bstrFullItemName is free in NotifySTIEvent
  3714. //
  3715. if (m_bstrDeviceId) {
  3716. SysFreeString(m_bstrDeviceId);
  3717. m_bstrDeviceId = NULL;
  3718. }
  3719. }
  3720. /**************************************************************************\
  3721. *
  3722. * WiaDelayedEvent
  3723. *
  3724. * Arguments:
  3725. *
  3726. *
  3727. *
  3728. * Return Value:
  3729. *
  3730. *
  3731. *
  3732. * History:
  3733. *
  3734. * 1/6/2000 Original Version
  3735. *
  3736. \**************************************************************************/
  3737. VOID WINAPI
  3738. WiaDelayedEvent(
  3739. VOID *pArg)
  3740. {
  3741. CWiaEventContext *pCEventCtx;
  3742. WIANOTIFY wn;
  3743. //
  3744. // Cast back the context
  3745. //
  3746. if (! pArg) {
  3747. return;
  3748. }
  3749. pCEventCtx = (CWiaEventContext *)pArg;
  3750. //
  3751. // Prepare the notification structure
  3752. //
  3753. wn.lSize = sizeof(WIANOTIFY);
  3754. wn.bstrDevId = pCEventCtx->m_bstrDeviceId;
  3755. wn.stiNotify.dwSize = sizeof(STINOTIFY);
  3756. wn.stiNotify.guidNotificationCode = pCEventCtx->m_guidEvent;
  3757. //
  3758. // Fire the event
  3759. //
  3760. g_eventNotifier.NotifySTIEvent(
  3761. &wn,
  3762. pCEventCtx->m_ulEventType,
  3763. pCEventCtx->m_bstrFullItemName);
  3764. //
  3765. // Release the initial reference
  3766. //
  3767. pCEventCtx->Release();
  3768. }
  3769. /**************************************************************************\
  3770. *
  3771. * wiasQueueEvent
  3772. *
  3773. * Arguments:
  3774. *
  3775. *
  3776. *
  3777. * Return Value:
  3778. *
  3779. *
  3780. *
  3781. * History:
  3782. *
  3783. * 1/6/2000 Original Version
  3784. *
  3785. \**************************************************************************/
  3786. HRESULT _stdcall
  3787. wiasQueueEvent(
  3788. BSTR bstrDeviceId,
  3789. const GUID *pEventGUID,
  3790. BSTR bstrFullItemName)
  3791. {
  3792. HRESULT hr = S_OK;
  3793. BYTE *pRootItemCtx;
  3794. CWiaEventContext *pCEventCtx = NULL;
  3795. BSTR bstrDeviceIdCopy = NULL;
  3796. BSTR bstrFullItemNameCopy = NULL;
  3797. BOOL bRet;
  3798. //
  3799. // Basic sanity check of the parameters
  3800. //
  3801. if ((! bstrDeviceId) || (! pEventGUID)) {
  3802. return (E_INVALIDARG);
  3803. }
  3804. //
  3805. // Poor man's exception handler
  3806. //
  3807. do {
  3808. bstrDeviceIdCopy = SysAllocString(bstrDeviceId);
  3809. if (! bstrDeviceIdCopy) {
  3810. hr = E_OUTOFMEMORY;
  3811. break;
  3812. }
  3813. if (bstrFullItemName) {
  3814. bstrFullItemNameCopy = SysAllocString(bstrFullItemName);
  3815. if (! bstrFullItemNameCopy) {
  3816. hr = E_OUTOFMEMORY;
  3817. break;
  3818. }
  3819. }
  3820. //
  3821. // Create an event context
  3822. //
  3823. pCEventCtx = new CWiaEventContext(
  3824. bstrDeviceIdCopy,
  3825. pEventGUID,
  3826. bstrFullItemNameCopy);
  3827. if (! pCEventCtx) {
  3828. hr = E_OUTOFMEMORY;
  3829. break;
  3830. }
  3831. //
  3832. // Queue a scheduler item
  3833. //
  3834. bRet = ScheduleWorkItem(
  3835. WiaDelayedEvent,
  3836. pCEventCtx,
  3837. 0,
  3838. NULL);
  3839. if (! bRet) {
  3840. hr = E_FAIL;
  3841. }
  3842. } while (FALSE);
  3843. //
  3844. // Garbage collection
  3845. //
  3846. if (hr != S_OK) {
  3847. if (pCEventCtx) {
  3848. delete pCEventCtx;
  3849. } else {
  3850. if (bstrDeviceIdCopy) {
  3851. SysFreeString(bstrDeviceIdCopy);
  3852. }
  3853. }
  3854. if (bstrFullItemNameCopy) {
  3855. SysFreeString(bstrFullItemNameCopy);
  3856. }
  3857. }
  3858. return (hr);
  3859. }
  3860. #ifdef UNICODE
  3861. void
  3862. PrepareCommandline(
  3863. BSTR bstrDeviceID,
  3864. const GUID &guidEvent,
  3865. LPCWSTR pwszOrigCmdline,
  3866. LPWSTR pwszResCmdline)
  3867. {
  3868. WCHAR wszGUIDStr[40];
  3869. WCHAR wszCommandline[MAX_PATH];
  3870. WCHAR *pPercentSign;
  3871. WCHAR *pTest = NULL;
  3872. //
  3873. // Fix up the commandline. First check that it has at least two %
  3874. //
  3875. pTest = wcschr(pwszOrigCmdline, '%');
  3876. if (pTest) {
  3877. pTest = wcschr(pTest + 1, '%');
  3878. }
  3879. if (!pTest) {
  3880. _snwprintf(
  3881. wszCommandline,
  3882. sizeof(wszCommandline) / sizeof( wszCommandline[0] ),
  3883. L"%s /StiDevice:%%1 /StiEvent:%%2",
  3884. pwszOrigCmdline);
  3885. } else {
  3886. wcsncpy(wszCommandline, pwszOrigCmdline, sizeof(wszCommandline) / sizeof( wszCommandline[0] ));
  3887. }
  3888. //
  3889. // enforce null termination
  3890. //
  3891. wszCommandline[ (sizeof(wszCommandline) / sizeof(wszCommandline[0])) - 1 ] = 0;
  3892. //
  3893. // Change the number {1|2} into s
  3894. //
  3895. pPercentSign = wcschr(wszCommandline, L'%');
  3896. *(pPercentSign + 1) = L's';
  3897. pPercentSign = wcschr(pPercentSign + 1, L'%');
  3898. *(pPercentSign + 1) = L's';
  3899. //
  3900. // Convert the GUID into string
  3901. //
  3902. StringFromGUID2(guidEvent, wszGUIDStr, 40);
  3903. //
  3904. // Final comand line
  3905. //
  3906. swprintf(pwszResCmdline, wszCommandline, bstrDeviceID, wszGUIDStr);
  3907. }
  3908. #else
  3909. void
  3910. PrepareCommandline(
  3911. BSTR bstrDeviceID,
  3912. const GUID &guidEvent,
  3913. LPCSTR pszOrigCmdline,
  3914. LPSTR pszResCmdline)
  3915. {
  3916. CHAR szCommandline[MAX_PATH];
  3917. CHAR *pPercentSign;
  3918. WCHAR wszGUIDStr[40];
  3919. char szGUIDStr[40];
  3920. char szDeviceID[12]; // Image\NNNN
  3921. //
  3922. // Fix up the commandline
  3923. //
  3924. DBG_WRN(("PrepareCommandLine"));
  3925. if (! strchr(pszOrigCmdline, '%')) {
  3926. _snprintf(
  3927. szCommandline,
  3928. sizeof(szCommandline) / sizeof( szCommandline[0] ),
  3929. "%s /StiDevice:%%1 /StiEvent:%%2",
  3930. pszOrigCmdline);
  3931. } else {
  3932. strncpy(szCommandline, pszOrigCmdline, sizeof(wszCommandline) / sizeof( wszCommandline[0] ));
  3933. }
  3934. //
  3935. // enforce null termination
  3936. //
  3937. szCommandline[ (sizeof(szCommandline) / sizeof(szCommandline[0])) - 1 ] = 0;
  3938. //
  3939. // Change the number {1|2} into s
  3940. //
  3941. pPercentSign = strchr(szCommandline, '%');
  3942. *(pPercentSign + 1) = 's';
  3943. pPercentSign = strchr(pPercentSign + 1, '%');
  3944. *(pPercentSign + 1) = 's';
  3945. //
  3946. // Convert the GUID into string
  3947. //
  3948. StringFromGUID2(guidEvent, wszGUIDStr, 40);
  3949. WideCharToMultiByte(CP_ACP,
  3950. 0,
  3951. bstrDeviceID,
  3952. -1,
  3953. szDeviceID,
  3954. sizeof(szDeviceID),
  3955. NULL,
  3956. NULL);
  3957. WideCharToMultiByte(CP_ACP,
  3958. 0,
  3959. wszGUIDStr,
  3960. -1,
  3961. szGUIDStr,
  3962. sizeof(szGUIDStr),
  3963. NULL,
  3964. NULL);
  3965. //
  3966. // Final result
  3967. //
  3968. sprintf(pszResCmdline, szCommandline, szDeviceID, szGUIDStr);
  3969. }
  3970. #endif
  3971. /**************************************************************************\
  3972. *
  3973. * ActionGuidExists
  3974. *
  3975. * Returns true if the specified event GUID is reported as an ACTION event
  3976. * by the driver
  3977. *
  3978. * Arguments:
  3979. *
  3980. * bstrDevId - identifies the device we're interested in
  3981. * pEventGUID - identifies the event we're looking for
  3982. *
  3983. * Return Value:
  3984. *
  3985. * TRUE - The driver reports this event as an ACTION event
  3986. * FALSE - This is not an ACTION event for this device
  3987. *
  3988. * History:
  3989. *
  3990. * 03/01/2000 Original Version
  3991. *
  3992. \**************************************************************************/
  3993. BOOL ActionGuidExists(
  3994. BSTR bstrDevId,
  3995. const GUID *pEventGUID)
  3996. {
  3997. BOOL bRet = FALSE;
  3998. IWiaDevMgr *pIDevMgr = NULL;
  3999. IWiaItem *pIItem = NULL;
  4000. IEnumWIA_DEV_CAPS *pIEnum = NULL;
  4001. WIA_DEV_CAP DevCap;
  4002. ULONG ulVal;
  4003. HRESULT hr = E_FAIL;
  4004. //
  4005. // Get the device manager and create an item interface for that device
  4006. //
  4007. hr = CWiaDevMgr::CreateInstance(IID_IWiaDevMgr, (VOID**) &pIDevMgr);
  4008. if (SUCCEEDED(hr)) {
  4009. hr = pIDevMgr->CreateDevice(bstrDevId, &pIItem);
  4010. if (SUCCEEDED(hr)) {
  4011. //
  4012. // Get an enumerator for the events
  4013. //
  4014. hr = pIItem->EnumDeviceCapabilities(WIA_DEVICE_EVENTS, &pIEnum);
  4015. if (SUCCEEDED(hr)) {
  4016. //
  4017. // Iterate through events to check whether we have a
  4018. // match
  4019. //
  4020. while(pIEnum->Next(1, &DevCap, &ulVal) == S_OK) {
  4021. if (DevCap.guid == *pEventGUID) {
  4022. //
  4023. // Check whether it's an action event, and mark
  4024. // our return to TRUE if it is.
  4025. //
  4026. if (DevCap.ulFlags & WIA_ACTION_EVENT) {
  4027. bRet = TRUE;
  4028. break;
  4029. }
  4030. }
  4031. }
  4032. pIEnum->Release();
  4033. } else {
  4034. DBG_WRN(("ActionGuidExists() : Failed to enumerate (0x%X)", hr));
  4035. }
  4036. pIItem->Release();
  4037. } else {
  4038. DBG_WRN(("ActionGuidExists() : Failed to create device (0x%X)", hr));
  4039. }
  4040. pIDevMgr->Release();
  4041. } else {
  4042. DBG_WRN(("ActionGuidExists() : Failed to create device manager (0x%X)", hr));
  4043. }
  4044. return bRet;
  4045. }