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.

3758 lines
98 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. stidev.cpp
  5. Abstract:
  6. Code to maintain list of STI devices and poll them
  7. Author:
  8. Vlad Sadovsky (VladS) 11-Feb-1997
  9. Byron Changuion (ByronC)
  10. History:
  11. 12/15/1998 VladS "List invalidate" support for unknown ADD/REMOVE device messages
  12. 01/08/1999 VladS Support for PnP interface notifications
  13. 12/08/1999 VladS Initiate move to complete server environment by using direct calls to the driver
  14. 11/06/2000 ByronC Enabled JIT loading/unloading of drivers, and inactive enumeration
  15. --*/
  16. //
  17. // Include Headers
  18. //
  19. #include "precomp.h"
  20. #include "stiexe.h"
  21. #include <rpc.h>
  22. #include <userenv.h>
  23. #include <mmsystem.h>
  24. #include <stilib.h>
  25. #include <validate.h>
  26. #include "stiusd.h"
  27. #include "device.h"
  28. #include "conn.h"
  29. #include "monui.h"
  30. #include "wiapriv.h"
  31. #include "lockmgr.h"
  32. #include "fstidev.h"
  33. #include <apiutil.h>
  34. #include "enum.h"
  35. #include "wiadevdp.h"
  36. #define PRIVATE_FOR_NO_SERVICE_UI
  37. //
  38. // Flag passed to our persistent event handler to let it know
  39. // whether the event is an STI device event or a WIA device event
  40. //
  41. #define STI_DEVICE_EVENT 0xF0000000
  42. //
  43. // Local defines and macros
  44. //
  45. //
  46. // Delay hardware initialization till happy time.
  47. //
  48. #define POSTPONE_INIT2
  49. //
  50. // Global service window handle
  51. extern HWND g_hStiServiceWindow;
  52. extern SERVICE_STATUS_HANDLE g_StiServiceStatusHandle;
  53. //
  54. // Validate guid of the event received from USD against the list of device events
  55. //
  56. #define VALIDATE_EVENT_GUID 1
  57. //
  58. // Static variables
  59. //
  60. //
  61. //
  62. // Linked list of maintained device objects, along with syncronization object
  63. // to guard access to it
  64. //
  65. LIST_ENTRY g_DeviceListHead;
  66. CRIT_SECT g_DeviceListSync;
  67. BOOL g_fDeviceListInitialized = FALSE;
  68. //
  69. // REMOVE:
  70. // Counter of active device objects
  71. //
  72. LONG g_lTotalActiveDevices = 0;
  73. //
  74. // Value of unique identified assigned to a device object to use as a handle.
  75. //
  76. LONG g_lGlobalDeviceId; // Use temporarily to identify opened device
  77. //
  78. // Connection list , used in connection objects methods, initialize here
  79. //
  80. extern LIST_ENTRY g_ConnectionListHead;
  81. extern LONG g_lTotalOpenedConnections ;
  82. //
  83. // Static function prototypes
  84. //
  85. EXTERN_C
  86. HANDLE
  87. GetCurrentUserTokenW(
  88. WCHAR Winsta[],
  89. DWORD DesiredAccess
  90. );
  91. BOOL
  92. WINAPI
  93. DumpTokenInfo(
  94. LPTSTR pszPrefix,
  95. HANDLE hToken
  96. );
  97. VOID
  98. WINAPI
  99. ScheduleDeviceCallback(
  100. VOID * pContext
  101. );
  102. VOID
  103. WINAPI
  104. DelayedDeviceInitCallback(
  105. VOID * pContext
  106. );
  107. VOID
  108. WINAPI
  109. AutoLaunchThread(
  110. LPVOID lpParameter
  111. );
  112. VOID
  113. CleanApplicationsListForEvent(
  114. LPCTSTR pDeviceName,
  115. PDEVICEEVENT pDeviceEvent,
  116. LPCTSTR pAppName
  117. );
  118. DWORD
  119. GetNumRegisteredApps(
  120. VOID
  121. );
  122. BOOL
  123. inline
  124. IsWildCardEvent(
  125. PDEVICEEVENT pev
  126. )
  127. /*++
  128. Routine Description:
  129. Check if given event app list represents wild-card
  130. Arguments:
  131. Return Value:
  132. TRUE , FALSE
  133. --*/
  134. {
  135. return !lstrcmp((LPCTSTR)pev->m_EventData,TEXT("*"));
  136. }
  137. //
  138. // Methods for device object
  139. //
  140. ACTIVE_DEVICE::ACTIVE_DEVICE(IN LPCTSTR lpszDeviceName, DEVICE_INFO *pInfo)
  141. {
  142. DBG_FN("ACTIVE_DEVICE::ACTIVE_DEVICE");
  143. USES_CONVERSION;
  144. PSTI_DEVICE_INFORMATION pDevInfo;
  145. HRESULT hres;
  146. m_dwSignature = ADEV_SIGNATURE;
  147. m_fValid = FALSE;
  148. m_fRefreshedBusOnFailure = FALSE;
  149. m_hDeviceEvent = NULL;
  150. m_pLastLaunchEvent = NULL;
  151. m_dwUserDisableNotifications = FALSE;
  152. m_hDeviceInterface = NULL;
  153. m_hDeviceNotificationSink = NULL;
  154. m_fLaunchableEventListNotEmpty = FALSE;
  155. m_dwSchedulerCookie = 0L;
  156. m_dwDelayedOpCookie = 0L;
  157. m_uiPollFailureCount = 0L;
  158. m_dwLaunchEventTimeExpire = 0;
  159. m_pLockInfo = NULL;
  160. m_pFakeStiDevice = NULL;
  161. m_pRootDrvItem = NULL;
  162. InitializeListHead(&m_ListEntry );
  163. InitializeListHead(&m_ConnectionListHead);
  164. InitializeListHead(&m_DeviceEventListHead );
  165. InterlockedIncrement(&g_lTotalActiveDevices);
  166. SetFlags(0L);
  167. if (!lpszDeviceName || !*lpszDeviceName) {
  168. ASSERT(("Trying to create device with invalid name", 0));
  169. return;
  170. }
  171. m_lDeviceId = InterlockedIncrement(&g_lGlobalDeviceId);
  172. hres = m_DrvWrapper.Initialize();
  173. if (FAILED(hres)) {
  174. m_fValid = FALSE;
  175. DBG_WRN(("ACTIVE_DEVICE::ACTIVE_DEVICE, Could not initialize driver wrapper class, marking this object invalid"));
  176. return;
  177. }
  178. m_DrvWrapper.setDevInfo(pInfo);
  179. //
  180. // Initialize device settings
  181. //
  182. GetDeviceSettings();
  183. //
  184. // object state is valid
  185. //
  186. m_fValid = TRUE;
  187. //
  188. // Check whether driver should be loaded on startup
  189. //
  190. if (!m_DrvWrapper.getJITLoading()) {
  191. // Also note that if the device is not active, we simply do not load
  192. // the driver, regardless of whether it's JIT or not.
  193. //
  194. if (m_DrvWrapper.getDeviceState() & DEV_STATE_ACTIVE) {
  195. //
  196. // Note that this object is still valid, even if driver cannot be loaded.
  197. // For example, driver will not be loaded if device is not plugged in.
  198. //
  199. LoadDriver();
  200. }
  201. }
  202. DBG_TRC(("Created active device object for device (%ws)",GetDeviceID()));
  203. return;
  204. } /* eop constructor */
  205. ACTIVE_DEVICE::~ACTIVE_DEVICE( VOID )
  206. {
  207. DBG_FN(ACTIVE_DEVICE::~ACTIVE_DEVICE);
  208. //LIST_ENTRY * pentry;
  209. STI_CONN *pConnection = NULL;
  210. //
  211. // When we are coming to a destructor it is assumed no current usage by any
  212. // other thread. We don't need to lock device object therefore.
  213. //
  214. //
  215. if (!IsValid() ) {
  216. return;
  217. }
  218. DBG_TRC(("Removing device object for device(%ws)", GetDeviceID()));
  219. //
  220. // Mark device object as being removed
  221. //
  222. SetFlags(QueryFlags() | STIMON_AD_FLAG_REMOVING);
  223. //
  224. // Stop PnP notifications if is enabled
  225. //
  226. StopPnPNotifications();
  227. //
  228. // Remove any delayed operation from scheduler queue
  229. //
  230. if (m_dwDelayedOpCookie) {
  231. RemoveWorkItem(m_dwDelayedOpCookie);
  232. m_dwDelayedOpCookie = 0;
  233. }
  234. //
  235. // Unload the driver.
  236. //
  237. UnLoadDriver(TRUE);
  238. //
  239. // Destroy Fake Sti Device
  240. //
  241. if (m_pFakeStiDevice) {
  242. delete m_pFakeStiDevice;
  243. m_pFakeStiDevice = NULL;
  244. }
  245. //
  246. // Destroy Lock information
  247. //
  248. if (m_pLockInfo) {
  249. LockInfo *pLockInfo = (LockInfo*) m_pLockInfo;
  250. if (pLockInfo->hDeviceIsFree != NULL) {
  251. CloseHandle(pLockInfo->hDeviceIsFree);
  252. pLockInfo->hDeviceIsFree = NULL;
  253. }
  254. LocalFree(m_pLockInfo);
  255. m_pLockInfo = NULL;
  256. }
  257. //
  258. // Delete all connection objects
  259. //
  260. {
  261. while (!IsListEmpty(&m_ConnectionListHead)) {
  262. pConnection = CONTAINING_RECORD( m_ConnectionListHead.Flink , STI_CONN, m_DeviceListEntry );
  263. if (pConnection->IsValid()) {
  264. DestroyDeviceConnection(pConnection->QueryID(),TRUE);
  265. }
  266. }
  267. }
  268. //
  269. // Remove from scheduled list if still there
  270. //
  271. if (m_ListEntry.Flink &&!IsListEmpty(&m_ListEntry)) {
  272. ASSERT(("Device is destructed, but still on the list", 0));
  273. RemoveEntryList(&m_ListEntry);
  274. InitializeListHead( &m_ListEntry );
  275. }
  276. //
  277. // Close the device's event handle
  278. //
  279. if (m_hDeviceEvent) {
  280. CloseHandle(m_hDeviceEvent);
  281. m_hDeviceEvent = NULL;
  282. }
  283. m_dwSignature = ADEV_SIGNATURE_FREE;
  284. //
  285. // We are gone completely
  286. //
  287. InterlockedDecrement(&g_lTotalActiveDevices);
  288. } /* eop destructor */
  289. //
  290. // IUnknown methods. Used only for reference counting
  291. //
  292. STDMETHODIMP
  293. ACTIVE_DEVICE::QueryInterface( REFIID riid, LPVOID * ppvObj)
  294. {
  295. return E_FAIL;
  296. }
  297. STDMETHODIMP_(ULONG)
  298. ACTIVE_DEVICE::AddRef( void)
  299. {
  300. ::InterlockedIncrement(&m_cRef);
  301. //DBG_TRC(("Device(%x)::AddRef RefCount=%d "),this,m_cRef);
  302. return m_cRef;
  303. }
  304. STDMETHODIMP_(ULONG)
  305. ACTIVE_DEVICE::Release( void)
  306. {
  307. LONG cNew;
  308. //DBG_TRC(("Device(%x)::Release (before) RefCount=%d "),this,m_cRef);
  309. if(!(cNew = ::InterlockedDecrement(&m_cRef))) {
  310. delete this;
  311. }
  312. return cNew;
  313. }
  314. VOID
  315. ACTIVE_DEVICE::
  316. GetDeviceSettings(
  317. VOID
  318. )
  319. /*++
  320. Routine Description:
  321. Get settings for the device being opened , for future use. This routine also marks whether
  322. the driver should be loaded on startup, or JIT
  323. Arguments:
  324. Return Value:
  325. --*/
  326. {
  327. DBG_FN(ACTIVE_DEVICE::GetDeviceSettings);
  328. //
  329. // Build device event list
  330. //
  331. m_fLaunchableEventListNotEmpty = BuildEventList();
  332. if (!m_fLaunchableEventListNotEmpty) {
  333. DBG_TRC(("ACTIVE_DEVICE::GetDeviceSettings, Device registry indicates no events for %ws ", GetDeviceID()));
  334. }
  335. //
  336. // Get value of poll timeout if device is polled
  337. //
  338. m_dwPollingInterval = m_DrvWrapper.getPollTimeout();
  339. if (m_dwPollingInterval < STIDEV_MIN_POLL_TIME) {
  340. m_dwPollingInterval = g_uiDefaultPollTimeout;
  341. }
  342. HRESULT hr = S_OK;
  343. DWORD dwType = REG_DWORD;
  344. DWORD dwSize = sizeof(m_dwUserDisableNotifications);
  345. //
  346. // Always read this value from the registry, just in case user changed it.
  347. //
  348. hr = g_pDevMan->GetDeviceValue(this,
  349. STI_DEVICE_VALUE_DISABLE_NOTIFICATIONS,
  350. &dwType,
  351. (BYTE*) &m_dwUserDisableNotifications,
  352. &dwSize);
  353. /* TDB: When we can load normal drivers JIT
  354. //
  355. // Decide whether driver should be loaded on Startup or JIT. Our rules for
  356. // determining this are:
  357. // 1. If devices is not capable of generating ACTION events, then load it JIT
  358. // 2. If notifications for this device are disabled, then load JIT
  359. // 3. In all other cases, load on startup.
  360. //
  361. if (!m_fLaunchableEventListNotEmpty || m_dwUserDisableNotifications) {
  362. m_DrvWrapper.setJITLoading(TRUE);
  363. DBG_TRC(("ACTIVE_DEVICE::GetDeviceSettings, Driver will be loaded JIT"));
  364. } else {
  365. m_DrvWrapper.setJITLoading(FALSE);
  366. DBG_TRC(("ACTIVE_DEVICE::GetDeviceSettings, Driver will be loaded on startup"));
  367. }
  368. */
  369. //
  370. // Decide whether driver should be loaded on Startup or JIT. Until we enable for
  371. // normal drivers like the comments above, our descision is based on:
  372. // 1) Is this a volume device? If so, then load JIT
  373. //
  374. if (m_DrvWrapper.getInternalType() & INTERNAL_DEV_TYPE_VOL) {
  375. m_DrvWrapper.setJITLoading(TRUE);
  376. DBG_TRC(("ACTIVE_DEVICE::GetDeviceSettings, Driver will be loaded JIT"));
  377. } else {
  378. m_DrvWrapper.setJITLoading(FALSE);
  379. DBG_TRC(("ACTIVE_DEVICE::GetDeviceSettings, Driver will be loaded on startup"));
  380. }
  381. }
  382. BOOL
  383. ACTIVE_DEVICE::
  384. LoadDriver(
  385. BOOL bReReadDevInfo /*= FALSE*/
  386. )
  387. /*++
  388. Routine Description:
  389. Arguments:
  390. Return Value:
  391. --*/
  392. {
  393. USES_CONVERSION;
  394. HRESULT hres = E_FAIL;
  395. DEVICE_INFO *pDeviceInfo = NULL;
  396. //
  397. // We don't want to re-load the driver if it's already loaded.
  398. //
  399. if (m_DrvWrapper.IsDriverLoaded()) {
  400. return TRUE;
  401. }
  402. if (m_DrvWrapper.IsPlugged()) {
  403. HKEY hKeyDevice = g_pDevMan->GetDeviceHKey(this, NULL);
  404. //
  405. // If asked, re-read the device information. The easiest way to do this
  406. // is to re-create the Dev. Info. structure.
  407. //
  408. if (bReReadDevInfo) {
  409. pDeviceInfo = m_DrvWrapper.getDevInfo();
  410. if (pDeviceInfo) {
  411. //
  412. // This only applies to non-volume devices. Volume devices' dev. info.
  413. // stucts are always re-created on enumeration, so are always current.
  414. //
  415. if (!(pDeviceInfo->dwInternalType & INTERNAL_DEV_TYPE_VOL)) {
  416. DEVICE_INFO *pNewDeviceInfo = NULL;
  417. //
  418. // When calling CreateDevInfoFromHKey, make sure that the
  419. // SP_DEVICE_INTERFACE_DATA parameter is NULL for
  420. // DevNode devices and non-NULL for interface devices.
  421. //
  422. SP_DEVICE_INTERFACE_DATA *pspDevInterfaceData = NULL;
  423. if (pDeviceInfo->dwInternalType & INTERNAL_DEV_TYPE_INTERFACE) {
  424. pspDevInterfaceData = &(pDeviceInfo->spDevInterfaceData);
  425. }
  426. pNewDeviceInfo = CreateDevInfoFromHKey(hKeyDevice,
  427. pDeviceInfo->dwDeviceState,
  428. &(pDeviceInfo->spDevInfoData),
  429. pspDevInterfaceData);
  430. //
  431. // If we successfully created the new one, destroy the old one
  432. // and set the new one as the DevInfo for this device.
  433. // Otherwise, leave the old one intact.
  434. //
  435. if (pNewDeviceInfo) {
  436. DestroyDevInfo(pDeviceInfo);
  437. m_DrvWrapper.setDevInfo(pNewDeviceInfo);
  438. }
  439. }
  440. }
  441. }
  442. //
  443. // Get the device information pointer here, in case it was updated above.
  444. //
  445. pDeviceInfo = m_DrvWrapper.getDevInfo();
  446. if (!pDeviceInfo) {
  447. DBG_ERR(("ACTIVE_DEVICE::LoadDriver, Cannot function with NULL Device Info.!"));
  448. return FALSE;
  449. }
  450. DBG_TRC(("ACTIVE_DEVICE::LoadDriver, Device is plugged: about to load driver"));
  451. hres = m_DrvWrapper.LoadInitDriver(hKeyDevice);
  452. if (SUCCEEDED(hres)) {
  453. //
  454. // For those devices who may modify their Friendly Name (e.g. PTP),
  455. // we refresh their settings here. Notice this only applies to
  456. // "real", non-interface devices.
  457. //
  458. if (m_DrvWrapper.getInternalType() & INTERNAL_DEV_TYPE_REAL) {
  459. if (pDeviceInfo && hKeyDevice) {
  460. RefreshDevInfoFromHKey(pDeviceInfo,
  461. hKeyDevice,
  462. pDeviceInfo->dwDeviceState,
  463. &(pDeviceInfo->spDevInfoData),
  464. &(pDeviceInfo->spDevInterfaceData));
  465. //
  466. // Also update the Friendly Name in device manager for
  467. // non-interface (i.e. DevNode) devices.
  468. // Note: Only do this if the Friendly name is non-NULL,
  469. // not empty, and doesn't already exist in registry.
  470. //
  471. if (!(m_DrvWrapper.getInternalType() & INTERNAL_DEV_TYPE_INTERFACE)) {
  472. //
  473. // Check whether the friendly name exists
  474. //
  475. DWORD dwSize = 0;
  476. CM_Get_DevNode_Registry_Property(pDeviceInfo->spDevInfoData.DevInst,
  477. CM_DRP_FRIENDLYNAME,
  478. NULL,
  479. NULL,
  480. &dwSize,
  481. 0);
  482. if (dwSize == 0) {
  483. //
  484. // Check the our LocalName string is non-NULL and not empty
  485. //
  486. if (pDeviceInfo->wszLocalName && lstrlenW(pDeviceInfo->wszLocalName)) {
  487. CM_Set_DevNode_Registry_PropertyW(pDeviceInfo->spDevInfoData.DevInst,
  488. CM_DRP_FRIENDLYNAME,
  489. pDeviceInfo->wszLocalName,
  490. (lstrlenW(pDeviceInfo->wszLocalName) + 1) * sizeof(WCHAR),
  491. 0);
  492. }
  493. }
  494. }
  495. }
  496. }
  497. //
  498. // Verify device capabilities require polling
  499. //
  500. if (m_DrvWrapper.getGenericCaps() & STI_GENCAP_NOTIFICATIONS) {
  501. //
  502. // Mark device object as receiving USD Notifications
  503. //
  504. SetFlags(QueryFlags() | STIMON_AD_FLAG_NOTIFY_CAPABLE);
  505. //
  506. // If timeout polling required, mark it.
  507. //
  508. if (m_DrvWrapper.getGenericCaps() & STI_GENCAP_POLLING_NEEDED) {
  509. DBG_TRC(("ACTIVE_DEVICE::LoadDriver, Polling device"));
  510. SetFlags(QueryFlags() | STIMON_AD_FLAG_POLLING);
  511. }
  512. else {
  513. DBG_TRC(("ACTIVE_DEVICE::LoadDriver, Device is marked for async events"));
  514. //
  515. // No polling required - USD should support async events
  516. //
  517. if (!m_hDeviceEvent) {
  518. m_hDeviceEvent = CreateEvent( NULL, // Security
  519. TRUE, // Manual reset
  520. FALSE, // No signalled initially
  521. NULL ); // Name
  522. }
  523. if (!m_hDeviceEvent) {
  524. ASSERT(("Failed to create event for notifications ", 0));
  525. }
  526. m_dwPollingInterval = INFINITE;
  527. }
  528. }
  529. //
  530. // Set poll interval and initiate poll
  531. //
  532. SetPollingInterval(m_dwPollingInterval);
  533. DBG_TRC(("Polling interval is set to %d sec on device (%ws)", (m_dwPollingInterval == INFINITE) ? -1 : (m_dwPollingInterval/1000), GetDeviceID()));
  534. //
  535. // Schedule EnableDeviceNotifications() and device reset
  536. //
  537. #ifdef POSTPONE_INIT2
  538. SetFlags(QueryFlags() | STIMON_AD_FLAG_DELAYED_INIT);
  539. //
  540. // Constructor of active device object is called with global list critical section taken
  541. // so we want to get out of here as soon as possible
  542. //
  543. m_dwDelayedOpCookie = ScheduleWorkItem((PFN_SCHED_CALLBACK) DelayedDeviceInitCallback,
  544. this,
  545. STIDEV_DELAYED_INTIT_TIME,
  546. NULL);
  547. if (!m_dwDelayedOpCookie) {
  548. DBG_ERR(("Could not schedule EnableNotificationsCallback"));
  549. }
  550. #else
  551. {
  552. TAKE_ACTIVE_DEVICE _t(this);
  553. EnableDeviceNotifications();
  554. }
  555. #endif
  556. if (!m_pFakeStiDevice) {
  557. //
  558. // Set the Fake Sti Device for WIA clients
  559. //
  560. m_pFakeStiDevice = new FakeStiDevice();
  561. if (m_pFakeStiDevice) {
  562. //
  563. // Note that this form of init cannot fail
  564. //
  565. m_pFakeStiDevice->Init(this);
  566. }
  567. }
  568. }
  569. if (IsValidHANDLE(hKeyDevice)) {
  570. RegCloseKey(hKeyDevice);
  571. hKeyDevice = NULL;
  572. }
  573. return TRUE;
  574. } else {
  575. DBG_TRC(("ACTIVE_DEVICE::LoadDriver, Device is unplugged: not loading driver"));
  576. }
  577. return FALSE;
  578. }
  579. BOOL
  580. ACTIVE_DEVICE::
  581. UnLoadDriver(
  582. BOOL bForceUnLoad
  583. )
  584. /*++
  585. Routine Description:
  586. Arguments:
  587. Return Value:
  588. --*/
  589. {
  590. DBG_FN(ACTIVE_DEVICE::UnloadSTIDevice);
  591. BOOL bUnLoadDriver = FALSE;
  592. //
  593. // Decide whether driver should be unloaded. If bForceUnLoad == TRUE,
  594. // we always unload.
  595. //
  596. if (bForceUnLoad) {
  597. bUnLoadDriver = TRUE;
  598. } else {
  599. //
  600. // If this device is JIT, and there are no pending connections,
  601. // unload it.
  602. //
  603. if (m_DrvWrapper.getJITLoading() && !m_DrvWrapper.getWiaClientCount()) {
  604. bUnLoadDriver = TRUE;
  605. }
  606. }
  607. if (bUnLoadDriver) {
  608. //
  609. // Disable device notifications
  610. //
  611. DisableDeviceNotifications();
  612. HRESULT hr = S_OK;
  613. if (m_DrvWrapper.IsDriverLoaded()) {
  614. __try {
  615. hr = g_pStiLockMgr->RequestLock(this, INFINITE); // Should this be infinite?????
  616. //
  617. // Make sure we call drvUninitializeWia on any connected App. Items
  618. //
  619. if (m_pRootDrvItem) {
  620. m_pRootDrvItem->CallDrvUninitializeForAppItems(this);
  621. m_pRootDrvItem = NULL;
  622. }
  623. }
  624. __finally
  625. {
  626. //
  627. // Call USD's unlock, before unloading driver. Notice that we
  628. // don't call g_pStiLockMgr->RequestUnlock(..). This is to avoid
  629. // a race condition between us calling RequestUnlock and
  630. // unloading the driver. This way, the device is always locked
  631. // for mutally exclusive acess, including when we call
  632. // m_DrvWrapper.UnLoadDriver(). Our subsequent call to
  633. // g_pStiLockMgr->ClearLockInfo(..) then clears the service
  634. // lock we just acquired.
  635. //
  636. if (SUCCEEDED(hr)) {
  637. hr = g_pStiLockMgr->UnlockDevice(this);
  638. }
  639. }
  640. //
  641. // Unload the driver.
  642. //
  643. m_DrvWrapper.UnLoadDriver();
  644. //
  645. // Clear the USD lock information
  646. //
  647. if (m_pLockInfo) {
  648. g_pStiLockMgr->ClearLockInfo((LockInfo*) m_pLockInfo);
  649. }
  650. }
  651. }
  652. return TRUE;
  653. }
  654. BOOL
  655. ACTIVE_DEVICE::
  656. BuildEventList(
  657. VOID
  658. )
  659. /*++
  660. Routine Description:
  661. Loads list of device notifications, which can activate application launch
  662. If device generates notification, which is not in this list, no app will start
  663. Arguments:
  664. Return Value:
  665. TRUE if successfully built event list with at least one launchable application
  666. FALSE on error or if there are no applications to be launched for any events on this device
  667. --*/
  668. {
  669. DEVICEEVENT * pDeviceEvent;
  670. TCHAR szTempString[MAX_PATH];
  671. DWORD dwSubkeyIndex = 0;
  672. BOOL fRet = FALSE;
  673. UINT cEventsRead = 0;
  674. UINT cEventsLaunchables = 0;
  675. HKEY hDevKey = NULL;
  676. HRESULT hr = S_OK;
  677. //
  678. // Get the device key
  679. //
  680. hDevKey = g_pDevMan->GetDeviceHKey(this, NULL);
  681. if (!hDevKey) {
  682. DBG_WRN(("Could not open device key for (%ws) hr = 0x%X.",GetDeviceID(), hr));
  683. return FALSE;
  684. }
  685. //
  686. // Open the events sub-key
  687. //
  688. RegEntry reEventsList(EVENTS,hDevKey);
  689. StiCString strEventSubKeyName;
  690. strEventSubKeyName.GetBufferSetLength(MAX_PATH);
  691. dwSubkeyIndex = 0;
  692. //
  693. // Clear existing list first
  694. //
  695. DestroyEventList();
  696. while (reEventsList.EnumSubKey(dwSubkeyIndex++,&strEventSubKeyName)) {
  697. //
  698. // Open new key for individual event
  699. //
  700. RegEntry reEvent((LPCTSTR)strEventSubKeyName,reEventsList.GetKey());
  701. if (!reEvent.IsValid()) {
  702. // ASSERT
  703. continue;
  704. }
  705. //
  706. // Allocate and fill event structure
  707. //
  708. pDeviceEvent = new DEVICEEVENT;
  709. if (!pDeviceEvent) {
  710. // ASSERT
  711. break;
  712. }
  713. cEventsRead++;
  714. //
  715. // Read and parse event guid
  716. //
  717. pDeviceEvent->m_EventGuid = GUID_NULL;
  718. pDeviceEvent->m_EventSubKey.CopyString(strEventSubKeyName);
  719. *szTempString = TEXT('\0');
  720. reEvent.GetString(TEXT("GUID"),szTempString,sizeof(szTempString));
  721. if (!IS_EMPTY_STRING(szTempString)) {
  722. ParseGUID(&pDeviceEvent->m_EventGuid,szTempString);
  723. }
  724. //
  725. // Get event descriptive name
  726. //
  727. *szTempString = TEXT('\0');
  728. reEvent.GetString(TEXT(""),szTempString,sizeof(szTempString));
  729. pDeviceEvent->m_EventName.CopyString(szTempString);
  730. //
  731. // Get applications list
  732. //
  733. *szTempString = TEXT('\0');
  734. reEvent.GetString(TEXT("LaunchApplications"),szTempString,sizeof(szTempString));
  735. pDeviceEvent->m_EventData.CopyString(szTempString);
  736. //
  737. // Mark launchability of the event
  738. //
  739. pDeviceEvent->m_fLaunchable = (BOOL)reEvent.GetNumber(TEXT("Launchable"),(long)TRUE);
  740. if (pDeviceEvent->m_fLaunchable && (pDeviceEvent->m_EventData.GetLength()!= 0 )) {
  741. cEventsLaunchables++;
  742. fRet = TRUE;
  743. }
  744. //
  745. // Finally insert filled structure into the list
  746. //
  747. InsertTailList(&m_DeviceEventListHead, &(pDeviceEvent->m_ListEntry));
  748. } // end while
  749. if (hDevKey) {
  750. RegCloseKey(hDevKey);
  751. hDevKey = NULL;
  752. }
  753. DBG_TRC(("Reading event list for device:%ws Total:%d Launchable:%d ",
  754. GetDeviceID(),
  755. cEventsRead,
  756. cEventsLaunchables));
  757. return fRet;
  758. } // endproc BuildEventList
  759. BOOL
  760. ACTIVE_DEVICE::
  761. DestroyEventList(
  762. VOID
  763. )
  764. {
  765. //
  766. // Destroy event list
  767. //
  768. LIST_ENTRY * pentry;
  769. DEVICEEVENT * pDeviceEvent;
  770. while (!IsListEmpty(&m_DeviceEventListHead)) {
  771. pentry = m_DeviceEventListHead.Flink;
  772. //
  773. // Remove from the list ( reset list entry )
  774. //
  775. RemoveHeadList(&m_DeviceEventListHead);
  776. InitializeListHead( pentry );
  777. pDeviceEvent = CONTAINING_RECORD( pentry, DEVICEEVENT,m_ListEntry );
  778. delete pDeviceEvent;
  779. }
  780. return TRUE;
  781. }
  782. BOOL
  783. ACTIVE_DEVICE::DoPoll(VOID)
  784. {
  785. USES_CONVERSION;
  786. HRESULT hres;
  787. BOOL fDeviceEventDetected = FALSE;
  788. STINOTIFY sNotify;
  789. //
  790. // verify state of the device object
  791. //
  792. if (!IsValid() || !m_DrvWrapper.IsDriverLoaded() ||
  793. !(QueryFlags() & (STIMON_AD_FLAG_POLLING | STIMON_AD_FLAG_NOTIFY_RUNNING))) {
  794. DBG_WRN(("Polling on non-activated or non-polled device."));
  795. return FALSE;
  796. }
  797. m_dwSchedulerCookie = 0;
  798. //
  799. // Lock device to get status information
  800. //
  801. {
  802. hres = g_pStiLockMgr->RequestLock(this, STIMON_AD_DEFAULT_WAIT_LOCK);
  803. if (SUCCEEDED(hres) ) {
  804. ZeroMemory(&m_DevStatus,sizeof(m_DevStatus));
  805. m_DevStatus.StatusMask = STI_DEVSTATUS_EVENTS_STATE;
  806. DBG_TRC(("Polling called on device:%ws", GetDeviceID()));
  807. hres = m_DrvWrapper.STI_GetStatus(&m_DevStatus);
  808. if (SUCCEEDED(hres) ) {
  809. //
  810. // If event detected, ask USD for additional information and
  811. // unlock device
  812. //
  813. if (m_DevStatus.dwEventHandlingState & STI_EVENTHANDLING_PENDING ) {
  814. fDeviceEventDetected = TRUE;
  815. if (!FillEventFromUSD(&sNotify)) {
  816. DBG_WRN(("Device driver claimed presence of notification, but failed to fill notification block"));
  817. }
  818. }
  819. // Reset failure skip count
  820. m_uiPollFailureCount = STIDEV_POLL_FAILURE_REPORT_COUNT;
  821. }
  822. else {
  823. //
  824. // Report error not on each polling attempt.
  825. //
  826. if (!m_uiPollFailureCount) {
  827. DBG_ERR(("Device (%ws) failed get status for events. HResult=(%x)", GetDeviceID(), hres));
  828. m_uiPollFailureCount = STIDEV_POLL_FAILURE_REPORT_COUNT;
  829. //
  830. // Too many subsequent polling failures - time to refresh device parent.
  831. // Do it only once and only if failures had been due to device absence
  832. //
  833. if (hres == STIERR_DEVICE_NOTREADY) {
  834. //
  835. // Stop polling on inactive device.
  836. // Nb: there is no way currently to restart polling
  837. //
  838. DBG_TRC(("Device not ready ,stopping notifications for device (%ws)",GetDeviceID()));
  839. //
  840. // First turn off running flag
  841. //
  842. m_dwFlags &= ~STIMON_AD_FLAG_NOTIFY_RUNNING;
  843. if (g_fRefreshDeviceControllerOnFailures &&
  844. !m_fRefreshedBusOnFailure ) {
  845. DBG_WRN(("Too many polling failures , refreshing parent object for the device "));
  846. // TDB:
  847. //hres = g_pSti->RefreshDeviceBus(T2W((LPTSTR)GetDeviceID()));
  848. m_fRefreshedBusOnFailure = TRUE;
  849. }
  850. }
  851. }
  852. m_uiPollFailureCount--;
  853. }
  854. hres = g_pStiLockMgr->RequestUnlock(this);
  855. if(FAILED(hres)) {
  856. DBG_ERR(("Failed to unlock device, hr = %x", hres));
  857. }
  858. }
  859. else {
  860. DBG_ERR(("Device locked , could not get status . HResult=(%x)",hres));
  861. }
  862. } /* end block on GetLockMgrDevice */
  863. //
  864. // If successfully detected device event and filled notification information -
  865. // proceed to processing method
  866. //
  867. if (fDeviceEventDetected) {
  868. ProcessEvent(&sNotify);
  869. }
  870. //
  871. // Schedule next poll, unless notifications disabled
  872. //
  873. if (m_dwFlags & STIMON_AD_FLAG_NOTIFY_RUNNING) {
  874. m_dwSchedulerCookie = ::ScheduleWorkItem(
  875. (PFN_SCHED_CALLBACK) ScheduleDeviceCallback,
  876. (LPVOID)this,
  877. m_dwPollingInterval,
  878. m_hDeviceEvent );
  879. if ( !m_dwSchedulerCookie ){
  880. ASSERT(("Polling routine could not schedule work item", 0));
  881. return FALSE;
  882. }
  883. }
  884. return TRUE;
  885. } /* eop DoPoll */
  886. BOOL
  887. ACTIVE_DEVICE::DoAsyncEvent(VOID)
  888. {
  889. HRESULT hres;
  890. BOOL fRet;
  891. BOOL fDeviceEventDetected = FALSE;
  892. STINOTIFY sNotify;
  893. DBG_FN(ACTIVE_DEVICE::DoAsyncEvent);
  894. //
  895. // verify state of the device object
  896. //
  897. if (!IsValid() || !m_DrvWrapper.IsDriverLoaded() ||
  898. !(QueryFlags() & STIMON_AD_FLAG_NOTIFY_RUNNING)) {
  899. DBG_WRN(("Async event on non-activated device."));
  900. return FALSE;
  901. }
  902. m_dwSchedulerCookie = 0;
  903. //
  904. // Lock device to get event information
  905. //
  906. hres = g_pStiLockMgr->RequestLock(this, STIMON_AD_DEFAULT_WAIT_LOCK);
  907. if (SUCCEEDED(hres) ) {
  908. //
  909. // If event detected, ask USD for additional information and
  910. // unlock device
  911. //
  912. if (!FillEventFromUSD(&sNotify)) {
  913. DBG_WRN(("Device driver claimed presence of notification, but failed to fill notification block "));
  914. }
  915. g_pStiLockMgr->RequestUnlock(this);
  916. fDeviceEventDetected = TRUE;
  917. }
  918. else {
  919. DBG_TRC(("Device locked , could not get status . HResult=(%x)",hres));
  920. }
  921. //
  922. // If successfully detected device event and filled notification information -
  923. // proceed to processing method
  924. //
  925. if (fDeviceEventDetected) {
  926. ProcessEvent(&sNotify);
  927. }
  928. //
  929. // Schedule next event unless polling disabled
  930. //
  931. if (m_dwFlags & STIMON_AD_FLAG_NOTIFY_RUNNING) {
  932. fRet = FALSE;
  933. if (m_hDeviceEvent) {
  934. ::ResetEvent(m_hDeviceEvent);
  935. fRet = SetHandleForUSD(m_hDeviceEvent);
  936. }
  937. if (!fRet) {
  938. DBG_ERR(("USD refused to take event handle , or event was not created "));
  939. ReportError(ERROR_INVALID_PARAMETER);
  940. return FALSE;
  941. }
  942. m_dwSchedulerCookie = ::ScheduleWorkItem(
  943. (PFN_SCHED_CALLBACK) ScheduleDeviceCallback,
  944. (LPVOID)this,
  945. m_dwPollingInterval,
  946. m_hDeviceEvent );
  947. if ( !m_dwSchedulerCookie ){
  948. ASSERT(("Async routine could not schedule work item", 0));
  949. return FALSE;
  950. }
  951. }
  952. return TRUE;
  953. } /* eop DoAsyncEvent */
  954. DWORD
  955. ACTIVE_DEVICE::
  956. DisableDeviceNotifications(
  957. VOID
  958. )
  959. {
  960. //
  961. // First turn off running and enable flags
  962. //
  963. DBG_TRC(("Request to disable notifications for device (%S)",GetDeviceID()));
  964. m_dwFlags &= ~STIMON_AD_FLAG_NOTIFY_ENABLED;
  965. StopNotifications();
  966. return TRUE;
  967. }
  968. DWORD
  969. ACTIVE_DEVICE::
  970. EnableDeviceNotifications(
  971. VOID
  972. )
  973. {
  974. DWORD dwRet = FALSE;
  975. m_dwFlags |= STIMON_AD_FLAG_NOTIFY_ENABLED;
  976. DBG_TRC(("Request to enable notifications for device (%S)",GetDeviceID()));
  977. if (NotificationsNeeded()) {
  978. dwRet = StartRunningNotifications();
  979. }
  980. else {
  981. DBG_TRC(("No notifications support needed for this device (%S)",GetDeviceID()));
  982. }
  983. return dwRet;
  984. }
  985. DWORD
  986. ACTIVE_DEVICE::
  987. StopNotifications(
  988. VOID
  989. )
  990. {
  991. BOOL fNotificationsOn = FALSE;
  992. fNotificationsOn = (m_dwFlags & STIMON_AD_FLAG_NOTIFY_RUNNING ) ? TRUE : FALSE;
  993. DBG_TRC(("Stopping notifications for device (%S)",GetDeviceID()));
  994. //
  995. // First turn off running and enable flags
  996. //
  997. m_dwFlags &= ~STIMON_AD_FLAG_NOTIFY_RUNNING;
  998. //
  999. // Remove from scheduler list
  1000. //
  1001. if (fNotificationsOn || m_dwSchedulerCookie) {
  1002. RemoveWorkItem(m_dwSchedulerCookie);
  1003. m_dwSchedulerCookie = NULL;
  1004. }
  1005. //
  1006. // Clear event handle for USD
  1007. //
  1008. if ((m_DrvWrapper.IsDriverLoaded()) &&
  1009. (m_dwFlags & STIMON_AD_FLAG_NOTIFY_CAPABLE ) &&
  1010. !(m_dwFlags & STIMON_AD_FLAG_POLLING) ) {
  1011. SetHandleForUSD(NULL);
  1012. }
  1013. return TRUE;
  1014. }
  1015. DWORD
  1016. ACTIVE_DEVICE::
  1017. StartRunningNotifications(
  1018. VOID
  1019. )
  1020. {
  1021. BOOL fRet = FALSE;
  1022. if (!(m_dwFlags & STIMON_AD_FLAG_NOTIFY_CAPABLE )) {
  1023. // Device is not capable of notifications
  1024. DBG_WRN(("Trying to run notifications on non capable device "));
  1025. return FALSE;
  1026. }
  1027. //
  1028. // If not enabled for notifications - return
  1029. //
  1030. if ( !(m_dwFlags & STIMON_AD_FLAG_NOTIFY_ENABLED )) {
  1031. DBG_TRC(("Trying to run notifications on device (%S), disabled for notifications", GetDeviceID()));
  1032. ReportError(ERROR_SERVICE_DISABLED);
  1033. return FALSE;
  1034. }
  1035. if ( m_dwFlags & STIMON_AD_FLAG_NOTIFY_RUNNING ) {
  1036. ASSERT(("Notifications enabled, but cookie ==0", m_dwSchedulerCookie));
  1037. return TRUE;
  1038. }
  1039. if (!IsDeviceAvailable()) {
  1040. ReportError(ERROR_NOT_READY);
  1041. return FALSE;
  1042. }
  1043. //
  1044. // We are starting receiving notifications first time, flush events from USD
  1045. //
  1046. FlushDeviceNotifications();
  1047. //
  1048. // Set event handle for USD if it is capable of async notifications
  1049. //
  1050. if ( (m_dwFlags & STIMON_AD_FLAG_NOTIFY_CAPABLE ) &&
  1051. !(m_dwFlags & STIMON_AD_FLAG_POLLING) ) {
  1052. fRet = FALSE;
  1053. if (m_hDeviceEvent) {
  1054. ::ResetEvent(m_hDeviceEvent);
  1055. fRet = SetHandleForUSD(m_hDeviceEvent);
  1056. }
  1057. if (!fRet) {
  1058. DBG_ERR(("USD refused to take event handle , or event was not created "));
  1059. ReportError(ERROR_INVALID_PARAMETER);
  1060. return FALSE;
  1061. }
  1062. }
  1063. fRet = FALSE;
  1064. //
  1065. // Starting accepting notifications - mark refresh flag as not done yet
  1066. //
  1067. m_fRefreshedBusOnFailure = FALSE;
  1068. //
  1069. // Schedule event processing for this device
  1070. //
  1071. m_dwSchedulerCookie = ::ScheduleWorkItem(
  1072. (PFN_SCHED_CALLBACK) ScheduleDeviceCallback,
  1073. (LPVOID)this,
  1074. m_dwPollingInterval,
  1075. m_hDeviceEvent );
  1076. if ( m_dwSchedulerCookie ){
  1077. m_dwFlags |= STIMON_AD_FLAG_NOTIFY_RUNNING;
  1078. DBG_TRC(("Started receiving notifications for device (%S)",GetDeviceID()));
  1079. fRet = TRUE;
  1080. }
  1081. return fRet;
  1082. } /* eop StartRunningNotifications */
  1083. BOOL
  1084. ACTIVE_DEVICE::
  1085. FlushDeviceNotifications(
  1086. VOID
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. Arguments:
  1091. Return Value:
  1092. TRUE if successful, FALSE on error (call GetLastError)
  1093. --*/
  1094. {
  1095. HRESULT hres;
  1096. STINOTIFY sNotify;
  1097. //
  1098. // verify state of the device object
  1099. //
  1100. if (!IsValid() || m_DrvWrapper.IsDriverLoaded() ||
  1101. !(QueryFlags() & (STIMON_AD_FLAG_NOTIFY_ENABLED ))) {
  1102. return FALSE;
  1103. }
  1104. //
  1105. // Lock device to get status information
  1106. //
  1107. hres = g_pStiLockMgr->RequestLock(this, STIMON_AD_DEFAULT_WAIT_LOCK);
  1108. if (SUCCEEDED(hres) ) {
  1109. ZeroMemory(&m_DevStatus,sizeof(m_DevStatus));
  1110. m_DevStatus.StatusMask = STI_DEVSTATUS_EVENTS_STATE;
  1111. hres = m_DrvWrapper.STI_GetStatus(&m_DevStatus);
  1112. if (SUCCEEDED(hres) ) {
  1113. //
  1114. // If event detected, ask USD for additional information and
  1115. // unlock device
  1116. //
  1117. if (m_DevStatus.dwEventHandlingState & STI_EVENTHANDLING_PENDING ) {
  1118. FillEventFromUSD(&sNotify);
  1119. }
  1120. }
  1121. g_pStiLockMgr->RequestUnlock(this);
  1122. }
  1123. return TRUE;
  1124. } /* eop FlushDeviceNotifications */
  1125. BOOL
  1126. ACTIVE_DEVICE::
  1127. ProcessEvent(
  1128. STINOTIFY *psNotify,
  1129. BOOL fForceLaunch, // = FALSE
  1130. LPCTSTR pszAppName // =NULL
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Is invoked when monitored device is issuing a device notification
  1135. ( either by poll , or by signalling handle).
  1136. USD is called to obtain notification parameters.
  1137. If device is already connected to, notification is passed to connection, currently in
  1138. focus.
  1139. If device is not connected to and notification is in the list of "launchable" , attempt is made
  1140. to launch application, which will acquire image from the device
  1141. Arguments:
  1142. Return Value:
  1143. TRUE if successful, FALSE on error (call GetLastError)
  1144. --*/
  1145. {
  1146. PDEVICEEVENT pDeviceEvent = NULL;
  1147. DWORD dwCurrentTickCount;
  1148. HANDLE hThread;
  1149. DWORD dwThread;
  1150. BOOL fRet;
  1151. STIMONWPRINTF(TEXT("Processing device notification for device (%s)"),GetDeviceID());
  1152. //
  1153. // Notify WIA of event if this is a valid WIA device event.
  1154. //
  1155. if (m_DrvWrapper.IsWiaDevice() &&
  1156. psNotify) {
  1157. HRESULT hr;
  1158. hr = NotifyWiaDeviceEvent(GetDeviceID(),
  1159. &psNotify->guidNotificationCode,
  1160. &psNotify->abNotificationData[0],
  1161. 0,
  1162. g_dwMessagePumpThreadId);
  1163. if (hr == S_FALSE) {
  1164. //
  1165. // WIA has handled this event and doesn't want to
  1166. // chain the event to STI for further processing.
  1167. //
  1168. return TRUE;
  1169. }
  1170. }
  1171. if (!fForceLaunch ) {
  1172. //
  1173. // If there is at least one connection to this device, pass notification
  1174. // information to connection in focus
  1175. //
  1176. if (IsConnectedTo() ) {
  1177. STIMONWPRINTF(TEXT("Notification delivered to subscriber"));
  1178. STI_CONN *pConnection = NULL;
  1179. LIST_ENTRY *pentry;
  1180. pentry = m_ConnectionListHead.Flink;
  1181. pConnection = CONTAINING_RECORD( pentry, STI_CONN,m_DeviceListEntry );
  1182. pConnection->QueueNotificationToProcess(psNotify);
  1183. return TRUE;
  1184. }
  1185. }
  1186. //
  1187. // Nobody connected to this device, so we need to see if associated
  1188. // application can be launched
  1189. // STIMONWPRINTF(TEXT("ProcessEvent received device notification, requiring auto launch."));
  1190. //
  1191. // Validate event against list of launchable events, associated with device object.
  1192. // If user explicitly disabled "events" for this device - don't launch anything
  1193. //
  1194. if (m_dwUserDisableNotifications || IsListEmpty(&m_DeviceEventListHead)) {
  1195. // No active launchable events , associated with this device
  1196. STIMONWPRINTF(TEXT("User disabled events or event list is empty for the device, ignoring notification"));
  1197. return FALSE;
  1198. }
  1199. LIST_ENTRY * pentry;
  1200. LIST_ENTRY * pentryNext;
  1201. for ( pentry = m_DeviceEventListHead.Flink;
  1202. pentry != &m_DeviceEventListHead;
  1203. pentry = pentryNext ) {
  1204. pentryNext = pentry->Flink;
  1205. pDeviceEvent = CONTAINING_RECORD( pentry,DEVICEEVENT ,m_ListEntry );
  1206. if(IsEqualIID(pDeviceEvent->m_EventGuid,psNotify->guidNotificationCode)) {
  1207. break;
  1208. }
  1209. else {
  1210. pDeviceEvent = NULL;
  1211. }
  1212. }
  1213. if (!pDeviceEvent || !pDeviceEvent->m_fLaunchable) {
  1214. // Not launchable event - don't do anything
  1215. DBG_TRC(("Did not recognize launchable event or event list is empty, notification ignored."));
  1216. #ifdef VALIDATE_EVENT_GUID
  1217. return FALSE;
  1218. #else
  1219. pDeviceEvent = CONTAINING_RECORD( m_DeviceEventListHead.Flink,DEVICEEVENT ,m_ListEntry );
  1220. DBG_ERR(("Using first event in the list for interim testing"));
  1221. #endif
  1222. }
  1223. //
  1224. // If we are already in after launch period - skip event
  1225. //
  1226. if (m_dwFlags & STIMON_AD_FLAG_LAUNCH_PENDING) {
  1227. dwCurrentTickCount = ::GetTickCount();
  1228. if ( dwCurrentTickCount < m_dwLaunchEventTimeExpire ) {
  1229. DBG_TRC(("Waiting since last event had not expired yet, notification ignored"));
  1230. ReportError(ERROR_NOT_READY);
  1231. return FALSE;
  1232. }
  1233. }
  1234. //
  1235. // Launching application may cause unpredictable delays . We don't want to hold
  1236. // main event processing thread , so kick in another dedicated thread to control
  1237. // process spawning. Before device lock is released, it is marked as waiting for pending
  1238. // launch, to prevent laucnchable events in quick succession from autolaunching
  1239. //
  1240. m_dwFlags |= STIMON_AD_FLAG_LAUNCH_PENDING;
  1241. //
  1242. // Set waiting period expiration limit, so we know when to start paying attention to
  1243. // launch events again
  1244. //
  1245. m_dwLaunchEventTimeExpire = ::GetTickCount() + STIMON_AD_DEFAULT_WAIT_LAUNCH;
  1246. m_pLastLaunchEvent = pDeviceEvent;
  1247. //
  1248. // Complete the outstanding AsyncRPC call to the ShellHWDetection Service.
  1249. // This will inform it of the STI device event.
  1250. //
  1251. DEVICE_INFO *pDeviceInfo = m_DrvWrapper.getDevInfo();
  1252. if (pDeviceInfo && psNotify)
  1253. {
  1254. EnterCriticalSection(&g_RpcEvent.cs);
  1255. if(g_RpcEvent.pAsync) {
  1256. RPC_STATUS status;
  1257. int nReply = 1;
  1258. g_RpcEvent.pEvent->EventGuid = psNotify->guidNotificationCode;
  1259. g_RpcEvent.pEvent->bstrEventDescription = SysAllocString(L"");
  1260. g_RpcEvent.pEvent->bstrDeviceID = SysAllocString(pDeviceInfo->wszDeviceInternalName);
  1261. g_RpcEvent.pEvent->bstrDeviceDescription = SysAllocString(pDeviceInfo->wszDeviceDescription);
  1262. g_RpcEvent.pEvent->dwDeviceType = (DWORD) pDeviceInfo->DeviceType;
  1263. g_RpcEvent.pEvent->bstrFullItemName = SysAllocString(NULL);
  1264. //
  1265. // Make sure WiaRPC knows this is for an STI device, and not a WIA device.
  1266. //
  1267. g_RpcEvent.pEvent->ulEventType = STI_DEVICE_EVENT;
  1268. status = RpcAsyncCompleteCall(g_RpcEvent.pAsync, &nReply);
  1269. if(status) {
  1270. DBG_ERR(("RpcAsyncComplete failed with error 0x%x", status));
  1271. } else {
  1272. DBG_ERR(("Completed RPC call"));
  1273. }
  1274. g_RpcEvent.pAsync = NULL;
  1275. fRet = TRUE;
  1276. } else {
  1277. DBG_ERR(("Did not have pAsync for this event"));
  1278. }
  1279. LeaveCriticalSection(&g_RpcEvent.cs);
  1280. }
  1281. //
  1282. // This code has been replaced in .NET Server with an AsyncRPC implementation
  1283. //
  1284. /*
  1285. PAUTO_LAUNCH_PARAM_CONTAINER pAutoContainer = new AUTO_LAUNCH_PARAM_CONTAINER;
  1286. if (!pAutoContainer) {
  1287. ReportError(ERROR_NOT_ENOUGH_MEMORY);
  1288. return FALSE;
  1289. }
  1290. pAutoContainer->pActiveDevice = this;
  1291. pAutoContainer->pLaunchEvent = pDeviceEvent;
  1292. pAutoContainer->pAppName = pszAppName;
  1293. //
  1294. // If application name already requested, we will not display UI, so perform
  1295. // syncronous call.
  1296. //
  1297. if (pszAppName) {
  1298. fRet = AutoLaunch(pAutoContainer);
  1299. delete pAutoContainer;
  1300. }
  1301. else {
  1302. //
  1303. // AddRef here to ensure we're not unloaded or destroyed while processing this
  1304. // event.
  1305. // Note: AutoLaunchThread must Release() this refcount.
  1306. //
  1307. AddRef();
  1308. hThread = ::CreateThread(NULL,
  1309. 0,
  1310. (LPTHREAD_START_ROUTINE)AutoLaunchThread,
  1311. (LPVOID)pAutoContainer,
  1312. 0,
  1313. &dwThread);
  1314. if ( hThread ) {
  1315. ::CloseHandle(hThread);
  1316. }
  1317. fRet = TRUE;
  1318. }
  1319. */
  1320. return fRet;
  1321. } // endproc ProcessEvent
  1322. BOOL
  1323. ACTIVE_DEVICE::
  1324. AutoLaunch(
  1325. PAUTO_LAUNCH_PARAM_CONTAINER pAutoContainer
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. Attempt to automatically launch application, which is associated with active device
  1330. event
  1331. Arguments:
  1332. Return Value:
  1333. TRUE if successful, FALSE on error (call GetLastError)
  1334. --*/
  1335. {
  1336. PDEVICEEVENT pDeviceEvent ;
  1337. BOOL fRet;
  1338. BOOL fChooseAgain;
  1339. BOOL fFailedFirstSelection = FALSE;
  1340. BOOL fFailedUserEnv = FALSE;
  1341. STRArray saAppList;
  1342. STRArray saCommandLineList;
  1343. DWORD dwError;
  1344. pDeviceEvent = (pAutoContainer->pLaunchEvent) ? (pAutoContainer->pLaunchEvent) : m_pLastLaunchEvent;
  1345. if (!pDeviceEvent) {
  1346. ASSERT(("No event available to AutoLaunch routine", 0));
  1347. return FALSE;
  1348. }
  1349. ASSERT(m_dwFlags & STIMON_AD_FLAG_LAUNCH_PENDING);
  1350. //
  1351. // Attract user attention
  1352. //
  1353. #ifdef PLAYSOUND_ALWAYS
  1354. ::PlaySound(TEXT("StillImageDevice"),NULL,SND_ALIAS | SND_ASYNC | SND_NOWAIT | SND_NOSTOP);
  1355. #endif
  1356. //
  1357. // Nothing appears to be launched, so continue with it
  1358. // Retreive command line
  1359. m_strLaunchCommandLine.CopyString(TEXT("\0"));
  1360. fRet = FALSE;
  1361. fRet = RetrieveSTILaunchInformation(pDeviceEvent,
  1362. pAutoContainer->pAppName,
  1363. saAppList,
  1364. saCommandLineList,
  1365. fFailedFirstSelection ? TRUE : FALSE
  1366. );
  1367. if (fRet) {
  1368. DEVICE_INFO *pDeviceInfo = pAutoContainer->pActiveDevice->m_DrvWrapper.getDevInfo();
  1369. if (pDeviceInfo) {
  1370. HRESULT hr = S_OK;
  1371. WCHAR *wszDest = NULL;
  1372. LONG *plSize = NULL;
  1373. IWiaEventCallback *pIEventCB = NULL;
  1374. ULONG ulEventType = WIA_ACTION_EVENT;
  1375. //
  1376. // Variables used as parameters for the ImageEventCallback() method.
  1377. //
  1378. BSTR bstrEventDescription = SysAllocString((LPCTSTR)pDeviceEvent->m_EventName);
  1379. BSTR bstrDeviceID = SysAllocString(pDeviceInfo->wszDeviceInternalName);
  1380. BSTR bstrDeviceDescription = SysAllocString(pDeviceInfo->wszDeviceDescription);
  1381. DWORD dwDeviceType = (DWORD) pDeviceInfo->DeviceType;
  1382. if (bstrEventDescription && bstrDeviceID && bstrDeviceDescription) {
  1383. //
  1384. // Package the Application list and the relevant command line info in a double
  1385. // NULL terminated BSTR. First calculate the number of bytes this will take.
  1386. // Our calculations are made up as follows:
  1387. // For every item in the AppList, add space for App name plus terminating NULL.
  1388. // For every item in the CommandLineList, add space for command line plus terminating NULL.
  1389. // Lastly, add space for terminating NULL (ensuring that the list is double NULL terminated)
  1390. //
  1391. // NOTE: Assumption here is that RetrieveSTILaunchInformation returns saAppList and
  1392. // saCommandLineList to have the same number of elements.
  1393. //
  1394. INT iCount;
  1395. LONG lSize = 0;
  1396. for (iCount = 0; iCount < saAppList.GetSize(); iCount++) {
  1397. lSize += (lstrlenW((LPCTSTR)*saAppList[iCount]) * sizeof(WCHAR)) + sizeof(L'\0');
  1398. lSize += (lstrlenW((LPCTSTR)*saCommandLineList[iCount]) * sizeof(WCHAR)) + sizeof(L'\0');
  1399. }
  1400. lSize += sizeof(L'\0') + sizeof(LONG);
  1401. BSTR bstrAppList = SysAllocStringByteLen(NULL, lSize);
  1402. if (bstrAppList) {
  1403. //
  1404. // Copy each null termintaed string into the BSTR (including the terminating null),
  1405. // and make sure the end is double terminated.
  1406. //
  1407. wszDest = bstrAppList;
  1408. for (iCount = 0; iCount < saAppList.GetSize(); iCount++) {
  1409. lstrcpyW(wszDest, (LPCTSTR)*saAppList[iCount]);
  1410. wszDest += lstrlenW(wszDest) + 1;
  1411. lstrcpyW(wszDest, (LPCTSTR)*saCommandLineList[iCount]);
  1412. wszDest += lstrlenW(wszDest) + 1;
  1413. }
  1414. wszDest[0] = L'\0';
  1415. //
  1416. // CoCreate our event UI handler. Note that it will not display any UI
  1417. // if there is only one application.
  1418. //
  1419. hr = _CoCreateInstanceInConsoleSession(
  1420. CLSID_StiEventHandler,
  1421. NULL,
  1422. CLSCTX_LOCAL_SERVER,
  1423. IID_IWiaEventCallback,
  1424. (void**)&pIEventCB);
  1425. if (SUCCEEDED(hr)) {
  1426. //
  1427. // Make the callback.
  1428. //
  1429. hr = pIEventCB->ImageEventCallback(&pDeviceEvent->m_EventGuid,
  1430. bstrEventDescription,
  1431. bstrDeviceID,
  1432. bstrDeviceDescription,
  1433. dwDeviceType,
  1434. bstrAppList,
  1435. &ulEventType,
  1436. 0);
  1437. pIEventCB->Release();
  1438. if (FAILED(hr)) {
  1439. DBG_ERR(("ACTIVE_DEVICE::AutoLaunch, could not launch STI event handler"));
  1440. fRet = FALSE;
  1441. }
  1442. }
  1443. SysFreeString(bstrAppList);
  1444. if (SUCCEEDED(hr)) {
  1445. //
  1446. // Application was launched
  1447. //
  1448. fRet = TRUE;
  1449. }
  1450. } else {
  1451. DBG_ERR(("ACTIVE_DEVICE::AutoLaunch, Out of memory!"));
  1452. fRet = FALSE;
  1453. }
  1454. } else {
  1455. DBG_ERR(("ACTIVE_DEVICE::AutoLaunch, Out of memory!"));
  1456. fRet = FALSE;
  1457. }
  1458. if (bstrEventDescription) {
  1459. SysFreeString(bstrEventDescription);
  1460. bstrEventDescription = NULL;
  1461. }
  1462. if (bstrDeviceID) {
  1463. SysFreeString(bstrDeviceID);
  1464. bstrDeviceID = NULL;
  1465. }
  1466. if (bstrDeviceDescription) {
  1467. SysFreeString(bstrDeviceDescription);
  1468. bstrDeviceDescription = NULL;
  1469. }
  1470. } else {
  1471. DBG_WRN(("ACTIVE_DEVICE::AutoLaunch, Device Information is NULL, ignoring event"));
  1472. fRet = FALSE;
  1473. }
  1474. }
  1475. else {
  1476. DBG_WRN(("ACTIVE_DEVICE::AutoLaunch, Could not get command line to launch application"));
  1477. // m_dwFlags &= ~STIMON_AD_FLAG_LAUNCH_PENDING;
  1478. fRet = FALSE;
  1479. }
  1480. //
  1481. // Clear the launch pending flag
  1482. //
  1483. m_dwFlags &= ~STIMON_AD_FLAG_LAUNCH_PENDING;
  1484. return fRet;
  1485. } // endproc AutoLaunch
  1486. BOOL
  1487. ACTIVE_DEVICE::
  1488. RetrieveSTILaunchInformation(
  1489. PDEVICEEVENT pev,
  1490. LPCTSTR pAppName,
  1491. STRArray& saAppList,
  1492. STRArray& saCommandLine,
  1493. BOOL fForceSelection // =FALSE
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. Get command line for automatic process launch.
  1498. Arguments:
  1499. Return Value:
  1500. TRUE if successful, FALSE on error (call GetLastError)
  1501. --*/
  1502. {
  1503. //
  1504. // If all registered applications are allowed to start on this event
  1505. // create array of names from registered list. Otherwise , parse list of
  1506. // allowed applications
  1507. //
  1508. ReportError(NOERROR);
  1509. if (IsWildCardEvent(pev) || fForceSelection ) {
  1510. RegEntry re(REGSTR_PATH_REG_APPS,HKEY_LOCAL_MACHINE);
  1511. RegEnumValues regenum(&re);
  1512. while (ERROR_SUCCESS == regenum.Next() ) {
  1513. if ( ((regenum.GetType() == REG_SZ ) ||(regenum.GetType() == REG_EXPAND_SZ ))
  1514. && !IS_EMPTY_STRING(regenum.GetName())) {
  1515. saAppList.Add((LPCTSTR)regenum.GetName());
  1516. }
  1517. }
  1518. }
  1519. else {
  1520. //
  1521. // Split into array of strings
  1522. //
  1523. TokenizeIntoStringArray(saAppList,
  1524. (LPCTSTR)pev->m_EventData,
  1525. TEXT(','));
  1526. }
  1527. //
  1528. // Work with filled array of applications
  1529. //
  1530. if (saAppList.GetSize() < 1) {
  1531. return FALSE;
  1532. }
  1533. //
  1534. // If application name requested, validate it against available list. Otherwise proceed
  1535. // with UI
  1536. //
  1537. if (pAppName) {
  1538. //
  1539. // Search through the list of available applications for the name of requested
  1540. //
  1541. INT iCount;
  1542. BOOL fFound = FALSE;
  1543. for (iCount = 0;
  1544. iCount < saAppList.GetSize();
  1545. iCount++) {
  1546. if (::lstrcmpi(pAppName,(LPCTSTR)*saAppList[iCount]) == 0) {
  1547. fFound = TRUE;
  1548. }
  1549. }
  1550. if (!fFound) {
  1551. // Invalid application name requested
  1552. ReportError(ERROR_INVALID_PARAMETER);
  1553. return FALSE;
  1554. } else {
  1555. //
  1556. // The app list should only contain this app's name, so remove all elements
  1557. // and add this one.
  1558. //
  1559. saAppList.RemoveAll();
  1560. saAppList.Add(pAppName);
  1561. }
  1562. }
  1563. //
  1564. // saAppList now contains the list of Applications to launch.
  1565. // We must fill saCommandLine with the relevant command lines.
  1566. //
  1567. INT iCount;
  1568. DBG_TRC(("Processing Device Event: AppList and CommandLines are:"));
  1569. for (iCount = 0; iCount < saAppList.GetSize(); iCount++) {
  1570. //
  1571. // Format command line for execution
  1572. //
  1573. RegEntry re(REGSTR_PATH_REG_APPS,HKEY_LOCAL_MACHINE);
  1574. StiCString strLaunchCommandLine;
  1575. TCHAR szRegCommandLine[2*255];
  1576. TCHAR szEventName[255] = {TEXT("")};
  1577. TCHAR *pszUuidString = NULL;
  1578. *szRegCommandLine = TEXT('\0');
  1579. re.GetString((LPCTSTR)*saAppList[iCount],szRegCommandLine,sizeof(szRegCommandLine));
  1580. if(!*szRegCommandLine) {
  1581. DBG_WRN(("ACTIVE_DEVICE::RetrieveSTILaunchInformation, RegEntry::GetString failed!"));
  1582. return FALSE;
  1583. }
  1584. if (UuidToString(&pev->m_EventGuid,(RPC_STRING *)&pszUuidString) != RPC_S_OK)
  1585. {
  1586. DBG_WRN(("ACTIVE_DEVICE::RetrieveSTILaunchInformation, UuidToString() failed!"));
  1587. return FALSE;
  1588. }
  1589. ASSERT(pszUuidString);
  1590. wsprintf(szEventName,TEXT("{%s}"),pszUuidString ? (TCHAR *)pszUuidString :TEXT(""));
  1591. strLaunchCommandLine.FormatMessage(szRegCommandLine,GetDeviceID(),szEventName);
  1592. //
  1593. // Add this to the list of Command Lines
  1594. //
  1595. saCommandLine.Add((LPCTSTR)strLaunchCommandLine);
  1596. if (pszUuidString) {
  1597. RpcStringFree((RPC_STRING *)&pszUuidString);
  1598. pszUuidString = NULL;
  1599. }
  1600. DBG_PRT((" AppName = (%ls)", (LPCTSTR)*saAppList[iCount]));
  1601. DBG_PRT((" CommandLine = (%ls)", (LPCTSTR)*saCommandLine[iCount]));
  1602. };
  1603. //
  1604. // Check that saAppList and saCommandLine have the same number of elements
  1605. //
  1606. if (saAppList.GetSize() != saCommandLine.GetSize()) {
  1607. DBG_WRN(("ACTIVE_DEVICE::RetrieveSTILaunchInformation, Application list and Command Line list have different number of elements!"));
  1608. return FALSE;
  1609. }
  1610. return TRUE;
  1611. } // endproc RetrieveAutoLaunchCommandLine
  1612. BOOL
  1613. ACTIVE_DEVICE::
  1614. IsDeviceAvailable(
  1615. VOID
  1616. )
  1617. /*++
  1618. Routine Description:
  1619. Returns TRUE if device is available for monitoring .
  1620. Arguments:
  1621. Return Value:
  1622. TRUE if successful, FALSE on error (call GetLastError)
  1623. --*/
  1624. {
  1625. STI_DEVICE_STATUS sds;
  1626. HRESULT hRes = STI_OK;
  1627. BOOL bRet;
  1628. //
  1629. // Check valid state
  1630. //
  1631. if (!IsValid() || !m_DrvWrapper.IsDriverLoaded()) {
  1632. return FALSE;
  1633. }
  1634. //
  1635. // Get and analyze status information from active device
  1636. //
  1637. ::ZeroMemory(&sds,sizeof(sds));
  1638. sds.StatusMask = STI_DEVSTATUS_ONLINE_STATE;
  1639. hRes = g_pStiLockMgr->RequestLock(this, 1000);
  1640. if (SUCCEEDED(hRes)) {
  1641. hRes = m_DrvWrapper.STI_GetStatus(&sds);
  1642. g_pStiLockMgr->RequestUnlock(this);
  1643. }
  1644. else {
  1645. //
  1646. // Ignore locking violation, as it may indicate device is in normal
  1647. // state
  1648. //
  1649. if ((STIERR_SHARING_VIOLATION == hRes) || (WIA_ERROR_BUSY == hRes) ) {
  1650. hRes = STI_OK;
  1651. //
  1652. // Since we couldn't talk to the device because someone else is speaking to it,
  1653. // we assume it's online
  1654. //
  1655. sds.dwOnlineState = STI_ONLINESTATE_OPERATIONAL;
  1656. }
  1657. }
  1658. bRet = SUCCEEDED(hRes) &&
  1659. (sds.dwOnlineState & STI_ONLINESTATE_OPERATIONAL) ;
  1660. DBG_TRC(("Request to check state on device (%S). RESULT:%s", GetDeviceID(),bRet ? "Available" : "Not available"));
  1661. return bRet;
  1662. } // endproc IsDeviceAvailable
  1663. BOOL
  1664. ACTIVE_DEVICE::
  1665. RemoveConnection(
  1666. STI_CONN *pConnection
  1667. )
  1668. {
  1669. TAKE_ACTIVE_DEVICE t(this);
  1670. STI_CONN *pExistingConnection = NULL;
  1671. BOOL fRet = FALSE;
  1672. pExistingConnection = FindMyConnection((HANDLE)pConnection->QueryID());
  1673. if (pExistingConnection) {
  1674. DBG_TRC(("Device(%S) removing connection (%x)", GetDeviceID(), pConnection));
  1675. pConnection->DumpObject();
  1676. RemoveEntryList(&pConnection->m_DeviceListEntry);
  1677. //
  1678. // Reset flags on device object
  1679. //
  1680. if (pConnection->QueryOpenMode() & STI_DEVICE_CREATE_DATA) {
  1681. SetFlags(QueryFlags() & ~STIMON_AD_FLAG_OPENED_FOR_DATA);
  1682. }
  1683. SetFlags(QueryFlags() & ~STIMON_AD_FLAG_LAUNCH_PENDING);
  1684. //
  1685. // If this was the last connection, stop notifications on a device
  1686. //
  1687. if (!NotificationsNeeded()) {
  1688. StopNotifications();
  1689. }
  1690. fRet = TRUE;
  1691. }
  1692. else {
  1693. // No connection on this device list
  1694. DBG_ERR(("Removing connection not on the list for this device (%S)",GetDeviceID()));
  1695. }
  1696. return fRet;
  1697. }
  1698. BOOL
  1699. ACTIVE_DEVICE::
  1700. AddConnection(
  1701. STI_CONN *pConnection
  1702. )
  1703. /*++
  1704. Routine Description:
  1705. This function is called when new connection is requested from client to active device
  1706. Arguments:
  1707. --*/
  1708. {
  1709. TAKE_ACTIVE_DEVICE t(this);
  1710. STI_CONN *pExistingConnection = NULL;
  1711. BOOL fRet = FALSE;
  1712. pExistingConnection = FindMyConnection((HANDLE)pConnection->QueryID());
  1713. if (!pExistingConnection) {
  1714. //
  1715. // Check if we are not in data mode
  1716. //
  1717. if (pConnection->QueryOpenMode() & STI_DEVICE_CREATE_DATA) {
  1718. if (QueryFlags() & STIMON_AD_FLAG_OPENED_FOR_DATA) {
  1719. DBG_TRC(("Device(%x) is being opened second time in data mode",this));
  1720. ::SetLastError(ERROR_ACCESS_DENIED);
  1721. return FALSE;
  1722. }
  1723. SetFlags(QueryFlags() | STIMON_AD_FLAG_OPENED_FOR_DATA);
  1724. }
  1725. //
  1726. // Add connection object to connected list
  1727. //
  1728. InsertHeadList(&m_ConnectionListHead,&pConnection->m_DeviceListEntry);
  1729. DBG_TRC(("Device(%S) added connection (%X) ", GetDeviceID(), pConnection));
  1730. pConnection->DumpObject();
  1731. //
  1732. // Set device object flags
  1733. //
  1734. SetFlags(QueryFlags() & ~STIMON_AD_FLAG_LAUNCH_PENDING);
  1735. //
  1736. // If notifications allowed, explicitly enable them.
  1737. //
  1738. if ( QueryFlags() & STIMON_AD_FLAG_NOTIFY_ENABLED ) {
  1739. StartRunningNotifications();
  1740. }
  1741. fRet = TRUE;
  1742. }
  1743. else {
  1744. // Already present - something is wrong
  1745. ASSERT(("Device adding connection which is already there ", 0));
  1746. }
  1747. return fRet;
  1748. }
  1749. STI_CONN *
  1750. ACTIVE_DEVICE::
  1751. FindMyConnection(
  1752. HANDLE hConnection
  1753. )
  1754. /*++
  1755. Routine Description:
  1756. This function is used to locate connection object from connection handle
  1757. Arguments:
  1758. --*/
  1759. {
  1760. LIST_ENTRY *pentry;
  1761. LIST_ENTRY *pentryNext;
  1762. STI_CONN *pConnection = NULL;
  1763. HANDLE hInternalHandle = hConnection;
  1764. for ( pentry = m_ConnectionListHead.Flink;
  1765. pentry != &m_ConnectionListHead;
  1766. pentry = pentryNext ) {
  1767. pentryNext = pentry->Flink;
  1768. pConnection = CONTAINING_RECORD( pentry, STI_CONN,m_DeviceListEntry );
  1769. if (hInternalHandle == pConnection->QueryID()) {
  1770. return pConnection;
  1771. }
  1772. }
  1773. return NULL;
  1774. }
  1775. BOOL
  1776. ACTIVE_DEVICE::
  1777. FillEventFromUSD(
  1778. STINOTIFY *psNotify
  1779. )
  1780. /*++
  1781. Routine Description:
  1782. This function is called after USD signalled presence of hardware event and if successful it
  1783. returns event descriptor filled with information about event
  1784. Arguments:
  1785. --*/
  1786. {
  1787. HRESULT hres;
  1788. psNotify->dwSize = sizeof STINOTIFY;
  1789. psNotify->guidNotificationCode = GUID_NULL;
  1790. if (!m_DrvWrapper.IsDriverLoaded()) {
  1791. ASSERT(("FillEventFromUSD couldn't find direct driver interface", 0));
  1792. return FALSE;
  1793. }
  1794. hres = m_DrvWrapper.STI_GetNotificationData(psNotify);
  1795. return SUCCEEDED(hres) ? TRUE : FALSE;
  1796. }
  1797. BOOL
  1798. ACTIVE_DEVICE::
  1799. SetHandleForUSD(
  1800. HANDLE hEvent
  1801. )
  1802. /*++
  1803. Routine Description:
  1804. This function is called to pass event handle to USD for later signalling in case of
  1805. hardware event
  1806. Arguments:
  1807. pContext - pointer to device object
  1808. --*/
  1809. {
  1810. HRESULT hres = E_FAIL;
  1811. if (!IsValid() || !m_DrvWrapper.IsDriverLoaded()) {
  1812. ASSERT(("SetHandleForUSD couldn't find direct driver interface", 0));
  1813. return FALSE;
  1814. }
  1815. //
  1816. // Ask device object for USD interface. Should get it because sti device aggregates
  1817. // USD
  1818. //
  1819. hres = m_DrvWrapper.STI_SetNotificationHandle(hEvent);
  1820. if (hres == STIERR_UNSUPPORTED) {
  1821. hres = S_OK;
  1822. }
  1823. return SUCCEEDED(hres) ? TRUE : FALSE;
  1824. }
  1825. BOOL
  1826. ACTIVE_DEVICE::
  1827. IsEventOnArrivalNeeded(
  1828. VOID
  1829. )
  1830. /*++
  1831. Routine Description:
  1832. Returns TRUE if this device needs to generate event on arrival.
  1833. Conditions are:
  1834. - Device successully initialized
  1835. - Device capabilities ( static or dynamic) include appropriate bit
  1836. - Device is capable and enabled for event generation
  1837. Arguments:
  1838. None
  1839. --*/
  1840. {
  1841. HRESULT hres;
  1842. STI_USD_CAPS sUsdCaps;
  1843. BOOL fRet;
  1844. fRet = FALSE;
  1845. ZeroMemory(&sUsdCaps,sizeof(sUsdCaps));
  1846. hres = m_DrvWrapper.STI_GetCapabilities(&sUsdCaps);
  1847. if (SUCCEEDED(hres)) {
  1848. if ( (m_dwFlags & STIMON_AD_FLAG_NOTIFY_ENABLED ) &&
  1849. (m_dwFlags & STIMON_AD_FLAG_NOTIFY_CAPABLE ) ) {
  1850. //
  1851. // Check that either static or dynamic capabilities mask conatins needed bit
  1852. //
  1853. if ( (sUsdCaps.dwGenericCaps | m_DrvWrapper.getGenericCaps()) &
  1854. STI_GENCAP_GENERATE_ARRIVALEVENT
  1855. ) {
  1856. fRet = TRUE;
  1857. }
  1858. }
  1859. }
  1860. return fRet;
  1861. } //
  1862. BOOL
  1863. ACTIVE_DEVICE::
  1864. InitPnPNotifications(
  1865. HWND hwnd
  1866. )
  1867. /*++
  1868. Routine Description:
  1869. Assumes device object to be locked
  1870. Arguments:
  1871. None
  1872. --*/
  1873. {
  1874. BOOL fRet = FALSE;
  1875. #ifdef WINNT
  1876. //
  1877. // First, stop any existing PnP notifications
  1878. //
  1879. StopPnPNotifications();
  1880. WCHAR *wszInterfaceName = NULL;
  1881. DWORD dwError;
  1882. //
  1883. // Get interface name for out device
  1884. //
  1885. wszInterfaceName = g_pDevMan->AllocGetInterfaceNameFromDevInfo(m_DrvWrapper.getDevInfo());
  1886. if (wszInterfaceName) {
  1887. //
  1888. // Open handle on this interface
  1889. //
  1890. m_hDeviceInterface = ::CreateFileW(wszInterfaceName,
  1891. GENERIC_READ, // Access
  1892. 0, // Share mode
  1893. NULL, // Sec attributes
  1894. OPEN_EXISTING, // Disposition
  1895. 0, // Attributes
  1896. NULL // Template file
  1897. );
  1898. if (IS_VALID_HANDLE(m_hDeviceInterface)) {
  1899. //
  1900. // Register to receive PnP notifications on interface handle
  1901. //
  1902. DEV_BROADCAST_HDR *psh;
  1903. DEV_BROADCAST_HANDLE sNotificationFilter;
  1904. //
  1905. // Register to receive device notifications from PnP
  1906. //
  1907. psh = (DEV_BROADCAST_HDR *)&sNotificationFilter;
  1908. psh->dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  1909. psh->dbch_devicetype = DBT_DEVTYP_HANDLE;
  1910. psh->dbch_reserved = 0;
  1911. sNotificationFilter.dbch_handle = m_hDeviceInterface;
  1912. DBG_TRC(("Attempting to register with PnP for interface device handle"));
  1913. m_hDeviceNotificationSink = RegisterDeviceNotification(g_StiServiceStatusHandle,
  1914. (LPVOID)&sNotificationFilter,
  1915. DEVICE_NOTIFY_SERVICE_HANDLE);
  1916. dwError = GetLastError();
  1917. if( !m_hDeviceNotificationSink && (NOERROR != dwError)) {
  1918. m_hDeviceNotificationSink = NULL;
  1919. //
  1920. // Failed to create notification sink with PnP subsystem
  1921. //
  1922. DBG_ERR(("InitPnPNotifications: Attempt to register %S with PnP failed. Error:0x%X",
  1923. GetDeviceID(), ::GetLastError()));
  1924. } else {
  1925. fRet = TRUE;
  1926. }
  1927. }
  1928. else {
  1929. DBG_WRN(("InitPnPNotifications: Attempt to open device interface on (%ws) failed. Error:0x%X", GetDeviceID(), ::GetLastError()));
  1930. }
  1931. delete [] wszInterfaceName;
  1932. }
  1933. else {
  1934. DBG_WRN(("InitPnPNotifications: Lookup for device interface name on (%ws) failed. Error:0x%X", GetDeviceID(), ::GetLastError()));
  1935. }
  1936. #else
  1937. fRet = TRUE;
  1938. #endif
  1939. return fRet;
  1940. }
  1941. BOOL
  1942. ACTIVE_DEVICE::
  1943. IsRegisteredForDeviceRemoval(
  1944. VOID
  1945. )
  1946. {
  1947. //
  1948. // Check whether we registered for device notifications on this
  1949. // device's interface.
  1950. //
  1951. if (IsValidHANDLE(m_hDeviceNotificationSink)) {
  1952. return TRUE;
  1953. } else {
  1954. return FALSE;
  1955. }
  1956. }
  1957. BOOL
  1958. ACTIVE_DEVICE::
  1959. StopPnPNotifications(
  1960. VOID
  1961. )
  1962. /*++
  1963. Routine Description:
  1964. Assumes device object to be locked
  1965. Arguments:
  1966. None
  1967. --*/
  1968. {
  1969. #ifdef WINNT
  1970. //
  1971. // Unregister for PnP notifications on interface handle
  1972. //
  1973. if (IS_VALID_HANDLE(m_hDeviceNotificationSink)) {
  1974. ::UnregisterDeviceNotification(m_hDeviceNotificationSink);
  1975. m_hDeviceNotificationSink = NULL;
  1976. }
  1977. else {
  1978. DBG_TRC(("StopPnPNotifications: Device sink is invalid "));
  1979. }
  1980. //
  1981. // Close interface handle
  1982. //
  1983. if (IS_VALID_HANDLE(m_hDeviceInterface)) {
  1984. ::CloseHandle(m_hDeviceInterface);
  1985. m_hDeviceInterface = NULL;
  1986. }
  1987. else {
  1988. DBG_TRC(("StopPnPNotifications: Device interface handle is invalid"));
  1989. }
  1990. #endif
  1991. return TRUE;
  1992. }
  1993. BOOL
  1994. ACTIVE_DEVICE::
  1995. UpdateDeviceInformation(
  1996. VOID
  1997. )
  1998. /*++
  1999. Routine Description:
  2000. Updates the cached device information struct.
  2001. Arguments:
  2002. None
  2003. --*/
  2004. {
  2005. USES_CONVERSION;
  2006. HRESULT hres;
  2007. BOOL bRet = TRUE;
  2008. /* TBD:
  2009. if (!m_strStiDeviceName) {
  2010. DBG_ERR(("Error updating device info cache, device name is invalid"));
  2011. bRet = FALSE;
  2012. }
  2013. //
  2014. // Update the cached WIA_DEVICE_INFORMATION in the ACTICVE_DEVICE
  2015. //
  2016. if (bRet) {
  2017. PSTI_WIA_DEVICE_INFORMATION pWiaDevInfo;
  2018. hres = StiPrivateGetDeviceInfoHelperW((LPWSTR)T2CW(m_strStiDeviceName),(LPVOID *)&pWiaDevInfo );
  2019. if (!SUCCEEDED(hres) || !pWiaDevInfo) {
  2020. DBG_ERR(("Loading device (%ws) . Failed to get WIA information from STI. HResult=(%x)", m_strStiDeviceName, hres));
  2021. m_pWiaDeviceInformation = NULL;
  2022. bRet = FALSE;
  2023. } else {
  2024. m_pWiaDeviceInformation = pWiaDevInfo;
  2025. }
  2026. }
  2027. */
  2028. return bRet;
  2029. }
  2030. //
  2031. // Functions
  2032. //
  2033. //
  2034. VOID
  2035. WINAPI
  2036. ScheduleDeviceCallback(
  2037. VOID * pContext
  2038. )
  2039. /*++
  2040. Routine Description:
  2041. This function is the callback called by the scheduler thread after the
  2042. specified timeout period has elapsed.
  2043. Arguments:
  2044. pContext - pointer to device object
  2045. --*/
  2046. {
  2047. ACTIVE_DEVICE* pActiveDevice = (ACTIVE_DEVICE* )pContext;
  2048. ASSERT(("Callback invoked with null context", pContext));
  2049. if (pContext) {
  2050. //
  2051. // No need to take the active device here - the caller
  2052. // has already AddRef'd, and will Release when
  2053. // we're done. A dealock will occur unless we first
  2054. // take the global list CS, then the ACTIVE_DEVICE's
  2055. // CS...
  2056. //TAKE_ACTIVE_DEVICE t(pActiveDevice);
  2057. pActiveDevice->AddRef();
  2058. if (pActiveDevice->QueryFlags() & STIMON_AD_FLAG_POLLING) {
  2059. pActiveDevice->DoPoll();
  2060. }
  2061. else {
  2062. //
  2063. // Async event arrived - call methods
  2064. //
  2065. pActiveDevice->DoAsyncEvent();
  2066. }
  2067. pActiveDevice->Release();
  2068. }
  2069. }
  2070. VOID
  2071. WINAPI
  2072. DelayedDeviceInitCallback(
  2073. VOID * pContext
  2074. )
  2075. /*++
  2076. Routine Description:
  2077. This function is the callback called by the scheduler thread after the
  2078. device is first created to enable notifications.
  2079. Arguments:
  2080. pContext - pointer to device object
  2081. --*/
  2082. {
  2083. ACTIVE_DEVICE* pActiveDevice = (ACTIVE_DEVICE* )pContext;
  2084. ASSERT(("Callback invoked with null context", pContext));
  2085. if (pContext) {
  2086. TAKE_ACTIVE_DEVICE t(pActiveDevice);
  2087. pActiveDevice->m_dwDelayedOpCookie = 0;
  2088. if (pActiveDevice->IsValid()) {
  2089. //
  2090. // If there is nobody to receive notifications, don't really enable them
  2091. //
  2092. pActiveDevice->EnableDeviceNotifications();
  2093. #ifdef DO_INITIAL_RESET
  2094. // NOTE:
  2095. // Resetting the device is a good way of ensuring that the device
  2096. // starts off in a stable state. Unfortunately, this can be bad
  2097. // because 1) It is often time consuming
  2098. // 2) We may wake up devices unecessarily (e.g. most
  2099. // serial cameras).
  2100. //
  2101. // Device reset is not necessary for WIA drivers, since it is a
  2102. // requirement that they are always in a stable state, so we
  2103. // could compromise and reset only non-WIA devices.
  2104. //
  2105. hres = g_pStiLockMgr->RequestLock(pActiveDevice, STIMON_AD_DEFAULT_WAIT_LOCK);
  2106. if (SUCCEEDED(hres) ) {
  2107. pActiveDevice->m_DrvWrapper.STI_DeviceReset();
  2108. g_pStiLockMgr->RequestUnLock(pActiveDevice);
  2109. }
  2110. #endif
  2111. //
  2112. // As we are done with delayed initialization - clear the flag
  2113. //
  2114. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() & ~STIMON_AD_FLAG_DELAYED_INIT);
  2115. } /* endif IsValid */
  2116. else {
  2117. ASSERT(("DelayedDeviceInitCallback received invalid device object", 0));
  2118. }
  2119. }
  2120. }
  2121. VOID
  2122. WINAPI
  2123. AutoLaunchThread(
  2124. LPVOID lpParameter
  2125. )
  2126. /*++
  2127. Routine Description:
  2128. Worker routine for autolaunching thread.
  2129. Validates parameter and invokes proper method
  2130. Arguments:
  2131. None.
  2132. Return Value:
  2133. None.
  2134. --*/
  2135. {
  2136. PAUTO_LAUNCH_PARAM_CONTAINER pAutoContainer = static_cast<AUTO_LAUNCH_PARAM_CONTAINER *>(lpParameter);
  2137. if (!lpParameter || !pAutoContainer->pActiveDevice) {
  2138. ASSERT(("No parameter passed to launch thread", 0));
  2139. return;
  2140. }
  2141. ACTIVE_DEVICE *pActiveDevice = pAutoContainer->pActiveDevice;
  2142. pActiveDevice->AutoLaunch(pAutoContainer);
  2143. pActiveDevice->Release();
  2144. delete pAutoContainer;
  2145. }
  2146. //
  2147. // Adding new device to the active list.
  2148. // This function is not reentrant with adding/removal
  2149. //
  2150. BOOL
  2151. AddDeviceByName(
  2152. LPCTSTR pszDeviceName,
  2153. BOOL fPnPInitiated // = FALSE
  2154. )
  2155. {
  2156. /*
  2157. USES_CONVERSION;
  2158. LIST_ENTRY * pentry;
  2159. LIST_ENTRY * pentryNext;
  2160. ACTIVE_DEVICE* pActiveDevice = NULL;
  2161. BOOL fAlreadyExists = FALSE;
  2162. DBG_TRC(("Requested arrival of device (%ws) ",pszDeviceName));
  2163. // BEGIN PROTECTED CODE
  2164. {
  2165. TAKE_CRIT_SECT t(g_DeviceListSync);
  2166. for ( pentry = g_DeviceListHead.Flink;
  2167. pentry != &g_DeviceListHead;
  2168. pentry = pentryNext ) {
  2169. pentryNext = pentry->Flink;
  2170. pActiveDevice = CONTAINING_RECORD( pentry,ACTIVE_DEVICE ,m_ListEntry );
  2171. if ( pActiveDevice->m_dwSignature != ADEV_SIGNATURE ) {
  2172. ASSERT(("Invalid device signature", 0));
  2173. break;
  2174. }
  2175. if (!::lstrcmpi(pszDeviceName,(LPCTSTR)pActiveDevice->m_strStiDeviceName)) {
  2176. fAlreadyExists = TRUE;
  2177. break;
  2178. }
  2179. }
  2180. if (!fAlreadyExists) {
  2181. pActiveDevice = new ACTIVE_DEVICE(pszDeviceName);
  2182. if (!pActiveDevice || !pActiveDevice->IsValid()) {
  2183. DBG_ERR(("Creating device failed "));
  2184. if (pActiveDevice) {
  2185. delete pActiveDevice;
  2186. }
  2187. return FALSE;
  2188. }
  2189. // Finally insert new object into the list
  2190. InsertTailList(&g_DeviceListHead,&pActiveDevice->m_ListEntry);
  2191. }
  2192. else {
  2193. STIMONWPRINTF(TEXT("Request to add new device found device is already maintained"));
  2194. return FALSE;
  2195. }
  2196. }
  2197. // END PROTECTED CODE
  2198. //
  2199. // If new device appeared - initialize PnP interface notifications
  2200. //
  2201. if ( pActiveDevice ) {
  2202. TAKE_ACTIVE_DEVICE t(pActiveDevice);
  2203. pActiveDevice->InitPnPNotifications(g_hStiServiceWindow);
  2204. }
  2205. //
  2206. // If this device or it's USD requests auto-generating a launch event on arrival
  2207. // schedule it here
  2208. //
  2209. // NOTE : This will also happen for WIA devices. Generally, this is what we want,
  2210. // when a new device arrives we should generate the event, since devices such as
  2211. // serial cameras wont generate this on their own.
  2212. //
  2213. //
  2214. // For STI devices we must check whether we need to generate the
  2215. // event. For WIA devices, we always want to, so it's not an issue.
  2216. //
  2217. BOOL bStiDeviceMustThrowEvent = (pActiveDevice->QueryFlags() & STIMON_AD_FLAG_NOTIFY_RUNNING)
  2218. && pActiveDevice->IsEventOnArrivalNeeded();
  2219. if (fPnPInitiated &&
  2220. pActiveDevice) {
  2221. TAKE_ACTIVE_DEVICE t(pActiveDevice);
  2222. STINOTIFY sNotify;
  2223. BOOL fRet;
  2224. //
  2225. // If this is a WIA device, then the event should be WIA_EVENT_DEVICE_CONNECTED.
  2226. // If this is an sti device, then it should be GUID_DeviceArrivedLaunch;
  2227. //
  2228. sNotify.dwSize = sizeof STINOTIFY;
  2229. if (pActiveDevice->m_pWiaDeviceInformation) {
  2230. sNotify.guidNotificationCode = WIA_EVENT_DEVICE_CONNECTED;
  2231. } else {
  2232. //
  2233. // Check whether this STI device should throw the event
  2234. //
  2235. if (!bStiDeviceMustThrowEvent) {
  2236. return TRUE;
  2237. }
  2238. sNotify.guidNotificationCode = GUID_DeviceArrivedLaunch;
  2239. }
  2240. DBG_TRC(("::AddDeviceByName, processing CONNECT event (STI or WIA) for %ws", T2W((TCHAR*)pszDeviceName)));
  2241. fRet = pActiveDevice->ProcessEvent(&sNotify);
  2242. if (!fRet) {
  2243. DBG_ERR(("Attempted to generate event on device(%ws) arrival and failed ", pszDeviceName));
  2244. }
  2245. }
  2246. */
  2247. return TRUE;
  2248. }
  2249. //
  2250. // Remove device identified by name
  2251. //
  2252. BOOL
  2253. RemoveDeviceByName(
  2254. LPTSTR pszDeviceName
  2255. )
  2256. {
  2257. USES_CONVERSION;
  2258. DBG_FN(RemoveDeviceByName);
  2259. LIST_ENTRY * pentry;
  2260. LIST_ENTRY * pentryNext;
  2261. ACTIVE_DEVICE* pActiveDevice = NULL;
  2262. BOOL fRet = FALSE;
  2263. DBG_TRC(("Requested removal of device (%ws)", pszDeviceName));
  2264. // BEGIN PROTECTED CODE
  2265. {
  2266. TAKE_CRIT_SECT t(g_DeviceListSync);
  2267. for ( pentry = g_DeviceListHead.Flink;
  2268. pentry != &g_DeviceListHead;
  2269. pentry = pentryNext ) {
  2270. pentryNext = pentry->Flink;
  2271. pActiveDevice = CONTAINING_RECORD( pentry,ACTIVE_DEVICE ,m_ListEntry );
  2272. if ( pActiveDevice->m_dwSignature != ADEV_SIGNATURE ) {
  2273. ASSERT(("Invalid device signature", 0));
  2274. fRet = FALSE;
  2275. break;
  2276. }
  2277. TCHAR *tszDeviceID = NULL;
  2278. tszDeviceID = W2T(pActiveDevice->GetDeviceID());
  2279. if (tszDeviceID) {
  2280. if (!::lstrcmp(pszDeviceName,tszDeviceID)) {
  2281. // Mark device as being removed
  2282. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() | STIMON_AD_FLAG_REMOVING);
  2283. //
  2284. // Remove any device notification callbacks
  2285. //
  2286. pActiveDevice->DisableDeviceNotifications();
  2287. //
  2288. // Stop PnP notifications immediately. This is important to free interface handle
  2289. //
  2290. pActiveDevice->StopPnPNotifications();
  2291. //
  2292. // Remove from the list
  2293. //
  2294. RemoveEntryList(&pActiveDevice->m_ListEntry);
  2295. pActiveDevice->m_ListEntry.Flink = pActiveDevice->m_ListEntry.Blink = NULL;
  2296. //
  2297. // Destroy device object if there are no references to it
  2298. //
  2299. ULONG ulRef = pActiveDevice->Release();
  2300. if (ulRef != 0) {
  2301. //
  2302. // The ACTIVE_DEVICE should have been destroyed i.e. it's
  2303. // ref count should have been 0. Someone is still holding
  2304. // an active count on it, which may indicate a problem
  2305. // since USD wont be unloaded until ACTIVE_DEVICE is
  2306. // destroyed...
  2307. //
  2308. // NOTE: If a transfer is occuring while deleteing, then
  2309. // the ACTIVE_DEVICE will not be destroyed here (since
  2310. // ref count > 0), but will be destroyed when the transfer
  2311. // finishes.
  2312. //
  2313. DBG_TRC(("* ACTIVE_DEVICE is removed from list but not yet destroyed!"));
  2314. //Break();
  2315. }
  2316. fRet = TRUE;
  2317. break;
  2318. }
  2319. }
  2320. }
  2321. }
  2322. // END PROTECTED CODE
  2323. return fRet;
  2324. }
  2325. //
  2326. // Mark device identified by name for removal
  2327. //
  2328. BOOL
  2329. MarkDeviceForRemoval(
  2330. LPTSTR pszDeviceName
  2331. )
  2332. {
  2333. USES_CONVERSION;
  2334. DBG_FN(MarkDeviceForRemoval);
  2335. LIST_ENTRY * pentry;
  2336. LIST_ENTRY * pentryNext;
  2337. ACTIVE_DEVICE* pActiveDevice = NULL;
  2338. BOOL fRet = FALSE;
  2339. DBG_TRC(("Requested marking of device (%S) for removal",pszDeviceName));
  2340. // BEGIN PROTECTED CODE
  2341. {
  2342. TAKE_CRIT_SECT t(g_DeviceListSync);
  2343. for ( pentry = g_DeviceListHead.Flink;
  2344. pentry != &g_DeviceListHead;
  2345. pentry = pentryNext ) {
  2346. pentryNext = pentry->Flink;
  2347. pActiveDevice = CONTAINING_RECORD( pentry,ACTIVE_DEVICE ,m_ListEntry );
  2348. if ( pActiveDevice->m_dwSignature != ADEV_SIGNATURE ) {
  2349. ASSERT(("Invalid device signature", 0));
  2350. fRet = FALSE;
  2351. break;
  2352. }
  2353. TCHAR *tszDeviceID = NULL;
  2354. tszDeviceID = W2T(pActiveDevice->GetDeviceID());
  2355. if (tszDeviceID) {
  2356. if (!::lstrcmp(pszDeviceName, tszDeviceID)) {
  2357. // Mark device as being removed
  2358. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() | STIMON_AD_FLAG_REMOVING);
  2359. fRet = TRUE;
  2360. break;
  2361. }
  2362. }
  2363. }
  2364. }
  2365. // END PROTECTED CODE
  2366. return fRet;
  2367. }
  2368. //
  2369. // Initialize/Terminate linked list
  2370. //
  2371. VOID
  2372. InitializeDeviceList(
  2373. VOID
  2374. )
  2375. {
  2376. InitializeListHead( &g_DeviceListHead );
  2377. InitializeListHead( &g_ConnectionListHead );
  2378. g_lTotalOpenedConnections = 0;
  2379. g_lTotalActiveDevices = 0;
  2380. g_fDeviceListInitialized = TRUE;
  2381. }
  2382. VOID
  2383. TerminateDeviceList(
  2384. VOID
  2385. )
  2386. {
  2387. LIST_ENTRY * pentry;
  2388. ACTIVE_DEVICE* pActiveDevice = NULL;
  2389. DBG_TRC(("Destroying list of active devices"));
  2390. if (!g_fDeviceListInitialized) {
  2391. return;
  2392. }
  2393. TAKE_CRIT_SECT t(g_DeviceListSync);
  2394. //
  2395. // Go through the list terminating devices
  2396. //
  2397. while (!IsListEmpty(&g_DeviceListHead)) {
  2398. pentry = g_DeviceListHead.Flink;
  2399. //
  2400. // Remove from the list ( reset list entry )
  2401. //
  2402. RemoveHeadList(&g_DeviceListHead);
  2403. InitializeListHead( pentry );
  2404. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  2405. // Destroy device object
  2406. // delete pActiveDevice;
  2407. pActiveDevice->Release();
  2408. }
  2409. g_fDeviceListInitialized = FALSE;
  2410. }
  2411. VOID
  2412. RefreshDeviceList(
  2413. WORD wCommand,
  2414. WORD wFlags
  2415. )
  2416. /*++
  2417. Routine Description:
  2418. Update device list. Invalidate if necessary
  2419. Arguments:
  2420. wCommand - update command code
  2421. wFlags - update flags
  2422. Return Value:
  2423. None
  2424. --*/
  2425. {
  2426. BOOL fOldState;
  2427. // TDB: Call CWiaDevMan::ReEnumerateDevices
  2428. /*
  2429. //
  2430. // Pause work item scheduler
  2431. //
  2432. fOldState = SchedulerSetPauseState(TRUE);
  2433. //
  2434. // Indicate that the device list refresh is not yet complete
  2435. //
  2436. ResetEvent(g_hDevListCompleteEvent);
  2437. //
  2438. // If needed, add devices , which might appear first.
  2439. //
  2440. if (wFlags & STIMON_MSG_REFRESH_NEW) {
  2441. //
  2442. // If request been made to purge removed devices - do it in 2 steps:
  2443. // - First, mark all devices currently active as inactive
  2444. // - Second, go through all devices from PnP and for each device either create new
  2445. // active device object ( if it does not exist yet), or mark existing one as active
  2446. // - Third , purge all device objects, marked as inactive from the list.
  2447. //
  2448. //
  2449. // NOTE: None of the parameters using LongToPtr are actually pointer values! They're
  2450. // actually wParams and lParams of Windows messages (equivalents).
  2451. //
  2452. if (wFlags & STIMON_MSG_PURGE_REMOVED) {
  2453. DBG_TRC(("Purging device list. Phase1: Marking all devices inactive "));
  2454. EnumerateActiveDevicesWithCallback(&RefreshExistingDevicesCallback,
  2455. (LPVOID)LongToPtr(MAKELONG(STIMON_MSG_REFRESH_SET_FLAG,STIMON_MSG_NOTIF_SET_INACTIVE)));
  2456. }
  2457. EnumerateStiDevicesWithCallback(&AddNewDevicesCallback, (LPVOID)LongToPtr(MAKELONG(0,wFlags)));
  2458. if (wFlags & STIMON_MSG_PURGE_REMOVED) {
  2459. DBG_TRC(("Purging device list. Phase2: Removing unconfirmed devices "));
  2460. EnumerateActiveDevicesWithCallback(&RefreshExistingDevicesCallback,
  2461. (LPVOID)LongToPtr(MAKELONG(STIMON_MSG_REFRESH_PURGE,0)));
  2462. }
  2463. }
  2464. //
  2465. // If requested, go through all known active devices and refresh their settings
  2466. //
  2467. if (wFlags & STIMON_MSG_REFRESH_EXISTING) {
  2468. EnumerateActiveDevicesWithCallback(&RefreshExistingDevicesCallback,(LPVOID)LongToPtr(MAKELONG(wCommand,wFlags)));
  2469. }
  2470. SetEvent(g_hDevListCompleteEvent);
  2471. // UnPause work item scheduler
  2472. SchedulerSetPauseState(fOldState);
  2473. */
  2474. }
  2475. //
  2476. // Set new value of interval for all polled devices
  2477. //
  2478. VOID
  2479. CALLBACK
  2480. ResetAllPollIntervalsCallback(
  2481. ACTIVE_DEVICE *pActiveDevice,
  2482. VOID *pContext
  2483. )
  2484. /*++
  2485. Routine Description:
  2486. Arguments:
  2487. Return Value:
  2488. TRUE , FALSE
  2489. --*/
  2490. {
  2491. ULONG ulContextLong = PtrToUlong(pContext);
  2492. TAKE_ACTIVE_DEVICE t(pActiveDevice);
  2493. //
  2494. // If device is polled - reset it's interval to new value
  2495. //
  2496. if(pActiveDevice->QueryFlags() & STIMON_AD_FLAG_POLLING) {
  2497. pActiveDevice->SetPollingInterval(ulContextLong);
  2498. DBG_TRC(("Polling interval is set to %d on device (%ws)",
  2499. pActiveDevice->QueryPollingInterval(),
  2500. pActiveDevice->GetDeviceID()));
  2501. }
  2502. }
  2503. BOOL
  2504. ResetAllPollIntervals(
  2505. UINT dwNewPollInterval
  2506. )
  2507. /*++
  2508. Routine Description:
  2509. Arguments:
  2510. Return Value:
  2511. TRUE , FALSE
  2512. --*/
  2513. {
  2514. EnumerateActiveDevicesWithCallback(&ResetAllPollIntervalsCallback,(LPVOID)LongToPtr(dwNewPollInterval));
  2515. return TRUE;
  2516. }
  2517. VOID
  2518. CALLBACK
  2519. DumpActiveDevicesCallback(
  2520. ACTIVE_DEVICE *pActiveDevice,
  2521. VOID *pContext
  2522. )
  2523. /*++
  2524. Routine Description:
  2525. Arguments:
  2526. Return Value:
  2527. TRUE , FALSE
  2528. --*/
  2529. {
  2530. STIMONWPRINTF(TEXT("Device:%ws DeviceId:%d Flags:%4x Poll interval:%d"),
  2531. pActiveDevice->GetDeviceID(),
  2532. pActiveDevice->m_lDeviceId,
  2533. pActiveDevice->QueryFlags(),
  2534. pActiveDevice->m_dwPollingInterval);
  2535. }
  2536. VOID
  2537. DebugDumpDeviceList(
  2538. VOID
  2539. )
  2540. /*++
  2541. Routine Description:
  2542. Arguments:
  2543. Return Value:
  2544. TRUE , FALSE
  2545. --*/
  2546. {
  2547. EnumerateActiveDevicesWithCallback(&DumpActiveDevicesCallback,NULL);
  2548. }
  2549. VOID
  2550. CALLBACK
  2551. PurgeDevicesCallback(
  2552. PSTI_DEVICE_INFORMATION pDevInfo,
  2553. VOID *pContext
  2554. )
  2555. /*++
  2556. Routine Description:
  2557. Callback routine to invoke when removing all devices
  2558. Arguments:
  2559. pDevInfo - pointer to device information block
  2560. Return Value:
  2561. None
  2562. --*/
  2563. {
  2564. USES_CONVERSION;
  2565. if (RemoveDeviceByName(W2T(pDevInfo->szDeviceInternalName))) {
  2566. STIMONWPRINTF(TEXT("Destroyed device object (%S)"),pDevInfo->szDeviceInternalName);
  2567. }
  2568. else {
  2569. STIMONWPRINTF(TEXT("Attempted destroying device object (%S), but failed"),pDevInfo->szDeviceInternalName);
  2570. }
  2571. }
  2572. VOID
  2573. DebugPurgeDeviceList(
  2574. VOID *pContext
  2575. )
  2576. /*++
  2577. Routine Description:
  2578. Unconditionally destroy active device list
  2579. Arguments:
  2580. Context to pass to callback
  2581. --*/
  2582. {
  2583. // Pause work item scheduler
  2584. SchedulerSetPauseState(TRUE);
  2585. // TBD: Find replacement
  2586. //EnumerateStiDevicesWithCallback(&PurgeDevicesCallback,pContext);
  2587. // UnPause work item scheduler
  2588. SchedulerSetPauseState(FALSE);
  2589. }
  2590. //
  2591. // Enumerators with callbacks
  2592. //
  2593. VOID
  2594. WINAPI
  2595. EnumerateStiDevicesWithCallback(
  2596. PFN_DEVINFO_CALLBACK pfn,
  2597. VOID *pContext
  2598. )
  2599. /*++
  2600. Routine Description:
  2601. Walk the list of installed devices, calling given routine for each device
  2602. Arguments:
  2603. pfn - Address of the callback
  2604. pContext- Pointer to context information to pass to callback
  2605. Return Value:
  2606. None
  2607. --*/
  2608. {
  2609. /* TDB: Find out who calls this and convert them over to CWiaDevMan
  2610. if (!g_fDeviceListInitialized) {
  2611. STIMONWPRINTF(TEXT("Device list not initialized"));
  2612. return;
  2613. }
  2614. if (!pfn) {
  2615. ASSERT(("Incorrect callback", 0));
  2616. return;
  2617. }
  2618. HRESULT hres;
  2619. PSTI_DEVICE_INFORMATION pDevInfo;
  2620. PVOID pBuffer;
  2621. UINT iDev;
  2622. DWORD dwItemsReturned;
  2623. //
  2624. // Enumerate STI devices
  2625. //
  2626. hres = g_pSti->GetDeviceList(0, // Type
  2627. FLAG_NO_LPTENUM, // Flags
  2628. &dwItemsReturned,
  2629. &pBuffer);
  2630. if (!SUCCEEDED(hres) || !pBuffer) {
  2631. DBG_ERR(("Enumeration call failed - abort. HRes=%x \n",hres));
  2632. goto Cleanup;
  2633. }
  2634. DBG_TRC(("EnumerateStiDevicesWithCallback, returned from GetList: counter=%d", dwItemsReturned));
  2635. pDevInfo = (PSTI_DEVICE_INFORMATION) pBuffer;
  2636. //
  2637. // Walk the device list and for each device add active object
  2638. //
  2639. for (iDev=0;
  2640. iDev<dwItemsReturned ;
  2641. iDev++, pDevInfo++) {
  2642. pfn(pDevInfo,pContext);
  2643. } // end_for
  2644. Cleanup:
  2645. if (pBuffer) {
  2646. LocalFree(pBuffer);
  2647. pBuffer = NULL;
  2648. }
  2649. */
  2650. }
  2651. VOID
  2652. WINAPI
  2653. EnumerateActiveDevicesWithCallback(
  2654. PFN_ACTIVEDEVICE_CALLBACK pfn,
  2655. VOID *pContext
  2656. )
  2657. /*++
  2658. Routine Description:
  2659. Walk the list of known active devices, calling given routine for each device
  2660. Arguments:
  2661. pfn - Address of the callback
  2662. pContext- Pointer to context information to pass to callback
  2663. Return Value:
  2664. None
  2665. --*/
  2666. {
  2667. if (!pfn) {
  2668. ASSERT(("Incorrect callback", 0));
  2669. return;
  2670. }
  2671. LIST_ENTRY * pentry;
  2672. LIST_ENTRY * pentryNext;
  2673. ACTIVE_DEVICE* pActiveDevice;
  2674. // BEGIN PROTECTED CODE
  2675. {
  2676. TAKE_CRIT_SECT t(g_DeviceListSync);
  2677. for ( pentry = g_DeviceListHead.Flink;
  2678. pentry != &g_DeviceListHead;
  2679. pentry = pentryNext ) {
  2680. pentryNext = pentry->Flink;
  2681. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  2682. if (!pActiveDevice->IsValid()) {
  2683. ASSERT(("Invalid device signature", 0));
  2684. break;
  2685. }
  2686. pfn(pActiveDevice,pContext);
  2687. }
  2688. }
  2689. // END PROTECTED CODE
  2690. }
  2691. VOID
  2692. CleanApplicationsListForEvent(
  2693. LPCTSTR pDeviceName,
  2694. PDEVICEEVENT pDeviceEvent,
  2695. LPCTSTR pAppName
  2696. )
  2697. /*++
  2698. Routine Description:
  2699. After it had been determined that application , associated with this event is not valid,
  2700. we want to make event function as wild card ( i.e. all eligibale apps are selected)
  2701. Arguments:
  2702. Return Value:
  2703. --*/
  2704. {
  2705. USES_CONVERSION;
  2706. //
  2707. // Build up reg path for event info
  2708. //
  2709. StiCString strRegPath;
  2710. strRegPath.CopyString((LPCTSTR)(IsPlatformNT() ? REGSTR_PATH_STIDEVICES_NT : REGSTR_PATH_STIDEVICES));
  2711. strRegPath+=TEXT("\\");
  2712. strRegPath+=pDeviceName;
  2713. RegEntry reEvent((LPCTSTR)strRegPath,HKEY_LOCAL_MACHINE);
  2714. if (reEvent.IsValid()) {
  2715. reEvent.MoveToSubKey(EVENTS);
  2716. reEvent.MoveToSubKey((LPCTSTR)pDeviceEvent->m_EventSubKey);
  2717. reEvent.SetValue(REGSTR_VAL_LAUNCH_APPS,TEXT("*"));
  2718. // Reset data in loaded event descriptor
  2719. pDeviceEvent->m_EventData.CopyString(TEXT("*"));
  2720. }
  2721. }
  2722. DWORD
  2723. GetNumRegisteredApps(
  2724. VOID
  2725. )
  2726. /*++
  2727. Routine Description:
  2728. Count number of currently registered applications
  2729. Arguments:
  2730. None
  2731. Return Value:
  2732. Number of registered apps
  2733. --*/
  2734. {
  2735. RegEntry re(REGSTR_PATH_REG_APPS,HKEY_LOCAL_MACHINE);
  2736. RegEnumValues regenum(&re);
  2737. DWORD dwCount = 0;
  2738. if (re.IsValid()) {
  2739. while (ERROR_SUCCESS == regenum.Next() ) {
  2740. #ifndef USE_QUERY_INFO
  2741. if ((regenum.GetType() == REG_SZ ) && !IS_EMPTY_STRING(regenum.GetName())) {
  2742. dwCount++;
  2743. }
  2744. }
  2745. #else
  2746. dwErrorReg = RegQueryInfoKey ( re.GetKey(), // Key
  2747. NULL, // Buffer for class string
  2748. NULL, // Size of class string buffer
  2749. NULL, // Reserved
  2750. NULL, // Number of subkeys
  2751. NULL, // Longest subkey name
  2752. NULL, // Longest class string
  2753. &dwCount, // Number of value entries
  2754. NULL, // Longest value name
  2755. NULL, // Longest value data
  2756. NULL, // Security descriptor
  2757. NULL ); // Last write time
  2758. #endif
  2759. }
  2760. return dwCount;
  2761. }
  2762. HRESULT
  2763. WiaGetDeviceInfo(
  2764. LPCWSTR pwszDeviceName,
  2765. DWORD *pdwDeviceType,
  2766. BSTR *pbstrDeviceDescription,
  2767. ACTIVE_DEVICE **ppDevice)
  2768. /*++
  2769. Routine Description:
  2770. Retrieve device information of device
  2771. Arguments:
  2772. Return Value:
  2773. status
  2774. --*/
  2775. {
  2776. USES_CONVERSION;
  2777. HRESULT hr = S_FALSE;
  2778. ACTIVE_DEVICE *pActiveDevice;
  2779. if (!ppDevice) {
  2780. return E_POINTER;
  2781. }
  2782. pActiveDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, (WCHAR*)pwszDeviceName);
  2783. if (pActiveDevice) {
  2784. //
  2785. // If that device is WIA capable
  2786. //
  2787. if (pActiveDevice->m_DrvWrapper.IsWiaDevice()) {
  2788. *ppDevice = pActiveDevice;
  2789. //
  2790. // Copy necessary information
  2791. //
  2792. DEVICE_INFO *pDeviceInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
  2793. if (pDeviceInfo) {
  2794. *pbstrDeviceDescription =
  2795. SysAllocString(
  2796. pDeviceInfo->wszDeviceDescription);
  2797. if (*pbstrDeviceDescription) {
  2798. *pdwDeviceType =
  2799. pDeviceInfo->DeviceType;
  2800. hr = S_OK;
  2801. }
  2802. }
  2803. }
  2804. }
  2805. if (hr != S_OK) {
  2806. *pdwDeviceType = 0;
  2807. *pbstrDeviceDescription = NULL;
  2808. *ppDevice = NULL;
  2809. }
  2810. return (hr);
  2811. }
  2812. HRESULT
  2813. WiaUpdateDeviceInfo()
  2814. /*++
  2815. Routine Description:
  2816. Refreshes the cached STI_WIA_DEVICE_INFORMATION in each device.
  2817. Arguments:
  2818. Return Value:
  2819. status
  2820. --*/
  2821. {
  2822. RefreshDeviceList(STIMON_MSG_REFRESH_DEV_INFO, STIMON_MSG_REFRESH_EXISTING);
  2823. return S_OK;
  2824. }