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.

3337 lines
114 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 2000
  4. *
  5. * TITLE: wiadevman.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ByronC
  10. *
  11. * DATE: 6 Nov, 2000
  12. *
  13. * DESCRIPTION:
  14. * Declarations and definitions for the WIA device manager class.
  15. * It controls the enumeration of devices, the internal device list, adding
  16. * removing of devices from this list (PnP initiated) and implements the
  17. * IWiaDevMgr interface.
  18. *
  19. *******************************************************************************/
  20. #include "precomp.h"
  21. #include "stiexe.h"
  22. #include "enum.h"
  23. #include "shpriv.h"
  24. #include "devmgr.h"
  25. #include "wiaevntp.h"
  26. //
  27. // NOTE: For Automated testing of FS devices, the volume devices need to
  28. // be visible from normal WIA enumeration and not just Autoplay.
  29. //
  30. // Uncomment the "#define PRIVATE_FOR_TEST"
  31. // This will enable ALL mass storage devices to show up as normal
  32. // WIA devices (i.e. accessible by all WIA apps, Shell etc.). That
  33. // includes your floppy drives, CD-ROMs, ZIP and so on.
  34. //
  35. // #define PRIVATE_FOR_TEST
  36. //
  37. // Helper functions
  38. //
  39. #define DEV_STATE_MASK 0xFFFFFFF8
  40. /**************************************************************************\
  41. * ::IsCorrectVolumeType
  42. *
  43. * This function checks whether the given volume is one that WIA will
  44. * accept as a possible candidate for the FS driver. We only
  45. * allow:
  46. * Removable drives
  47. * File systems that don't enforce security
  48. *
  49. * Arguments:
  50. *
  51. * wszMountPoint - The volume mount point
  52. *
  53. * Return Value:
  54. *
  55. * DeviceState
  56. *
  57. * History:
  58. *
  59. * 11/06/2000 Original Version
  60. *
  61. \**************************************************************************/
  62. BOOL IsCorrectVolumeType(
  63. LPWSTR wszMountPoint)
  64. {
  65. BOOL bValid = FALSE;
  66. DWORD dwFSFlags = 0;
  67. //
  68. // Do parameter validation
  69. //
  70. if (wszMountPoint) {
  71. UINT uDriveType = GetDriveTypeW(wszMountPoint);
  72. //
  73. // Check whether this is a fixed drive. We don't allow fixed drives.
  74. // Note that we don't worry about network drives because our
  75. // volume enumerator only enumerates local volumes.
  76. //
  77. if (uDriveType != DRIVE_FIXED) {
  78. //
  79. // Skip floppy drives
  80. //
  81. if ((towupper(wszMountPoint[0]) != L'A') && (towupper(wszMountPoint[0]) != L'B')) {
  82. //
  83. // Check whether file system is securable...
  84. //
  85. if (GetVolumeInformationW(wszMountPoint,
  86. NULL,
  87. 0,
  88. NULL,
  89. NULL,
  90. &dwFSFlags,
  91. NULL,
  92. 0))
  93. {
  94. if (!(dwFSFlags & FS_PERSISTENT_ACLS)) {
  95. bValid = TRUE;
  96. }
  97. }
  98. }
  99. }
  100. } else {
  101. ASSERT(("NULL wszMountPoint parameter - this should never happen!", wszMountPoint));
  102. }
  103. return bValid;
  104. }
  105. /**************************************************************************\
  106. * ::MapCMStatusToDeviceState
  107. *
  108. * This function translates status and problem number information returned
  109. * from CM_Get_DevNode_STatus to our internal device state flags. The
  110. * status of the dev node tells us whether the device is active or disabled
  111. * etc.
  112. *
  113. * Arguments:
  114. *
  115. * dwOldDevState - The previous device state. This contains other
  116. * bits we wamt to carry over. Currently, this
  117. * is only the DEV_STATE_CON_EVENT_WAS_THROWN
  118. * bit.
  119. * ulStatus - Status from CM_Get_DevNode_Status
  120. * ulProblemNumber - Problem from CM_Get_DevNode_Status
  121. *
  122. * Return Value:
  123. *
  124. * DeviceState
  125. *
  126. * History:
  127. *
  128. * 11/06/2000 Original Version
  129. *
  130. \**************************************************************************/
  131. DWORD MapCMStatusToDeviceState(
  132. DWORD dwOldDevState,
  133. ULONG ulStatus,
  134. ULONG ulProblemNumber)
  135. {
  136. //
  137. // Clear the lower 3 bits
  138. //
  139. DWORD dwDevState = dwOldDevState & DEV_STATE_MASK;
  140. if (ulStatus & DN_STARTED) {
  141. dwDevState |= DEV_STATE_ACTIVE;
  142. } else if (ulStatus & DN_HAS_PROBLEM) {
  143. if (CM_PROB_DISABLED) {
  144. dwDevState |= DEV_STATE_DISABLED;
  145. }
  146. if (CM_PROB_HARDWARE_DISABLED) {
  147. dwDevState |= DEV_STATE_DISABLED;
  148. }
  149. if (CM_PROB_WILL_BE_REMOVED) {
  150. dwDevState |= DEV_STATE_REMOVED;
  151. }
  152. }
  153. return dwDevState;
  154. }
  155. /**************************************************************************\
  156. * ::MapMediaStatusToDeviceState
  157. *
  158. * This function translates media status to our device internal state.
  159. *
  160. * Arguments:
  161. *
  162. * dwMediaStatus - Media status returned from Shell volume enumeration.
  163. *
  164. * Return Value:
  165. *
  166. * DeviceState
  167. *
  168. * History:
  169. *
  170. * 11/06/2000 Original Version
  171. *
  172. \**************************************************************************/
  173. DWORD MapMediaStatusToDeviceState(
  174. DWORD dwMediaStatus
  175. )
  176. {
  177. DWORD dwDevState = 0;
  178. if (dwMediaStatus & HWDMS_PRESENT) {
  179. dwDevState |= DEV_STATE_ACTIVE;
  180. }
  181. return dwDevState;
  182. }
  183. //
  184. // CWiaDevMan Methods
  185. //
  186. /**************************************************************************\
  187. * CWiaDevMan::CWiaDevMan
  188. *
  189. * Constructor
  190. *
  191. * Arguments:
  192. *
  193. * None
  194. *
  195. * Return Value:
  196. *
  197. * None
  198. *
  199. * History:
  200. *
  201. * 11/06/2000 Original Version
  202. *
  203. \**************************************************************************/
  204. CWiaDevMan::CWiaDevMan()
  205. {
  206. m_DeviceInfoSet = NULL;
  207. m_bMakeVolumesVisible = FALSE;
  208. m_bVolumesEnabled = TRUE;
  209. m_dwHWCookie = 0;
  210. }
  211. /**************************************************************************\
  212. * CWiaDevMan::~CWiaDevMan
  213. *
  214. * Destructor - kills the device list and destroys our infoset
  215. *
  216. * Arguments:
  217. *
  218. * None
  219. *
  220. * Return Value:
  221. *
  222. * None
  223. *
  224. * History:
  225. *
  226. * 11/06/2000 Original Version
  227. *
  228. \**************************************************************************/
  229. CWiaDevMan::~CWiaDevMan()
  230. {
  231. // Destroy all our device objects
  232. DestroyDeviceList();
  233. // Destroy our device infoset
  234. DestroyInfoSet();
  235. if (m_dwHWCookie) {
  236. //
  237. // Unregister for notifications
  238. //
  239. HRESULT hr = S_OK;
  240. IHardwareDevices *pihwdevs = NULL;
  241. hr = CoCreateInstance(CLSID_HardwareDevices,
  242. NULL,
  243. CLSCTX_LOCAL_SERVER | CLSCTX_NO_FAILURE_LOG,
  244. IID_IHardwareDevices,
  245. (VOID**)&pihwdevs);
  246. if (SUCCEEDED(hr)) {
  247. pihwdevs->Unadvise(m_dwHWCookie);
  248. m_dwHWCookie = 0;
  249. pihwdevs->Release();
  250. } else {
  251. DBG_WRN(("CWiaDevMan::~CWiaDevMan, CoCreateInstance, looking for Shell interface IHardwareDevices failed"));
  252. }
  253. }
  254. }
  255. /**************************************************************************\
  256. * CWiaDevMan::Initialize
  257. *
  258. * This method initializes the device manager object. It does not enumerate
  259. * any devices - ReEnumerateDevices needs to be called to populate our
  260. * device list.
  261. *
  262. * Arguments:
  263. *
  264. * dwCallbackThreadId - This specifies the id of the thread on which we
  265. * will receive volume notifications. Notice
  266. * that these callbacks are done via APCs, so this
  267. * ThreadId must not change, or we should reregister
  268. * with the new ThreadId.
  269. *
  270. * Return Value:
  271. *
  272. * Status
  273. *
  274. * History:
  275. *
  276. * 11/06/2000 Original Version
  277. *
  278. \**************************************************************************/
  279. HRESULT CWiaDevMan::Initialize()
  280. {
  281. HRESULT hr = S_OK;
  282. IHardwareDevices *pihwdevs = NULL;
  283. //
  284. // Initialize the device list head
  285. //
  286. InitializeListHead(&m_leDeviceListHead);
  287. //
  288. // Check that our critical section was initialized correctly
  289. //
  290. if (!m_csDevList.IsInitialized()) {
  291. DBG_ERR(("CWiaDevMan::Initialize, Critical section could not be initialized"));
  292. return E_UNEXPECTED;
  293. }
  294. //
  295. // Check our relevant registry settings
  296. //
  297. GetRegistrySettings();
  298. if (VolumesAreEnabled()) {
  299. /* This code has been removed for this release. It would be used
  300. to enable scenarios based on Mass Storage Class cameras behaving
  301. like normal WIA devices, specifically with us being able to
  302. throw "Connect" and "Disconnect" events.
  303. This may be re-enabled for the next release. When it does, we must
  304. be sure to revisit our APC notification handler: CWiaDevMan::ShellHWEventAPCProc.
  305. It should be re-written not to make any COM calls, else we'll hit a problem when
  306. multiple APCs are queued, as soon as we make a COM invocation, we enter a wait
  307. state, which causes the next APC request to execute. This leads to "nested"
  308. COM calls, which is not supported by the OS.
  309. hr = CoCreateInstance(CLSID_HardwareDevices,
  310. NULL,
  311. CLSCTX_LOCAL_SERVER | CLSCTX_NO_FAILURE_LOG,
  312. IID_IHardwareDevices,
  313. (VOID**)&pihwdevs);
  314. if (SUCCEEDED(hr)) {
  315. HANDLE hPseudoThread = GetCurrentThread(); // Note that this is a pseudo handle and need not be closed
  316. HANDLE hThread = NULL; // IHardwareDevices will close this handle when it is done
  317. if (DuplicateHandle(GetCurrentProcess(),
  318. hPseudoThread,
  319. GetCurrentProcess(),
  320. &hThread,
  321. DUPLICATE_SAME_ACCESS,
  322. FALSE,
  323. 0)) {
  324. //
  325. // Register this object for Volume notifications.
  326. //
  327. hr = pihwdevs->Advise(GetCurrentProcessId(),
  328. (ULONG_PTR)hThread,
  329. (ULONG_PTR)CWiaDevMan::ShellHWEventAPCProc,
  330. &m_dwHWCookie);
  331. } else {
  332. DBG_WRN(("CWiaDevMan::Initialize, DuplicateHandle failed, could not register for Volume Notifications"));
  333. }
  334. pihwdevs->Release();
  335. } else {
  336. DBG_WRN(("CWiaDevMan::Initialize, CoCreateInstance on CLSID_HardwareDevices failed, could not register for Volume Notifications"));
  337. }
  338. */
  339. }
  340. //
  341. // Create our infoset. Note that we overwrite hr here, since if we cannot
  342. // see volumes, it is not fatal to us.
  343. //
  344. hr = CreateInfoSet();
  345. return hr;
  346. }
  347. /**************************************************************************\
  348. * CWiaDevMan::GetRegistrySettings
  349. *
  350. * This method reads certain registry entries related to the WiaDevMan
  351. * operation. Currently, we're looking for:
  352. *
  353. * EnableVolumeDevices - Indicates whether we enable volumes. We
  354. * assume they're enabled unless it's registry
  355. * value is specifically 0.
  356. * MakeVolumeDevicesVisible - Indicates whether volume device should be
  357. * included in normal device enumeration. This
  358. * makes them visible to the outside world by
  359. * default.
  360. *
  361. * Arguments:
  362. *
  363. * None
  364. *
  365. * Return Value:
  366. *
  367. * None
  368. *
  369. * History:
  370. *
  371. * 01/27/2001 Original Version
  372. *
  373. \**************************************************************************/
  374. VOID CWiaDevMan::GetRegistrySettings()
  375. {
  376. HRESULT hr = S_OK;
  377. DWORD dwVal = 0;
  378. DWORD dwRet = 0;
  379. HKEY hKey = NULL;
  380. //
  381. // Open the registry in the right place
  382. //
  383. dwRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  384. REGSTR_PATH_STICONTROL_W,
  385. 0,
  386. 0,
  387. REG_OPTION_NON_VOLATILE,
  388. KEY_READ,
  389. NULL,
  390. &hKey,
  391. NULL);
  392. if (dwRet == ERROR_SUCCESS && IsValidHANDLE(hKey)) {
  393. //
  394. // Read "EnableVolumeDevices"
  395. //
  396. hr = ReadRegistryDWORD(hKey,
  397. REGSTR_VAL_ENABLE_VOLUMES_W,
  398. &dwVal);
  399. if ((hr == S_OK) && (dwVal == 0)) {
  400. //
  401. // Disable volume device
  402. //
  403. m_bVolumesEnabled = FALSE;
  404. DBG_TRC(("CWiaDevMan::GetRegistrySettings, volume devices disabled"));
  405. } else {
  406. //
  407. // Enable volume devices
  408. //
  409. m_bVolumesEnabled = TRUE;
  410. DBG_TRC(("CWiaDevMan::GetRegistrySettings, volume devices Enabled"));
  411. }
  412. dwVal = 0;
  413. #ifdef PRIVATE_FOR_TEST
  414. //
  415. // Read "MakeVolumeDevicesVisible"
  416. //
  417. hr = ReadRegistryDWORD(hKey,
  418. REGSTR_VAL_MAKE_VOLUMES_VISIBLE_W,
  419. &dwVal);
  420. #endif
  421. if (dwVal == 0) {
  422. //
  423. // Make volume devices invisible from normal enumeration
  424. //
  425. m_bMakeVolumesVisible = FALSE;
  426. DBG_TRC(("CWiaDevMan::GetRegistrySettings, volume devices invisible by default"));
  427. } else {
  428. //
  429. // Make volume devices visible in normal enumeration
  430. //
  431. m_bMakeVolumesVisible = TRUE;
  432. DBG_TRC(("CWiaDevMan::GetRegistrySettings, volume devices now visible by default"));
  433. }
  434. RegCloseKey(hKey);
  435. }
  436. }
  437. /**************************************************************************\
  438. * CWiaDevMan::ReEnumerateDevices
  439. *
  440. * This method enumerates devices (both real WIA and volumes). Flags
  441. * specify whether we should do a refresh or throw events.
  442. *
  443. * Refresh means: Re-Enumerate devices and find out whether we
  444. * have any extra or missing entries.
  445. * GenEvents means throw connect events for devices.
  446. * that we noticed have arrived or left since last eneumeration. Only
  447. * valid with Refresh. We always throw disconnect events.
  448. *
  449. * Arguments:
  450. *
  451. * ulFlags - Options for enumeration. See DEV_MAN_FULL_REFRESH
  452. * DEV_MAN_GEN_EVENTS
  453. *
  454. * Return Value:
  455. *
  456. * Status
  457. *
  458. * History:
  459. *
  460. * 11/06/2000 Original Version
  461. *
  462. \**************************************************************************/
  463. HRESULT CWiaDevMan::ReEnumerateDevices(
  464. ULONG ulFlags)
  465. {
  466. TAKE_CRIT_SECT tcs(m_csDevList);
  467. HRESULT hr = S_OK;
  468. ResetEvent(g_hDevListCompleteEvent);
  469. //
  470. // Check whether flags indicate refresh.
  471. //
  472. if (ulFlags & DEV_MAN_FULL_REFRESH) {
  473. DestroyInfoSet();
  474. hr = CreateInfoSet();
  475. if (FAILED(hr)) {
  476. DBG_ERR(("CWiaDevMan::ReEnumerateDevices, failed to CreateInfoSet"));
  477. SetEvent(g_hDevListCompleteEvent);
  478. return hr;
  479. }
  480. }
  481. //
  482. // To generate events, we do it in 3 steps:
  483. // 1. Mark existing devices in list as "inactive".
  484. // 2. Do low level enumeration to find out what devices exist now, and
  485. // create new DEVICE_OBJECTS if necessary. On creation, throw connect
  486. // event. Mark device as "active", whether newly created or not.
  487. // 3. Traverse device list to see whether any devices in list are still
  488. // marked "inactive" - these devices need to be removed. For each
  489. // device that needs to be removed, throw diconnect event.
  490. // NOTE: This method is NOT the preferred method to handle device arrivals!
  491. //
  492. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  493. //
  494. // This is Step 1. of events
  495. //
  496. ForEachDeviceInList(DEV_MAN_OP_DEV_SET_FLAGS, STIMON_AD_FLAG_MARKED_INACTIVE);
  497. }
  498. //
  499. // Update service status with start pending if requested
  500. //
  501. if (ulFlags & DEV_MAN_STATUS_STARTP) {
  502. UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
  503. }
  504. //
  505. // Now, let's enumerate WIA "devnode" devices
  506. // This is Step 2. of events
  507. //
  508. // NOTE: Always Continue with enumeration, so skip the usual "if (SUCCEEDED)" checks
  509. EnumDevNodeDevices(ulFlags);
  510. //
  511. // Update service status with start pending if requested
  512. //
  513. if (ulFlags & DEV_MAN_STATUS_STARTP) {
  514. UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
  515. }
  516. //
  517. // Now, let's enumerate WIA "interface" devices
  518. //
  519. EnumInterfaceDevices(ulFlags);
  520. //
  521. // Update service status with start pending if requested
  522. //
  523. if (ulFlags & DEV_MAN_STATUS_STARTP) {
  524. UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
  525. }
  526. //
  527. // If volumes are enabled, then enumerate them.
  528. //
  529. //
  530. // Issue - do we ever generate connect events for volumes?
  531. //
  532. if (VolumesAreEnabled()) {
  533. EnumVolumes(ulFlags);
  534. }
  535. //
  536. // Update service status with start pending if requested
  537. //
  538. if (ulFlags & DEV_MAN_STATUS_STARTP) {
  539. UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
  540. }
  541. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  542. //
  543. // This is Step 3. of events
  544. //
  545. ForEachDeviceInList(DEV_MAN_OP_DEV_REMOVE_MATCH, STIMON_AD_FLAG_MARKED_INACTIVE);
  546. }
  547. //
  548. // Update service status with start pending if requested
  549. //
  550. if (ulFlags & DEV_MAN_STATUS_STARTP) {
  551. UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
  552. }
  553. SetEvent(g_hDevListCompleteEvent);
  554. return hr;
  555. }
  556. // ulFlags indicate whether we should throw connect event
  557. HRESULT CWiaDevMan::AddDevice(
  558. ULONG ulFlags,
  559. DEVICE_INFO *pInfo)
  560. {
  561. TAKE_CRIT_SECT tcs(m_csDevList);
  562. HRESULT hr = S_OK;
  563. ACTIVE_DEVICE *pActiveDevice = NULL;
  564. if (pInfo) {
  565. pActiveDevice = new ACTIVE_DEVICE(pInfo->wszDeviceInternalName, pInfo);
  566. //
  567. // Note that the ACTIVE_DEVICE will decide whether it should load
  568. // the driver or not.
  569. //
  570. if (pActiveDevice) {
  571. if (pActiveDevice->IsValid()) {
  572. //
  573. // Add this device to the device list. TBD: We may want
  574. // exclusive access to the list here. Do we do it, or the caller?
  575. //
  576. InsertTailList(&m_leDeviceListHead,&pActiveDevice->m_ListEntry);
  577. TAKE_ACTIVE_DEVICE tad(pActiveDevice);
  578. pActiveDevice->InitPnPNotifications(NULL);
  579. //
  580. // Throw CONNECT event, if we're told to. Notice that GenerateEventForDevice
  581. // willl change WIA_EVENT_DEVICE_CONNECTED to GUID_DeviceArrivedLaunch in
  582. // the case of STI only devices.
  583. //
  584. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  585. //
  586. // Only throw connect event if device is active, and it is not a
  587. // generic mass storage device (MSC cameras are marked as MSC not
  588. // VOL).
  589. //
  590. if ((pInfo->dwDeviceState & DEV_STATE_ACTIVE) && !(pInfo->dwInternalType & INTERNAL_DEV_TYPE_VOL)) {
  591. GenerateSafeConnectEvent(pActiveDevice);
  592. }
  593. } else {
  594. //
  595. // Mark that the event was generated, even though we didn't actually throw it.
  596. // This is so that the disconnect event will be thrown correctly.
  597. //
  598. if (pInfo->dwDeviceState & DEV_STATE_ACTIVE)
  599. {
  600. //
  601. // NOTE: We only do this if the device is ACTIVE. Basically, this case
  602. // is used for service startup. We would miss the device arrival events if
  603. // we did this for inactive devices, because when the device is subsequently
  604. // plugged in, the event would not be generated (if it was already marked).
  605. //
  606. pActiveDevice->m_DrvWrapper.setConnectEventState(TRUE);
  607. }
  608. }
  609. } else {
  610. DBG_ERR(("CWiaDevMan::AddDevice, could not create the device object"));
  611. delete pActiveDevice;
  612. }
  613. } else {
  614. DBG_ERR(("CWiaDevMan::AddDevice, Out of memory"));
  615. hr = E_OUTOFMEMORY;
  616. }
  617. } else {
  618. DBG_ERR(("CWiaDevMan::AddDevice, called with no device information"));
  619. }
  620. return hr;
  621. }
  622. HRESULT CWiaDevMan::RemoveDevice(ACTIVE_DEVICE *pActiveDevice)
  623. {
  624. HRESULT hr = S_OK;
  625. if (pActiveDevice) {
  626. TAKE_ACTIVE_DEVICE t(pActiveDevice);
  627. //
  628. // Only throw disconnect event if device is not a generic mass storage device
  629. // (MSC cameras are marked as MSC not VOL).
  630. //
  631. DEVICE_INFO *pInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
  632. if (!(pInfo->dwInternalType & INTERNAL_DEV_TYPE_VOL)) {
  633. //
  634. // Generate disconnect event
  635. //
  636. GenerateSafeDisconnectEvent(pActiveDevice);
  637. }
  638. //
  639. // Mark device as being removed
  640. //
  641. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() | STIMON_AD_FLAG_REMOVING);
  642. //
  643. // Remove any device notification callbacks
  644. //
  645. pActiveDevice->DisableDeviceNotifications();
  646. //
  647. // Stop PnP notifications immediately. This is important to free interface handle
  648. //
  649. pActiveDevice->StopPnPNotifications();
  650. //
  651. // Remove from the list
  652. //
  653. RemoveEntryList(&pActiveDevice->m_ListEntry);
  654. pActiveDevice->m_ListEntry.Flink = pActiveDevice->m_ListEntry.Blink = NULL;
  655. }
  656. if (pActiveDevice) {
  657. //
  658. // NOTE: Make sure that TAKE_ACTIVE_DEVICE has released the critical section BEFORE
  659. // we call the final release
  660. // NOTE also an assumption: The device list critical section must be grabbed before
  661. // calling this function, else it may be unsafe.
  662. //
  663. //
  664. // Destroy device object if there are no references to it
  665. //
  666. pActiveDevice->Release();
  667. }
  668. return hr;
  669. }
  670. HRESULT CWiaDevMan::RemoveDevice(DEVICE_INFO *pInfo)
  671. {
  672. HRESULT hr = E_NOTIMPL;
  673. DBG_WRN(("* Not implemented method: CWiaDevMan::RemoveDevice is being called"));
  674. return hr;
  675. }
  676. HRESULT CWiaDevMan::GenerateEventForDevice(
  677. const GUID *guidEvent,
  678. ACTIVE_DEVICE *pActiveDevice)
  679. {
  680. HRESULT hr = S_OK;
  681. BOOL bRet = FALSE;
  682. STINOTIFY sNotify;
  683. if (!guidEvent || !pActiveDevice) {
  684. DBG_WRN(("CWiaDevMan::GenerateEventForDevice, one or more NULL parameters"));
  685. return E_POINTER;
  686. }
  687. memset(&sNotify, 0, sizeof(sNotify));
  688. sNotify.dwSize = sizeof(STINOTIFY);
  689. sNotify.guidNotificationCode = *guidEvent;
  690. if (*guidEvent == WIA_EVENT_DEVICE_CONNECTED) {
  691. //
  692. // If this device or it's USD requests auto-generating a launch event on arrival
  693. // schedule it here
  694. //
  695. //
  696. // For STI devices we must check whether we need to generate the
  697. // event. For WIA devices, we always want to, so it's not an issue.
  698. //
  699. if (!pActiveDevice->m_DrvWrapper.IsWiaDevice()) {
  700. BOOL bStiDeviceMustThrowEvent = (pActiveDevice->QueryFlags() & STIMON_AD_FLAG_NOTIFY_RUNNING)
  701. && pActiveDevice->IsEventOnArrivalNeeded();
  702. if (!bStiDeviceMustThrowEvent) {
  703. return S_OK;
  704. } else {
  705. //
  706. // Make sure we change WIA_EVENT_DEVICE_CONNECTED to the appropriate STI guid
  707. //
  708. sNotify.guidNotificationCode = GUID_DeviceArrivedLaunch;
  709. }
  710. }
  711. }
  712. //
  713. // Inform the ACTIVE_DEVICE to process the event
  714. //
  715. {
  716. //TDB: DO we really need exclusive access to the device object?
  717. //TAKE_ACTIVE_DEVICE t(pActiveDevice);
  718. DBG_TRC(("CWiaDevMan::GenerateEventForDevice,, processing event (STI or WIA) for %ws", pActiveDevice->GetDeviceID()));
  719. bRet = pActiveDevice->ProcessEvent(&sNotify);
  720. if (!bRet) {
  721. DBG_WRN(("CWiaDevMan::GenerateEventForDevice, Attempted to generate event on device(%ws) arrival and failed ", pActiveDevice->GetDeviceID()));
  722. }
  723. }
  724. return hr;
  725. }
  726. HRESULT CWiaDevMan::NotifyRunningDriversOfEvent(
  727. const GUID *pEvent)
  728. {
  729. TAKE_CRIT_SECT tcs(m_csDevList);
  730. HRESULT hr = S_OK;
  731. //
  732. // Walk through list of devices
  733. //
  734. LIST_ENTRY *pentry = NULL;
  735. LIST_ENTRY *pentryNext = NULL;
  736. ACTIVE_DEVICE *pActiveDevice = NULL;
  737. {
  738. //
  739. // For each device in list, we want to notify the driver of an event. Note
  740. // this only applies to WIA drivers that are already loaded.
  741. //
  742. for ( pentry = m_leDeviceListHead.Flink; pentry != &m_leDeviceListHead; pentry = pentryNext ) {
  743. pentryNext = pentry->Flink;
  744. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  745. //
  746. // Check whether this is a WIA driver and whether it is loaded
  747. //
  748. if (pActiveDevice->m_DrvWrapper.IsWiaDriverLoaded()) {
  749. BSTR bstrDevId = SysAllocString(pActiveDevice->GetDeviceID());
  750. if (bstrDevId) {
  751. //
  752. // Call the driver to let it know about this event. Note that we
  753. // don't care whether it fails or not - we simply move on to the next
  754. // device in our list.
  755. //
  756. pActiveDevice->m_DrvWrapper.WIA_drvNotifyPnpEvent(pEvent,
  757. bstrDevId,
  758. 0);
  759. SysFreeString(bstrDevId);
  760. bstrDevId = NULL;
  761. }
  762. }
  763. }
  764. }
  765. return hr;
  766. }
  767. HRESULT CWiaDevMan::ProcessDeviceArrival()
  768. {
  769. HRESULT hr = S_OK;
  770. hr = ReEnumerateDevices(DEV_MAN_GEN_EVENTS /*| DEV_MAN_FULL_REFRESH*/);
  771. return hr;
  772. }
  773. HRESULT CWiaDevMan::ProcessDeviceRemoval(
  774. WCHAR *wszDeviceID)
  775. {
  776. HRESULT hr = S_OK;
  777. ACTIVE_DEVICE *pActiveDevice = NULL;
  778. if (wszDeviceID) {
  779. DBG_TRC(("CWiaDevMan::ProcessDeviceRemoval, finding device ID '%ls'",
  780. wszDeviceID));
  781. //
  782. // Attempt to find the device
  783. //
  784. pActiveDevice = IsInList(DEV_MAN_IN_LIST_DEV_ID, wszDeviceID);
  785. if (pActiveDevice) {
  786. hr = ProcessDeviceRemoval(pActiveDevice, TRUE);
  787. //
  788. // Release it since it was addref'd
  789. //
  790. pActiveDevice->Release();
  791. }
  792. else
  793. {
  794. DBG_TRC(("CWiaDevMan::ProcessDeviceRemoval, did not find device ID '%ls'",
  795. wszDeviceID));
  796. }
  797. } else {
  798. DBG_TRC(("CWiaDevMan::ProcessDeviceRemoval, ProcessDeviceRemoval called with NULL device ID"));
  799. }
  800. return hr;
  801. }
  802. HRESULT CWiaDevMan::ProcessDeviceRemoval(
  803. ACTIVE_DEVICE *pActiveDevice,
  804. BOOL bGenEvent)
  805. {
  806. HRESULT hr = S_OK;
  807. if (pActiveDevice) {
  808. //
  809. // Mark the device as inactive
  810. //
  811. pActiveDevice->m_DrvWrapper.setDeviceState(pActiveDevice->m_DrvWrapper.getDeviceState() & ~DEV_STATE_ACTIVE);
  812. if (bGenEvent) {
  813. //
  814. // Generate disconnect event
  815. //
  816. DBG_TRC(("ProcessDeviceRemoval, generating SafeDisconnect Event "
  817. "for device '%ls'", pActiveDevice->GetDeviceID()));
  818. GenerateSafeDisconnectEvent(pActiveDevice);
  819. }
  820. {
  821. //
  822. // Note that we do not take the active device during event generation.
  823. //
  824. //TAKE_ACTIVE_DEVICE tad(pActiveDevice);
  825. //
  826. // Remove any device notification callbacks
  827. //
  828. pActiveDevice->DisableDeviceNotifications();
  829. //
  830. // Stop PnP notifications immediately. This is important to free interface handle
  831. //
  832. pActiveDevice->StopPnPNotifications();
  833. //
  834. // Unload the driver
  835. //
  836. pActiveDevice->UnLoadDriver(TRUE);
  837. }
  838. } else {
  839. DBG_TRC(("CWiaDevMan::ProcessDeviceRemoval, Device not in list"));
  840. }
  841. return hr;
  842. }
  843. ACTIVE_DEVICE* CWiaDevMan::IsInList(
  844. ULONG ulFlags,
  845. const WCHAR *wszID)
  846. {
  847. TAKE_CRIT_SECT tcs(m_csDevList);
  848. LIST_ENTRY *pentry = NULL;
  849. LIST_ENTRY *pentryNext = NULL;
  850. ACTIVE_DEVICE *pActiveDevice = NULL;
  851. DEVICE_INFO *pDevInfo = NULL;
  852. //
  853. // Walk through list of devices and count the ones of appropriate type
  854. //
  855. {
  856. for ( pentry = m_leDeviceListHead.Flink; pentry != &m_leDeviceListHead; pentry = pentryNext ) {
  857. pentryNext = pentry->Flink;
  858. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  859. pDevInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
  860. if (pDevInfo) {
  861. //
  862. // Decide what to compare, based on the flags. Note that if more
  863. // that one flag is set, then the comarison will be done on more
  864. // than one field. We will return TRUE on the first hit.
  865. //
  866. //
  867. // Here's a quick workaround for volume devices: whenever we hit
  868. // potential match, check whether this is of the correct VolumeType.
  869. //
  870. if (pDevInfo->dwInternalType & INTERNAL_DEV_TYPE_VOL) {
  871. if (!IsCorrectVolumeType(pDevInfo->wszAlternateID)) {
  872. DBG_TRC(("CWiaDevMan::IsInList, Volume (%ws) is not of correct type.", pDevInfo->wszAlternateID));
  873. continue;
  874. }
  875. }
  876. if (DEV_MAN_IN_LIST_DEV_ID) {
  877. if (lstrcmpiW(pDevInfo->wszDeviceInternalName, wszID) == 0) {
  878. pActiveDevice->AddRef();
  879. return pActiveDevice;
  880. }
  881. }
  882. if (ulFlags & DEV_MAN_IN_LIST_ALT_ID) {
  883. if (pDevInfo->wszAlternateID) {
  884. if (lstrcmpiW(pDevInfo->wszAlternateID, wszID) == 0) {
  885. pActiveDevice->AddRef();
  886. return pActiveDevice;
  887. }
  888. }
  889. }
  890. }
  891. }
  892. }
  893. return FALSE;
  894. }
  895. ULONG CWiaDevMan::NumDevices(ULONG ulFlags)
  896. {
  897. TAKE_CRIT_SECT tcs(m_csDevList);
  898. LIST_ENTRY *pentry = NULL;
  899. LIST_ENTRY *pentryNext = NULL;
  900. ACTIVE_DEVICE *pActiveDevice = NULL;
  901. ULONG ulCount = 0;
  902. //
  903. // Walk through list of devices and count the ones of appropriate type
  904. //
  905. {
  906. for ( pentry = m_leDeviceListHead.Flink; pentry != &m_leDeviceListHead; pentry = pentryNext ) {
  907. pentryNext = pentry->Flink;
  908. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  909. //
  910. // Check whether this device is one of the ones we want to count.
  911. // If it is, then increment the count.
  912. //
  913. if (IsCorrectEnumType(ulFlags, pActiveDevice->m_DrvWrapper.getDevInfo())) {
  914. ++ulCount;
  915. }
  916. }
  917. }
  918. return ulCount;
  919. }
  920. VOID WINAPI CWiaDevMan::EnumerateActiveDevicesWithCallback(
  921. PFN_ACTIVEDEVICE_CALLBACK pfn,
  922. VOID *pContext
  923. )
  924. /*++
  925. Routine Description:
  926. Walk the list of known active devices, calling given routine for each device
  927. Arguments:
  928. pfn - Address of the callback
  929. pContext- Pointer to context information to pass to callback
  930. Return Value:
  931. None
  932. --*/
  933. {
  934. if (!pfn) {
  935. ASSERT(("Incorrect callback", 0));
  936. return;
  937. }
  938. LIST_ENTRY * pentry;
  939. LIST_ENTRY * pentryNext;
  940. ACTIVE_DEVICE* pActiveDevice;
  941. // BEGIN PROTECTED CODE
  942. {
  943. TAKE_CRIT_SECT _tcs(m_csDevList);
  944. for ( pentry = m_leDeviceListHead.Flink;
  945. pentry != &m_leDeviceListHead;
  946. pentry = pentryNext ) {
  947. pentryNext = pentry->Flink;
  948. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  949. if (!pActiveDevice->IsValid()) {
  950. ASSERT(("CWiaDevMan::EnumerateActiveDevicesWithCallback, Invalid device signature", 0));
  951. break;
  952. }
  953. pfn(pActiveDevice,pContext);
  954. }
  955. }
  956. // END PROTECTED CODE
  957. }
  958. HRESULT CWiaDevMan::GetDevInfoStgs(
  959. ULONG ulFlags,
  960. ULONG *pulNumDevInfoStream,
  961. IWiaPropertyStorage ***pppOutputStorageArray)
  962. {
  963. TAKE_CRIT_SECT tcs(m_csDevList);
  964. HRESULT hr = S_OK;
  965. ULONG ulCount = 0;
  966. ULONG ulIndex = 0;
  967. IWiaPropertyStorage **ppDevInfoStgs = NULL;
  968. IWiaPropertyStorage **ppDevAndRemoteDevStgs = NULL;
  969. ULONG ulRemoteDevices = 0;
  970. *pulNumDevInfoStream = 0;
  971. *pppOutputStorageArray = NULL;
  972. //
  973. // Count number of devices matching our category flags
  974. //
  975. ulCount = NumDevices(ulFlags);
  976. if (ulCount) {
  977. //
  978. // Allocate space for that many streams
  979. //
  980. ppDevInfoStgs = new IWiaPropertyStorage*[ulCount];
  981. if (ppDevInfoStgs) {
  982. memset(ppDevInfoStgs, 0, sizeof(IWiaPropertyStorage*) * ulCount);
  983. //
  984. // Go through device list, and for every device is our category, save
  985. // its information to a stream
  986. //
  987. LIST_ENTRY *pentry = NULL;
  988. LIST_ENTRY *pentryNext = NULL;
  989. ACTIVE_DEVICE *pActiveDevice = NULL;
  990. {
  991. ulIndex = 0;
  992. for ( pentry = m_leDeviceListHead.Flink; pentry != &m_leDeviceListHead; pentry = pentryNext ) {
  993. pentryNext = pentry->Flink;
  994. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  995. //
  996. // Paranoid check for overflow - break if we've reached our count
  997. //
  998. if (ulIndex >= ulCount) {
  999. break;
  1000. }
  1001. //
  1002. // Check whether this device is one of the ones we want
  1003. //
  1004. if (IsCorrectEnumType(ulFlags, pActiveDevice->m_DrvWrapper.getDevInfo())) {
  1005. DEVICE_INFO *pDeviceInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
  1006. if (pDeviceInfo) {
  1007. //
  1008. // Here's a work-around for MSC or Volume devices. Since we cant get the
  1009. // display name when we receive the volume arrival notification, we should
  1010. // refresh it here
  1011. //
  1012. if (pDeviceInfo->dwInternalType & (INTERNAL_DEV_TYPE_VOL | INTERNAL_DEV_TYPE_MSC_CAMERA)) {
  1013. RefreshDevInfoFromMountPoint(pDeviceInfo, pDeviceInfo->wszAlternateID);
  1014. }
  1015. ppDevInfoStgs[ulIndex] = CreateDevInfoStg(pDeviceInfo);
  1016. if (!ppDevInfoStgs[ulIndex]) {
  1017. hr = E_OUTOFMEMORY;
  1018. break;
  1019. }
  1020. }
  1021. ++ulIndex;
  1022. }
  1023. }
  1024. }
  1025. } else {
  1026. hr = E_OUTOFMEMORY;
  1027. }
  1028. } else {
  1029. hr = S_FALSE;
  1030. }
  1031. /* Removed remote device enumeration in order to reduce our attack surface.
  1032. //
  1033. // If everything succeeded, check whether there are any remote devices installed.
  1034. // If there are, add them to the list. Skip this step if local devices only was
  1035. // requested.
  1036. //
  1037. if (SUCCEEDED(hr) && !(ulFlags & DEV_MAN_ENUM_TYPE_LOCAL_ONLY)) {
  1038. ulRemoteDevices = CountRemoteDevices(0);
  1039. if (ulRemoteDevices) {
  1040. //
  1041. // Allocate space for the new device list. It must be big enough to hold both
  1042. // local and remote dev. info. stgs.
  1043. //
  1044. ppDevAndRemoteDevStgs = new IWiaPropertyStorage*[ulCount + ulRemoteDevices];
  1045. if (ppDevAndRemoteDevStgs) {
  1046. memset(ppDevAndRemoteDevStgs, 0, sizeof(IWiaPropertyStorage*) * (ulCount + ulRemoteDevices));
  1047. //
  1048. // Copy the local dev. info. storages
  1049. //
  1050. for (ulIndex = 0; ulIndex < ulCount; ulIndex++) {
  1051. ppDevAndRemoteDevStgs[ulIndex] = ppDevInfoStgs[ulIndex];
  1052. }
  1053. //
  1054. // No need for the local only array, since we have a copy of the local
  1055. // dev. info. stgs in the ppDevAndRemoteDevStgs array.
  1056. //
  1057. if (ppDevInfoStgs) {
  1058. delete [] ppDevInfoStgs;
  1059. ppDevInfoStgs = NULL;
  1060. }
  1061. //
  1062. // Set ppDevInfoStgs to point to ppDevAndRemoteDevStgs. This is simply cosmetic,
  1063. // since our code that sets the return values can now always use the ppDevInfoStgs
  1064. // pointer.
  1065. //
  1066. ppDevInfoStgs = ppDevAndRemoteDevStgs;
  1067. //
  1068. // Create dev. info. stgs for the remote devices. We pass in the address where
  1069. // the first dev. info. stg. will reside, and the maxiumum number of dev. info. stgs
  1070. // to fill in. This is to avoid the problem where the registry might be updated
  1071. // in between us counting the number of remote devices with CountRemoteDevices(..),
  1072. // and actually enumerating them with FillRemoteDeviceStgs(..).
  1073. //
  1074. hr = FillRemoteDeviceStgs(&ppDevAndRemoteDevStgs[ulCount], &ulRemoteDevices);
  1075. if (SUCCEEDED(hr)) {
  1076. //
  1077. // Increment the device count to be local + remote devices
  1078. //
  1079. ulCount += ulRemoteDevices;
  1080. } else {
  1081. //
  1082. // If we failed to get remote devices, that's OK since it's non-fatal.
  1083. // Do some clean-up so we return local devices only. This involves
  1084. // deleting any remote device info. stgs. that were added after the
  1085. // local dev. info. stgs.
  1086. //
  1087. for (ulIndex = ulCount; ulIndex < (ulCount + ulRemoteDevices); ulIndex++) {
  1088. if (ppDevAndRemoteDevStgs[ulIndex]) {
  1089. delete ppDevAndRemoteDevStgs[ulIndex];
  1090. ppDevAndRemoteDevStgs[ulIndex] = NULL;
  1091. }
  1092. }
  1093. hr = S_OK;
  1094. }
  1095. } else {
  1096. hr = E_OUTOFMEMORY;
  1097. }
  1098. }
  1099. }
  1100. */
  1101. //
  1102. // Set the return
  1103. //
  1104. if (SUCCEEDED(hr)) {
  1105. *pulNumDevInfoStream = ulCount;
  1106. *pppOutputStorageArray = ppDevInfoStgs;
  1107. if (*pulNumDevInfoStream) {
  1108. hr = S_OK;
  1109. } else {
  1110. hr = S_FALSE;
  1111. }
  1112. } else {
  1113. //
  1114. // On failure, cleanup.
  1115. //
  1116. if (ppDevInfoStgs) {
  1117. for (ulIndex = 0; ulIndex < ulCount; ulIndex++) {
  1118. if (ppDevInfoStgs[ulIndex]) {
  1119. delete ppDevInfoStgs[ulIndex];
  1120. ppDevInfoStgs[ulIndex] = NULL;
  1121. }
  1122. }
  1123. delete [] ppDevInfoStgs;
  1124. ppDevInfoStgs = NULL;
  1125. }
  1126. }
  1127. return hr;
  1128. }
  1129. HRESULT CWiaDevMan::GetDeviceValue(
  1130. ACTIVE_DEVICE *pActiveDevice,
  1131. WCHAR *pValueName,
  1132. DWORD *pType,
  1133. BYTE *pData,
  1134. DWORD *cbData)
  1135. {
  1136. HRESULT hr = E_FAIL;
  1137. DEVICE_INFO *pInfo = NULL;
  1138. HKEY hDevRegKey = NULL;
  1139. HKEY hDevDataRegKey = NULL;
  1140. DWORD dwError = 0;
  1141. if (pActiveDevice) {
  1142. TAKE_ACTIVE_DEVICE tad(pActiveDevice);
  1143. pInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
  1144. if (pInfo) {
  1145. //
  1146. // Get the device registry key
  1147. //
  1148. hDevRegKey = GetDeviceHKey(pActiveDevice, NULL);
  1149. if (hDevRegKey) {
  1150. //
  1151. // Open the DeviceData section
  1152. //
  1153. dwError = RegCreateKeyExW(hDevRegKey,
  1154. REGSTR_VAL_DATA_W,
  1155. 0,
  1156. NULL,
  1157. REG_OPTION_NON_VOLATILE,
  1158. KEY_READ,
  1159. NULL,
  1160. &hDevDataRegKey,
  1161. NULL);
  1162. if (dwError == ERROR_SUCCESS) {
  1163. //
  1164. // Call RegQueryValueEx.
  1165. //
  1166. dwError = RegQueryValueExW(hDevDataRegKey,
  1167. pValueName,
  1168. NULL,
  1169. pType,
  1170. pData,
  1171. cbData);
  1172. if (dwError == ERROR_SUCCESS) {
  1173. hr = S_OK;
  1174. }
  1175. RegCloseKey(hDevDataRegKey);
  1176. }
  1177. //
  1178. // Close the device registry key
  1179. //
  1180. RegCloseKey(hDevRegKey);
  1181. }
  1182. } else {
  1183. DBG_WRN(("CWiaDevMan::GetDeviceValue, DeviceInfo is not valid"));
  1184. }
  1185. } else {
  1186. DBG_TRC(("CWiaDevMan::GetDeviceValue, called with NULL"));
  1187. }
  1188. return hr;
  1189. }
  1190. WCHAR* CWiaDevMan::AllocGetInterfaceNameFromDevInfo(DEVICE_INFO *pDevInfo)
  1191. {
  1192. TAKE_CRIT_SECT tcs(m_csDevList);
  1193. WCHAR *wszInterface = NULL;
  1194. GUID guidClass = GUID_DEVCLASS_IMAGE;
  1195. BOOL bRet = FALSE;
  1196. DWORD dwStrLen = 0;
  1197. SP_DEVICE_INTERFACE_DATA *pspDevInterfaceData = NULL;
  1198. SP_DEVICE_INTERFACE_DATA spTemp;
  1199. DWORD dwDetailSize = 0;
  1200. SP_DEVICE_INTERFACE_DETAIL_DATA_W *pspDevInterfaceDetailData = NULL;
  1201. if (pDevInfo) {
  1202. //
  1203. // Check whether this is an interface or devnode device
  1204. //
  1205. if (pDevInfo->dwInternalType & INTERNAL_DEV_TYPE_INTERFACE) {
  1206. pspDevInterfaceData = &pDevInfo->spDevInterfaceData;
  1207. } else {
  1208. spTemp.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  1209. spTemp.InterfaceClassGuid = guidClass;
  1210. bRet = SetupDiEnumDeviceInterfaces (m_DeviceInfoSet,
  1211. &pDevInfo->spDevInfoData,
  1212. &guidClass,
  1213. 0,
  1214. &spTemp);
  1215. if (bRet) {
  1216. pspDevInterfaceData = &spTemp;
  1217. } else {
  1218. DBG_WRN(("CWiaDevMan::AllocGetInterfaceNameFromDevInfo, SetupDiEnumDeviceInterfaces failed to return interface information"))
  1219. }
  1220. }
  1221. //
  1222. // If we have a valid pspDevInterfaceData, then we can get the interface
  1223. // detail information, which includes the interface name
  1224. //
  1225. if (pspDevInterfaceData) {
  1226. SP_DEVINFO_DATA spDevInfoData;
  1227. spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1228. //
  1229. // Get the required size for the interface detail
  1230. //
  1231. bRet = SetupDiGetDeviceInterfaceDetailW(m_DeviceInfoSet,
  1232. pspDevInterfaceData,
  1233. NULL,
  1234. 0,
  1235. &dwDetailSize,
  1236. &spDevInfoData);
  1237. DWORD dwError = GetLastError();
  1238. if ((dwError == ERROR_INSUFFICIENT_BUFFER) && dwDetailSize) {
  1239. pspDevInterfaceDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*) new BYTE[dwDetailSize];
  1240. if (pspDevInterfaceDetailData) {
  1241. pspDevInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  1242. //
  1243. // Get the actual interface detail
  1244. //
  1245. bRet = SetupDiGetDeviceInterfaceDetailW(m_DeviceInfoSet,
  1246. pspDevInterfaceData,
  1247. pspDevInterfaceDetailData,
  1248. dwDetailSize,
  1249. &dwDetailSize,
  1250. NULL);
  1251. if (bRet) {
  1252. dwStrLen = lstrlenW(pspDevInterfaceDetailData->DevicePath);
  1253. wszInterface = new WCHAR[dwStrLen + 1];
  1254. if (wszInterface) {
  1255. lstrcpyW(wszInterface, pspDevInterfaceDetailData->DevicePath);
  1256. } else {
  1257. DBG_WRN(("CWiaDevMan::AllocGetInterfaceNameFromDevInfo, out of memory"))
  1258. }
  1259. } else {
  1260. DBG_TRC(("CWiaDevMan::AllocGetInterfaceNameFromDevInfo, Could not get SP_DEVICE_INTERFACE_DETAIL_DATA"));
  1261. }
  1262. delete [] pspDevInterfaceDetailData;
  1263. } else {
  1264. DBG_WRN(("CWiaDevMan::AllocGetInterfaceNameFromDevInfo, out of memory"))
  1265. }
  1266. } else {
  1267. DBG_WRN(("CWiaDevMan::AllocGetInterfaceNameFromDevInfo, SetupDiGetDeviceInterfaceDetail returned an error, could not determine buffer size"))
  1268. }
  1269. } else {
  1270. DBG_TRC(("CWiaDevMan::AllocGetInterfaceNameFromDevInfo, Could not get SP_DEVICE_INTERFACE_DATA"));
  1271. }
  1272. }
  1273. return wszInterface;
  1274. }
  1275. //
  1276. // Look up driver name by interface name
  1277. // NOTE: In the interests of time, this was copied directly from infoset.h
  1278. BOOL
  1279. CWiaDevMan::LookupDriverNameFromInterfaceName(
  1280. LPCTSTR pszInterfaceName,
  1281. StiCString *pstrDriverName)
  1282. {
  1283. TAKE_CRIT_SECT tcs(m_csDevList);
  1284. BUFFER bufDetailData;
  1285. SP_DEVINFO_DATA spDevInfoData;
  1286. SP_DEVICE_INTERFACE_DATA spDevInterfaceData;
  1287. PSP_DEVICE_INTERFACE_DETAIL_DATA pspDevInterfaceDetailData;
  1288. TCHAR szDevDriver[STI_MAX_INTERNAL_NAME_LENGTH];
  1289. DWORD cbData = 0;
  1290. DWORD dwErr = 0;
  1291. HKEY hkDevice = (HKEY)INVALID_HANDLE_VALUE;
  1292. LONG lResult = ERROR_SUCCESS;
  1293. DWORD dwType = REG_SZ;
  1294. BOOL fRet = FALSE;
  1295. BOOL fDataAcquired = FALSE;
  1296. bufDetailData.Resize(sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) +
  1297. MAX_PATH * sizeof(TCHAR) +
  1298. 16
  1299. );
  1300. pspDevInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) bufDetailData.QueryPtr();
  1301. if (!pspDevInterfaceDetailData) {
  1302. return (CR_OUT_OF_MEMORY);
  1303. }
  1304. //
  1305. // Locate this device interface in our device information set.
  1306. //
  1307. spDevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  1308. if (SetupDiOpenDeviceInterface(m_DeviceInfoSet,
  1309. pszInterfaceName,
  1310. DIODI_NO_ADD,
  1311. &spDevInterfaceData)) {
  1312. //
  1313. // First try to open interface regkey.
  1314. //
  1315. hkDevice = SetupDiOpenDeviceInterfaceRegKey(m_DeviceInfoSet,
  1316. &spDevInterfaceData,
  1317. 0,
  1318. KEY_READ);
  1319. if(INVALID_HANDLE_VALUE != hkDevice){
  1320. *szDevDriver = TEXT('\0');
  1321. cbData = sizeof(szDevDriver);
  1322. lResult = RegQueryValueEx(hkDevice,
  1323. REGSTR_VAL_DEVICE_ID,
  1324. NULL,
  1325. &dwType,
  1326. (LPBYTE)szDevDriver,
  1327. &cbData);
  1328. dwErr = ::GetLastError();
  1329. RegCloseKey(hkDevice);
  1330. hkDevice = (HKEY)INVALID_HANDLE_VALUE;
  1331. if(ERROR_SUCCESS == lResult){
  1332. fDataAcquired = TRUE;
  1333. }
  1334. }
  1335. if(!fDataAcquired){
  1336. //
  1337. // Try to open devnode regkey.
  1338. //
  1339. cbData = 0;
  1340. pspDevInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  1341. spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1342. fRet = SetupDiGetDeviceInterfaceDetail(m_DeviceInfoSet,
  1343. &spDevInterfaceData,
  1344. pspDevInterfaceDetailData,
  1345. bufDetailData.QuerySize(),
  1346. &cbData,
  1347. &spDevInfoData);
  1348. if(fRet){
  1349. //
  1350. // Get device interface registry key.
  1351. //
  1352. hkDevice = SetupDiOpenDevRegKey(m_DeviceInfoSet,
  1353. &spDevInfoData,
  1354. DICS_FLAG_GLOBAL,
  1355. 0,
  1356. DIREG_DRV,
  1357. KEY_READ);
  1358. dwErr = ::GetLastError();
  1359. } else {
  1360. DBG_ERR(("SetupDiGetDeviceInterfaceDetail() Failed Err=0x%x",GetLastError()));
  1361. }
  1362. if (INVALID_HANDLE_VALUE != hkDevice) {
  1363. *szDevDriver = TEXT('\0');
  1364. cbData = sizeof(szDevDriver);
  1365. lResult = RegQueryValueEx(hkDevice,
  1366. REGSTR_VAL_DEVICE_ID,
  1367. NULL,
  1368. &dwType,
  1369. (LPBYTE)szDevDriver,
  1370. &cbData);
  1371. dwErr = ::GetLastError();
  1372. RegCloseKey(hkDevice);
  1373. hkDevice = (HKEY)INVALID_HANDLE_VALUE;
  1374. if(ERROR_SUCCESS == lResult){
  1375. fDataAcquired = TRUE;
  1376. }
  1377. } else {
  1378. DBG_ERR(("SetupDiOpenDevRegKey() Failed Err=0x%x",GetLastError()));
  1379. fRet = FALSE;
  1380. }
  1381. }
  1382. if (fDataAcquired) {
  1383. //
  1384. // Got it
  1385. //
  1386. pstrDriverName->CopyString(szDevDriver);
  1387. fRet = TRUE;
  1388. }
  1389. } else {
  1390. DBG_ERR(("CWiaDevMan::LookupDriverNameFromInterfaceName() Failed Err=0x%x",GetLastError()));
  1391. fRet = FALSE;
  1392. }
  1393. return (fRet);
  1394. }
  1395. ACTIVE_DEVICE* CWiaDevMan::LookDeviceFromPnPHandles(
  1396. HANDLE hInterfaceHandle,
  1397. HANDLE hPnPSink)
  1398. {
  1399. TAKE_CRIT_SECT tcs(m_csDevList);
  1400. LIST_ENTRY *pentry;
  1401. LIST_ENTRY *pentryNext;
  1402. ACTIVE_DEVICE *pActiveDevice = NULL;
  1403. ACTIVE_DEVICE *pCurrent = NULL;
  1404. {
  1405. for ( pentry = m_leDeviceListHead.Flink; pentry != &m_leDeviceListHead; pentry = pentryNext ) {
  1406. pentryNext = pentry->Flink;
  1407. pCurrent = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  1408. if ( !pCurrent->IsValid()) {
  1409. DBG_WRN(("CWiaDevMan::LookupDeviceByPnPHandles, Invalid device object, aborting search..."));
  1410. break;
  1411. }
  1412. //
  1413. // Check whether this PnP notification handle returned from
  1414. // RegisterDeviceNotification is the one we're looking for
  1415. //
  1416. if ( hPnPSink == pCurrent->GetNotificationsSink()) {
  1417. pActiveDevice = pCurrent;
  1418. pActiveDevice->AddRef();
  1419. break;
  1420. }
  1421. }
  1422. }
  1423. return pActiveDevice;
  1424. }
  1425. VOID CWiaDevMan::DestroyInfoSet()
  1426. {
  1427. TAKE_CRIT_SECT tcs(m_csDevList);
  1428. if (m_DeviceInfoSet) {
  1429. SetupDiDestroyDeviceInfoList(m_DeviceInfoSet);
  1430. m_DeviceInfoSet = NULL;
  1431. }
  1432. }
  1433. HRESULT CWiaDevMan::CreateInfoSet()
  1434. {
  1435. TAKE_CRIT_SECT tcs(m_csDevList);
  1436. HRESULT hr = S_OK;
  1437. DWORD dwErr = 0;
  1438. HDEVINFO hdvNew = NULL;
  1439. //
  1440. // Create a blank infoset
  1441. //
  1442. m_DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
  1443. if ( m_DeviceInfoSet && (m_DeviceInfoSet != INVALID_HANDLE_VALUE)) {
  1444. //
  1445. // Now we can retrieve the existing list of WIA devices
  1446. // into the device information set we created above.
  1447. //
  1448. //
  1449. // This adds WIA "devnode" devices
  1450. //
  1451. hdvNew = SetupDiGetClassDevsEx(&(GUID_DEVCLASS_IMAGE),
  1452. NULL,
  1453. NULL,
  1454. DIGCF_DEVICEINTERFACE,
  1455. m_DeviceInfoSet,
  1456. NULL,
  1457. NULL);
  1458. if (hdvNew == INVALID_HANDLE_VALUE) {
  1459. dwErr = ::GetLastError();
  1460. DBG_ERR(("CWiaDevMan::CreateInfoSet, SetupDiGetClassDevsEx failed with 0x%lx\n", dwErr));
  1461. } else {
  1462. //
  1463. // This adds WIA "interface" devices
  1464. //
  1465. hdvNew = SetupDiGetClassDevsEx(&(GUID_DEVCLASS_IMAGE),
  1466. NULL,
  1467. NULL,
  1468. 0,
  1469. m_DeviceInfoSet,
  1470. NULL,
  1471. NULL);
  1472. if (hdvNew == INVALID_HANDLE_VALUE) {
  1473. dwErr = ::GetLastError();
  1474. DBG_ERR(("CWiaDevMan::CreateInfoSet, second SetupDiGetClassDevsEx failed with 0x%lx\n", dwErr));
  1475. }
  1476. }
  1477. } else {
  1478. dwErr = ::GetLastError();
  1479. DBG_ERR(("CWiaDevMan::CreateInfoSet, SetupDiCreateDeviceInfoList failed with 0x%lx\n", dwErr));
  1480. }
  1481. if (dwErr) {
  1482. hr = HRESULT_FROM_WIN32(dwErr);
  1483. }
  1484. return hr;
  1485. }
  1486. VOID CWiaDevMan::DestroyDeviceList()
  1487. {
  1488. TAKE_CRIT_SECT tcs(m_csDevList);
  1489. LIST_ENTRY *pentry = NULL;
  1490. ACTIVE_DEVICE *pActiveDevice = NULL;
  1491. DBG_TRC(("Destroying list of active devices"));
  1492. //
  1493. // Go through the list terminating devices
  1494. //
  1495. while (!IsListEmpty(&m_leDeviceListHead)) {
  1496. pentry = m_leDeviceListHead.Flink;
  1497. //
  1498. // Remove from the list ( reset list entry )
  1499. //
  1500. RemoveHeadList(&m_leDeviceListHead);
  1501. InitializeListHead( pentry );
  1502. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  1503. //
  1504. // Remove any device notification callbacks
  1505. //
  1506. pActiveDevice->DisableDeviceNotifications();
  1507. // Release device object
  1508. pActiveDevice->Release();
  1509. }
  1510. }
  1511. BOOL CWiaDevMan::VolumesAreEnabled()
  1512. {
  1513. return m_bVolumesEnabled;
  1514. }
  1515. HRESULT CWiaDevMan::ForEachDeviceInList(
  1516. ULONG ulFlags,
  1517. ULONG ulParam)
  1518. {
  1519. TAKE_CRIT_SECT tcs(m_csDevList);
  1520. HRESULT hr = S_OK;
  1521. //
  1522. // Walk through list of devices
  1523. //
  1524. LIST_ENTRY *pentry = NULL;
  1525. LIST_ENTRY *pentryNext = NULL;
  1526. ACTIVE_DEVICE *pActiveDevice = NULL;
  1527. {
  1528. //
  1529. // For each device in list, call the appropriate device manager method
  1530. //
  1531. for ( pentry = m_leDeviceListHead.Flink; pentry != &m_leDeviceListHead; pentry = pentryNext ) {
  1532. pentryNext = pentry->Flink;
  1533. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  1534. switch (ulFlags) {
  1535. case DEV_MAN_OP_DEV_SET_FLAGS:
  1536. {
  1537. //
  1538. // Set the flags on the ACTIVE_DEVICE
  1539. //
  1540. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() | ulParam);
  1541. break;
  1542. }
  1543. case DEV_MAN_OP_DEV_REMOVE_MATCH:
  1544. {
  1545. //
  1546. // Remove device if the ACTIVE_DEVICE flags have the specified bit set
  1547. //
  1548. if (pActiveDevice->QueryFlags() & ulParam) {
  1549. hr = RemoveDevice(pActiveDevice);
  1550. }
  1551. break;
  1552. }
  1553. case DEV_MAN_OP_DEV_REREAD:
  1554. {
  1555. //
  1556. // Get the device settings, which includes rebuilding
  1557. // the STI event list from registry
  1558. //
  1559. pActiveDevice->GetDeviceSettings();
  1560. break;
  1561. }
  1562. case DEV_MAN_OP_DEV_RESTORE_EVENT:
  1563. {
  1564. DEVICE_INFO *pDeviceInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
  1565. if (pDeviceInfo) {
  1566. //
  1567. // NOTE: We don't want to restore MSC camera device event handlers
  1568. // here. This is because they are restored along with the global handlers
  1569. // in RestoreAllPersistentCBs
  1570. //
  1571. if (!(pDeviceInfo->dwInternalType & INTERNAL_DEV_TYPE_MSC_CAMERA)) {
  1572. HKEY hKey = NULL;
  1573. //
  1574. // Get the device's HKEY and restore any device specific event handlers
  1575. //
  1576. hKey = GetDeviceHKey(pActiveDevice, NULL);
  1577. if (hKey) {
  1578. g_eventNotifier.RestoreDevPersistentCBs(hKey);
  1579. }
  1580. }
  1581. }
  1582. }
  1583. default:
  1584. // do nothing
  1585. ;
  1586. };
  1587. if (FAILED(hr)) {
  1588. DBG_WRN(("CWiaDevMan::ForEachDeviceInList, failed with params (0x%8X, 0x%8X), on device %ws",
  1589. ulFlags, ulParam, pActiveDevice->GetDeviceID()));
  1590. break;
  1591. }
  1592. }
  1593. }
  1594. return hr;
  1595. }
  1596. HRESULT CWiaDevMan::EnumDevNodeDevices(
  1597. ULONG ulFlags)
  1598. {
  1599. HRESULT hr = S_OK; // Notice that none of these errors are fatal. We always return S_OK.
  1600. ULONG ulIndex = 0;
  1601. DWORD dwError = ERROR_SUCCESS;
  1602. DWORD dwFlags = DIGCF_PROFILE;
  1603. CONFIGRET ConfigRet = CR_SUCCESS;
  1604. ULONG ulStatus = 0;
  1605. ULONG ulProblemNumber = 0;
  1606. HKEY hDevRegKey = (HKEY)INVALID_HANDLE_VALUE;
  1607. DWORD dwDeviceState = 0;
  1608. DWORD cbData = 0;
  1609. DEVICE_INFO *pDevInfo = NULL;
  1610. ACTIVE_DEVICE *pActiveDevice = NULL;
  1611. SP_DEVINFO_DATA spDevInfoData;
  1612. WCHAR wszDeviceID[STI_MAX_INTERNAL_NAME_LENGTH];
  1613. //
  1614. // Enumerate "devnode" devices.
  1615. //
  1616. spDevInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
  1617. for (ulIndex = 0; SetupDiEnumDeviceInfo (m_DeviceInfoSet, ulIndex, &spDevInfoData); ulIndex++) {
  1618. //
  1619. // See if this node is active.
  1620. //
  1621. ulStatus = 0;
  1622. ulProblemNumber = 0;
  1623. ConfigRet = CM_Get_DevNode_Status(&ulStatus,
  1624. &ulProblemNumber,
  1625. spDevInfoData.DevInst,
  1626. 0);
  1627. if(CR_SUCCESS != ConfigRet){
  1628. DBG_WRN(("CWiaDevMan::EnumDevNodeDevices, On index %d, CM_Get_DevNode_Status returned error, assuming device is inactive", ulIndex));
  1629. }
  1630. //
  1631. // Get device regkey.
  1632. //
  1633. hDevRegKey = SetupDiOpenDevRegKey(m_DeviceInfoSet,
  1634. &spDevInfoData,
  1635. DICS_FLAG_GLOBAL,
  1636. 0,
  1637. DIREG_DRV,
  1638. KEY_READ);
  1639. if(hDevRegKey != INVALID_HANDLE_VALUE) {
  1640. //
  1641. // See if it has "StillImage" in SubClass key.
  1642. //
  1643. if(IsStiRegKey(hDevRegKey)){
  1644. //
  1645. // Get this device name
  1646. //
  1647. cbData = sizeof(wszDeviceID);
  1648. dwError = RegQueryValueExW(hDevRegKey,
  1649. REGSTR_VAL_DEVICE_ID_W,
  1650. NULL,
  1651. NULL,
  1652. (LPBYTE)wszDeviceID,
  1653. &cbData);
  1654. if (dwError == ERROR_SUCCESS) {
  1655. wszDeviceID[STI_MAX_INTERNAL_NAME_LENGTH-1] = L'\0';
  1656. //
  1657. // Check whether we already have the appropriate DEVICE_OBJECT in the list.
  1658. // If we do, find out whether we should generate a connect/disconnect event, else fill
  1659. // out the DeviceInformation struct and create a new DEVICE_OBJECT for it.
  1660. //
  1661. DBG_TRC(("EnumDevNodeDevices, searching for device '%ls' in list",
  1662. wszDeviceID));
  1663. pActiveDevice = IsInList(DEV_MAN_IN_LIST_DEV_ID, wszDeviceID);
  1664. if (pActiveDevice) {
  1665. //
  1666. // Mark this device as active
  1667. //
  1668. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() & ~STIMON_AD_FLAG_MARKED_INACTIVE);
  1669. DWORD dwOldDevState;
  1670. dwOldDevState = pActiveDevice->m_DrvWrapper.getDeviceState();
  1671. //
  1672. // Mark the new device state appropriately
  1673. //
  1674. dwDeviceState = MapCMStatusToDeviceState(dwOldDevState, ulStatus, ulProblemNumber);
  1675. //
  1676. // Update the device information. Certain fields are transient e.g.
  1677. // device state and port name
  1678. //
  1679. RefreshDevInfoFromHKey(pActiveDevice->m_DrvWrapper.getDevInfo(),
  1680. hDevRegKey,
  1681. dwDeviceState,
  1682. &spDevInfoData,
  1683. NULL);
  1684. DBG_TRC(("EnumDevNodeDevices, device '%ls' is in the list, "
  1685. "Old Device State = '%lu', New Device State = %lu",
  1686. wszDeviceID, dwOldDevState, dwDeviceState));
  1687. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  1688. //
  1689. // Check whether its state changed. If it changed
  1690. // from inactive to active, throw connect event. If
  1691. // state changed from active to inactive, throw disconnect event.
  1692. //
  1693. if (((~dwOldDevState) & DEV_STATE_ACTIVE) &&
  1694. (dwDeviceState & DEV_STATE_ACTIVE)) {
  1695. //
  1696. // Load the driver
  1697. //
  1698. pActiveDevice->LoadDriver(TRUE);
  1699. GenerateSafeConnectEvent(pActiveDevice);
  1700. DBG_TRC(("EnumDevNodeDevices, generating SafeConnect Event "
  1701. "for device '%ls'", wszDeviceID));
  1702. } else if ((dwOldDevState & DEV_STATE_ACTIVE) &&
  1703. ((~dwDeviceState) & DEV_STATE_ACTIVE)) {
  1704. DBG_TRC(("EnumDevNodeDevices, generating SafeDisconnect Event "
  1705. "for device '%ls'", wszDeviceID));
  1706. GenerateSafeDisconnectEvent(pActiveDevice);
  1707. pActiveDevice->UnLoadDriver(FALSE);
  1708. }
  1709. }
  1710. //
  1711. // NOTE: In the case when we are not started yet, and the class installer
  1712. // starts us to install a device, certain timing conditions make it so that
  1713. // the device is enumerated on startup, but the device is not registred
  1714. // for PnP notifications like device removal. This is because it is not fully installed
  1715. // yet, so the lookup of the interface name to do a CreateFile on fails.
  1716. // So, to get around that, when the class installer is finished installing,
  1717. // and tells us to reenumerate, we also check whether the device is registered
  1718. // for PnP notifications. If it isn't, we attempt to register. If successful, we
  1719. // generate connect event (since we missed it the first time round)
  1720. //
  1721. if (!pActiveDevice->IsRegisteredForDeviceRemoval() && (dwDeviceState & DEV_STATE_ACTIVE)) {
  1722. //
  1723. // This device is active but is not yet registered. Let's attempt to register it
  1724. //
  1725. if (pActiveDevice->InitPnPNotifications(NULL)) {
  1726. //
  1727. // Successful. So now generate connect event if told to do so
  1728. //
  1729. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  1730. GenerateSafeConnectEvent(pActiveDevice);
  1731. }
  1732. }
  1733. }
  1734. pActiveDevice->Release();
  1735. } else {
  1736. //
  1737. // Create and fill out a DEVICE_INFO structure. For
  1738. //
  1739. dwDeviceState = MapCMStatusToDeviceState(0, ulStatus, ulProblemNumber);
  1740. DBG_TRC(("EnumDevNodeDevices, device '%ls' is NOT in the list, "
  1741. "Device State = %lu", wszDeviceID, dwDeviceState));
  1742. pDevInfo = CreateDevInfoFromHKey(hDevRegKey, dwDeviceState, &spDevInfoData, NULL);
  1743. DumpDevInfo(pDevInfo);
  1744. AddDevice(ulFlags, pDevInfo);
  1745. }
  1746. } else {
  1747. DBG_WRN(("CWiaDevMan::EnumDevNodeDevices, On index %d, could not read DeviceID", ulIndex));
  1748. }
  1749. } else {
  1750. DBG_WRN(("CWiaDevMan::EnumDevNodeDevices, device on index %d is not StillImage", ulIndex));
  1751. }
  1752. //
  1753. // Close the device registry key
  1754. //
  1755. RegCloseKey(hDevRegKey);
  1756. hDevRegKey = NULL;
  1757. } else {
  1758. DBG_WRN(("CWiaDevMan::EnumDevNodeDevices, SetupDiOpenDevRegKey on index %d return INVALID_HANDLE_VALUE", ulIndex));
  1759. }
  1760. }
  1761. return S_OK;
  1762. }
  1763. HRESULT CWiaDevMan::EnumInterfaceDevices(
  1764. ULONG ulFlags)
  1765. {
  1766. HRESULT hr = S_OK; // Notice that none of these errors are fatal. We always return S_OK.
  1767. ULONG ulIndex = 0;
  1768. DWORD dwError = ERROR_SUCCESS;
  1769. DWORD dwFlags = DIGCF_PROFILE;
  1770. CONFIGRET ConfigRet = CR_SUCCESS;
  1771. GUID guidInterface = GUID_DEVCLASS_IMAGE;
  1772. ULONG ulStatus = 0;
  1773. ULONG ulProblemNumber = 0;
  1774. HKEY hDevRegKey = (HKEY)INVALID_HANDLE_VALUE;
  1775. DWORD dwDeviceState = 0;
  1776. DWORD cbData = 0;
  1777. DEVICE_INFO *pDevInfo = NULL;
  1778. ACTIVE_DEVICE *pActiveDevice = NULL;
  1779. DWORD dwDetailDataSize = 0;
  1780. BOOL bSkip = FALSE;
  1781. SP_DEVINFO_DATA spDevInfoData;
  1782. SP_DEVICE_INTERFACE_DATA spDevInterfaceData;
  1783. WCHAR wszDeviceID[STI_MAX_INTERNAL_NAME_LENGTH];
  1784. //
  1785. // Enumerate "devnode" devices.
  1786. //
  1787. spDevInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
  1788. spDevInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
  1789. for (ulIndex = 0; SetupDiEnumDeviceInterfaces(m_DeviceInfoSet, NULL, &guidInterface, ulIndex, &spDevInterfaceData); ulIndex++) {
  1790. dwDeviceState = 0;
  1791. bSkip = FALSE;
  1792. hDevRegKey = SetupDiOpenDeviceInterfaceRegKey(m_DeviceInfoSet,
  1793. &spDevInterfaceData,
  1794. 0,
  1795. KEY_READ);
  1796. if(hDevRegKey != INVALID_HANDLE_VALUE) {
  1797. //
  1798. // See if it has "StillImage" in SubClass key.
  1799. //
  1800. if(IsStiRegKey(hDevRegKey)) {
  1801. //
  1802. // Get this device name
  1803. //
  1804. cbData = sizeof(wszDeviceID);
  1805. dwError = RegQueryValueExW(hDevRegKey,
  1806. REGSTR_VAL_DEVICE_ID_W,
  1807. NULL,
  1808. NULL,
  1809. (LPBYTE)wszDeviceID,
  1810. &cbData);
  1811. if (dwError == ERROR_SUCCESS) {
  1812. //
  1813. // Get devnode which this interface is created on.
  1814. //
  1815. dwError = SetupDiGetDeviceInterfaceDetail(m_DeviceInfoSet,
  1816. &spDevInterfaceData,
  1817. NULL,
  1818. 0,
  1819. NULL,
  1820. &spDevInfoData);
  1821. if(dwError == ERROR_INSUFFICIENT_BUFFER){
  1822. //
  1823. // See if this node is active.
  1824. //
  1825. ulStatus = 0;
  1826. ulProblemNumber = 0;
  1827. ConfigRet = CM_Get_DevNode_Status(&ulStatus,
  1828. &ulProblemNumber,
  1829. spDevInfoData.DevInst,
  1830. 0);
  1831. if(CR_SUCCESS != ConfigRet){
  1832. DBG_WRN(("CWiaDevMan::EnumInterfaceDevices, On index %d, CM_Get_DevNode_Status returned error, assuming device is inactive", ulIndex));
  1833. }
  1834. } else {
  1835. bSkip = TRUE;
  1836. }
  1837. } else {
  1838. DBG_WRN(("CWiaDevMan::EnumInterfaceDevices, device on index %d, could not read DeviceID", ulIndex));
  1839. bSkip = TRUE;
  1840. }
  1841. }else {
  1842. DBG_WRN(("CWiaDevMan::EnumInterfaceDevices, device on index %d, not a StillImage", ulIndex));
  1843. bSkip = TRUE;
  1844. }
  1845. } else {
  1846. DBG_WRN(("CWiaDevMan::EnumInterfaceDevices, SetupDiOpenDeviceInterfaceRegKey on index %d return INVALID_HANDLE_VALUE", ulIndex));
  1847. bSkip = TRUE;
  1848. }
  1849. if (!bSkip) {
  1850. //
  1851. // If we get to here, it means we have a valid StillImage device, it's HKEY, spDevInterfaceData, and spDevInfoData
  1852. //
  1853. wszDeviceID[STI_MAX_INTERNAL_NAME_LENGTH-1] = L'\0';
  1854. //
  1855. // Check whether we already have the appropriate DEVICE_OBJECT in the list.
  1856. // If we do, find out whether we should generate a connect/disconnect event, else fill
  1857. // out the DeviceInformation struct and create a new DEVICE_OBJECT for it.
  1858. //
  1859. pActiveDevice = IsInList(DEV_MAN_IN_LIST_DEV_ID, wszDeviceID);
  1860. if (pActiveDevice) {
  1861. //
  1862. // Mark this device as active
  1863. //
  1864. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() & ~STIMON_AD_FLAG_MARKED_INACTIVE);
  1865. DWORD dwOldDevState;
  1866. dwOldDevState = pActiveDevice->m_DrvWrapper.getDeviceState();
  1867. //
  1868. // Mark the device state appropriately
  1869. //
  1870. dwDeviceState = MapCMStatusToDeviceState(dwOldDevState, ulStatus, ulProblemNumber);
  1871. DBG_TRC(("EnumInterfaceDevices, device '%ls' is in the list, "
  1872. "Old Device State = %lu, New Device State = %lu",
  1873. wszDeviceID, dwOldDevState, dwDeviceState));
  1874. //
  1875. // Update the device information. Certain fields are transient e.g.
  1876. // device state and port name
  1877. //
  1878. RefreshDevInfoFromHKey(pActiveDevice->m_DrvWrapper.getDevInfo(),
  1879. hDevRegKey,
  1880. dwDeviceState,
  1881. &spDevInfoData,
  1882. &spDevInterfaceData);
  1883. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  1884. //
  1885. // Check whether its state changed. If it changed
  1886. // from inactive to active, throw connect event. If
  1887. // state changed from active to inactive, throw disconnect event.
  1888. //
  1889. if (((~dwOldDevState) & DEV_STATE_ACTIVE) &&
  1890. (dwDeviceState & DEV_STATE_ACTIVE)) {
  1891. //
  1892. // Load the driver
  1893. //
  1894. pActiveDevice->LoadDriver(TRUE);
  1895. GenerateSafeConnectEvent(pActiveDevice);
  1896. } else if ((dwOldDevState & DEV_STATE_ACTIVE) &&
  1897. ((~dwDeviceState) & DEV_STATE_ACTIVE)) {
  1898. GenerateSafeDisconnectEvent(pActiveDevice);
  1899. pActiveDevice->UnLoadDriver(FALSE);
  1900. }
  1901. }
  1902. //
  1903. // NOTE: In the case when we are not started yet, and the class installer
  1904. // starts us to install a device, certain timing conditions make it so that
  1905. // the device is enumerated on startup, but the device is not registred
  1906. // for PnP notifications like device removal. This is because it is not fully installed
  1907. // yet, so the lookup of the interface name to do a CreateFile on fails.
  1908. // So, to get around that, when the class installer is finished installing,
  1909. // and tells us to reenumerate, we also check whether the device is registered
  1910. // for PnP notifications. If it isn't, we attempt to register. If successful, we
  1911. // generate connect event (since we missed it the first time round)
  1912. //
  1913. if (!pActiveDevice->IsRegisteredForDeviceRemoval() && (dwDeviceState & DEV_STATE_ACTIVE)) {
  1914. //
  1915. // This device is active but is not yet registered. Let's attempt to register it
  1916. //
  1917. if (pActiveDevice->InitPnPNotifications(NULL)) {
  1918. //
  1919. // Successful. So now generate connect event if told to do so
  1920. //
  1921. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  1922. GenerateSafeConnectEvent(pActiveDevice);
  1923. }
  1924. }
  1925. }
  1926. pActiveDevice->Release();
  1927. } else {
  1928. //
  1929. // Create and fill out a DEVICE_INFO structure. For
  1930. //
  1931. dwDeviceState = MapCMStatusToDeviceState(0, ulStatus, ulProblemNumber);
  1932. DBG_TRC(("EnumInterfaceDevices, device '%ls' is NOT in the list, "
  1933. "Device State = %lu", wszDeviceID, dwDeviceState));
  1934. pDevInfo = CreateDevInfoFromHKey(hDevRegKey, dwDeviceState, &spDevInfoData, &spDevInterfaceData);
  1935. DumpDevInfo(pDevInfo);
  1936. AddDevice(ulFlags, pDevInfo);
  1937. }
  1938. }
  1939. //
  1940. // Close the device registry key
  1941. //
  1942. if (hDevRegKey != INVALID_HANDLE_VALUE) {
  1943. RegCloseKey(hDevRegKey);
  1944. hDevRegKey = NULL;
  1945. }
  1946. }
  1947. return S_OK;
  1948. }
  1949. //
  1950. // Shortcut: for now, we're only going to enum mount points. Maybe, we might want to enumerate
  1951. // volumes, see which are removable media, cdroms etc., then match them up with corresponding
  1952. // mount points.
  1953. //
  1954. HRESULT CWiaDevMan::EnumVolumes(
  1955. ULONG ulFlags)
  1956. {
  1957. HRESULT hr = S_OK;
  1958. IHardwareDevices *pihwdevs = NULL;
  1959. ACTIVE_DEVICE *pActiveDevice = NULL;
  1960. DEVICE_INFO *pDevInfo = NULL;
  1961. hr = CoCreateInstance(CLSID_HardwareDevices,
  1962. NULL,
  1963. CLSCTX_LOCAL_SERVER | CLSCTX_NO_FAILURE_LOG,
  1964. IID_IHardwareDevices,
  1965. (VOID**)&pihwdevs);
  1966. if (SUCCEEDED(hr))
  1967. {
  1968. IHardwareDevicesMountPointsEnum *penum = NULL;
  1969. hr = pihwdevs->EnumMountPoints(&penum);
  1970. if (SUCCEEDED(hr))
  1971. {
  1972. LPWSTR pszMountPoint = NULL;
  1973. LPWSTR pszDeviceIDVolume = NULL;
  1974. while (penum->Next(&pszMountPoint, &pszDeviceIDVolume) == S_OK)
  1975. {
  1976. //
  1977. // Check if this is one of the volumes we "allow". We only
  1978. // allow:
  1979. // Removable drives with
  1980. // Non-securable file system
  1981. //
  1982. if (IsCorrectVolumeType(pszMountPoint)) {
  1983. //
  1984. // Check whether we already have the appropriate DEVICE_OBJECT in the list.
  1985. // If we do, find out whether we should generate a connect/disconnect event, else fill
  1986. // out the DeviceInformation struct and create a new DEVICE_OBJECT for it.
  1987. //
  1988. pActiveDevice = IsInList(DEV_MAN_IN_LIST_ALT_ID, pszMountPoint);
  1989. if (pActiveDevice) {
  1990. // TDB:
  1991. // We'd want to generate a connect/disconnect event for MSC camera
  1992. // Right now, there is no way to tell if it is MSC camera
  1993. // DWORD dwDevState = MapMediaStatusToDeviceState(dwMediaState);
  1994. //
  1995. // Mark this device as active
  1996. //
  1997. pActiveDevice->SetFlags(pActiveDevice->QueryFlags() & ~STIMON_AD_FLAG_MARKED_INACTIVE);
  1998. /*
  1999. DWORD dwOldDevState;
  2000. dwOldDevState = pActiveDevice->m_DrvWrapper.getDeviceState();
  2001. //
  2002. // Update the device information. Certain fields are transient e.g.
  2003. // device state and port name
  2004. //
  2005. RefreshDevInfoFromHKey(pActiveDevice->m_DrvWrapper.getDevInfo(),
  2006. hDevRegKey,
  2007. dwDeviceState,
  2008. &spDevInfoData);
  2009. if (ulFlags & DEV_MAN_GEN_EVENTS) {
  2010. //
  2011. // Check whether its state changed. If it changed
  2012. // from inactive to active, throw connect event. If
  2013. // state changed from active to inactive, throw disconnect event.
  2014. //
  2015. if (((~dwOldDevState) & DEV_STATE_ACTIVE) &&
  2016. (dwDeviceState & DEV_STATE_ACTIVE)) {
  2017. //
  2018. // Load the driver
  2019. //
  2020. //DumpDevInfo(pActiveDevice->m_DrvWrapper.getDevInfo());
  2021. //pActiveDevice->LoadDriver();
  2022. GenerateEventForDevice(&WIA_EVENT_DEVICE_CONNECTED, pActiveDevice);
  2023. } else if ((dwOldDevState & DEV_STATE_ACTIVE) &&
  2024. ((~dwDeviceState) & DEV_STATE_ACTIVE)) {
  2025. GenerateSafeDisconnectEvent(pActiveDevice);
  2026. pActiveDevice->UnLoadDriver(FALSE);
  2027. }
  2028. }
  2029. */
  2030. pActiveDevice->Release();
  2031. } else {
  2032. //
  2033. // Create and fill out a DEVICE_INFO structure. For
  2034. //
  2035. pDevInfo = CreateDevInfoForFSDriver(pszMountPoint);
  2036. DumpDevInfo(pDevInfo);
  2037. AddDevice(ulFlags, pDevInfo);
  2038. }
  2039. }
  2040. if (pszMountPoint) {
  2041. CoTaskMemFree(pszMountPoint);
  2042. pszMountPoint = NULL;
  2043. }
  2044. if (pszDeviceIDVolume) {
  2045. CoTaskMemFree(pszDeviceIDVolume);
  2046. pszDeviceIDVolume = NULL;
  2047. }
  2048. }
  2049. penum->Release();
  2050. }
  2051. pihwdevs->Release();
  2052. } else {
  2053. DBG_WRN(("CWiaDevMan::EnumVolumes, CoCreateInstance on CLSID_HardwareDevices failed"));
  2054. }
  2055. return hr;
  2056. }
  2057. /**************************************************************************\
  2058. * CWiaDevMan::FillRemoteDeviceStgs
  2059. *
  2060. * Enumerate remote devices and create a device info. storage for each
  2061. * remote device we come accross. We don't touch the network here - the
  2062. * remote devices are represented by the appropriate entries in the
  2063. * registry. Only if the calling application calls CreateDevice(..) to
  2064. * talk to the device, do we hit the remote machine.
  2065. *
  2066. * Arguments:
  2067. *
  2068. * ppRemoteDevList - Caller allocated array to store the dev. info.
  2069. * interface pointers.
  2070. * pulDevices - This is an IN/OUT parameter.
  2071. * On entry, this is the maximum number of dev. info.
  2072. * stgs to add to the ppRemoteDevList array.
  2073. * On return, this contains the actual number of dev.
  2074. * info. stgs added to the array.
  2075. *
  2076. * Return Value:
  2077. *
  2078. * Status
  2079. *
  2080. * History:
  2081. *
  2082. * 2/05/2001 Original Version
  2083. *
  2084. \**************************************************************************/
  2085. HRESULT CWiaDevMan::FillRemoteDeviceStgs(
  2086. IWiaPropertyStorage **ppRemoteDevList,
  2087. ULONG *pulDevices)
  2088. {
  2089. DBG_FN(::FillRemoteDeviceStgs);
  2090. HRESULT hr = S_OK;
  2091. //
  2092. // Check parameters
  2093. //
  2094. if (!ppRemoteDevList || !pulDevices) {
  2095. DBG_WRN(("CWiaDevMan::FillRemoteDeviceStgs, NULL parameters are not allowed!"));
  2096. return E_INVALIDARG;
  2097. }
  2098. ULONG ulMaxDevicesToAdd = *pulDevices;
  2099. ULONG ulNumDevices = 0;
  2100. //
  2101. // Enumerate remote devices and create a dev. info. storage for each one we find.
  2102. // We must not add more devices than ppRemoteDevList can hold, and we must set the
  2103. // return value to indicate how many dev. info storages we did actually add.
  2104. //
  2105. //
  2106. // find remote device entry in registry
  2107. //
  2108. LPWSTR szKeyName = REGSTR_PATH_STICONTROL_DEVLIST_W;
  2109. HKEY hKeySetup,hKeyDevice;
  2110. LONG lResult;
  2111. DWORD dwMachineIndex = 0;
  2112. if (RegOpenKeyExW (HKEY_LOCAL_MACHINE,
  2113. szKeyName,
  2114. 0,
  2115. KEY_READ | KEY_WRITE,
  2116. &hKeySetup) == ERROR_SUCCESS) {
  2117. //
  2118. // look for machine names
  2119. //
  2120. WCHAR wszTemp[MAX_PATH+1];
  2121. WCHAR *pwszTempVal = NULL;
  2122. //
  2123. // go through enumeration, open key
  2124. //
  2125. dwMachineIndex = 0;
  2126. do {
  2127. hr = S_OK;
  2128. lResult = RegEnumKeyW(hKeySetup,dwMachineIndex,wszTemp,MAX_PATH+1);
  2129. if (lResult == ERROR_SUCCESS) {
  2130. //
  2131. // Increment the index so we can get the next key on next
  2132. // iteration
  2133. //
  2134. dwMachineIndex++;
  2135. //
  2136. // Paranoid overflow check. If we don't have enough space for
  2137. // this, then break out of the loop.
  2138. //
  2139. if (ulNumDevices >= ulMaxDevicesToAdd) {
  2140. break;
  2141. }
  2142. lResult = RegOpenKeyExW (hKeySetup,
  2143. wszTemp,
  2144. 0,
  2145. KEY_READ | KEY_WRITE,
  2146. &hKeyDevice);
  2147. if (lResult == ERROR_SUCCESS) {
  2148. DEVICE_INFO *pDeviceInfo = NULL;
  2149. //
  2150. // We need to create a Dev. Info. for this remote device. The
  2151. // property storage is created from the DEVICE_INFO struct we
  2152. // create from the remote device registry entry.
  2153. //
  2154. pDeviceInfo = CreateDevInfoForRemoteDevice(hKeyDevice);
  2155. if (pDeviceInfo) {
  2156. ppRemoteDevList[ulNumDevices] = CreateDevInfoStg(pDeviceInfo);
  2157. if (ppRemoteDevList[ulNumDevices]) {
  2158. //
  2159. // We successfully created a dev. info. for this remote device,
  2160. // so increment the returned dev. info. count.
  2161. //
  2162. ulNumDevices++;
  2163. }
  2164. //
  2165. // Cleanup the DEVICE_INFO struct since it's no longer needed
  2166. //
  2167. delete pDeviceInfo;
  2168. pDeviceInfo = NULL;
  2169. }
  2170. RegCloseKey(hKeyDevice);
  2171. hKeyDevice = NULL;
  2172. } else {
  2173. DBG_ERR(("CWiaDevMan::FillRemoteDeviceStgs, failed RegOpenKeyExW, status = %lx",lResult));
  2174. }
  2175. }
  2176. } while (lResult == ERROR_SUCCESS);
  2177. RegCloseKey(hKeySetup);
  2178. }
  2179. *pulDevices = ulNumDevices;
  2180. return hr;
  2181. }
  2182. /**************************************************************************\
  2183. * CWiaDevMan::CountRemoteDevices
  2184. *
  2185. * This method counts the number of remote devices. The remote devices
  2186. * are represented by registry entries in the DevList section under
  2187. * the StillImage key.
  2188. *
  2189. * Arguments:
  2190. *
  2191. * ulFlags - Currently unused
  2192. *
  2193. * Return Value:
  2194. *
  2195. * Number of remote devices.
  2196. *
  2197. * History:
  2198. *
  2199. * 2/05/2001 Original Version
  2200. *
  2201. \**************************************************************************/
  2202. ULONG CWiaDevMan::CountRemoteDevices(
  2203. ULONG ulFlags)
  2204. {
  2205. DBG_FN(::CountRemoteDevices);
  2206. HRESULT hr = S_OK;
  2207. //
  2208. // find remote device entry in registry
  2209. //
  2210. LPWSTR szKeyName = REGSTR_PATH_STICONTROL_DEVLIST_W;
  2211. HKEY hKeyDeviceList;
  2212. LONG lResult;
  2213. DWORD dwNumDevices = 0;
  2214. if (RegOpenKeyExW (HKEY_LOCAL_MACHINE,
  2215. szKeyName,
  2216. 0,
  2217. KEY_READ | KEY_WRITE,
  2218. &hKeyDeviceList) == ERROR_SUCCESS) {
  2219. //
  2220. // Get the number of sub-keys. Since each remote device is stored
  2221. // under a separate key, this will give us the total number of
  2222. // remote devices.
  2223. //
  2224. lResult = RegQueryInfoKey(hKeyDeviceList,
  2225. NULL,
  2226. 0,
  2227. NULL,
  2228. &dwNumDevices,
  2229. NULL,
  2230. NULL,
  2231. NULL,
  2232. NULL,
  2233. NULL,
  2234. NULL,
  2235. NULL);
  2236. RegCloseKey(hKeyDeviceList);
  2237. }
  2238. return dwNumDevices;
  2239. }
  2240. /**************************************************************************\
  2241. * CWiaDevMan::IsCorrectEnumType
  2242. *
  2243. * This function checks whether a given device (represented by pInfo)
  2244. * matches the category of devices specified in the enumeration flags
  2245. * (specified by ulEnumType)
  2246. *
  2247. * This function works on the principle that if the device is of type X, and
  2248. * you didn't ask for X, then it returns FALSE. Else, it returns TRUE.
  2249. *
  2250. * Arguments:
  2251. *
  2252. * ulEnumType - Enumeration flags (see DEV_MAN_ENUM_TYPE_XXXX in header)
  2253. * pInfo - Pointer to DEVICE_INFO
  2254. *
  2255. * Return Value:
  2256. *
  2257. * TRUE - This device falls into the category of devices
  2258. * FALSE - This device does not fall into the category of devices we want
  2259. *
  2260. * History:
  2261. *
  2262. * 11/06/2000 Original Version
  2263. *
  2264. \**************************************************************************/
  2265. BOOL CWiaDevMan::IsCorrectEnumType(
  2266. ULONG ulEnumType,
  2267. DEVICE_INFO *pInfo)
  2268. {
  2269. if (!pInfo) {
  2270. return FALSE;
  2271. }
  2272. // Shortcut - if ulEnumType == ALL_DEVICES return TRUE?
  2273. if (!(pInfo->dwDeviceState & DEV_STATE_ACTIVE) &&
  2274. !(ulEnumType & DEV_MAN_ENUM_TYPE_INACTIVE)) {
  2275. //
  2276. // This device is inactive and caller only wanted active
  2277. //
  2278. return FALSE;
  2279. }
  2280. if (!(pInfo->dwInternalType & INTERNAL_DEV_TYPE_WIA) &&
  2281. !(ulEnumType & DEV_MAN_ENUM_TYPE_STI)) {
  2282. //
  2283. // This is an STI only device, and caller asked for WIA
  2284. //
  2285. return FALSE;
  2286. }
  2287. if (!(ulEnumType & DEV_MAN_ENUM_TYPE_VOL) &&
  2288. (pInfo->dwInternalType & INTERNAL_DEV_TYPE_VOL)) {
  2289. //
  2290. // This is volume device and caller didn't ask to include volume. We
  2291. // first check whether the bMakeVolumesVisible override is set to TRUE,
  2292. // else we don't want it to show up, so we return FALSE.
  2293. //
  2294. if (!m_bMakeVolumesVisible) {
  2295. return FALSE;
  2296. }
  2297. }
  2298. if ((ulEnumType & DEV_MAN_ENUM_TYPE_LOCAL_ONLY) &&
  2299. !(pInfo->dwInternalType & INTERNAL_DEV_TYPE_LOCAL)) {
  2300. //
  2301. // This is remote and asked not to include remote
  2302. //
  2303. return FALSE;
  2304. }
  2305. #ifdef WIA_DISABLE_VIDEO_SUPPORT
  2306. if (GET_STIDEVICE_TYPE(pInfo->DeviceType) == StiDeviceTypeStreamingVideo) {
  2307. //
  2308. // If this SKU of the OS disables WIA Video support, do not
  2309. // enumerate video devices.
  2310. //
  2311. return FALSE;
  2312. }
  2313. #endif
  2314. return TRUE;
  2315. }
  2316. /**************************************************************************\
  2317. * CWiaDevMan::GenerateSafeConnectEvent
  2318. *
  2319. * This function generates a connect event for a device, IFF it has not
  2320. * been generated already.
  2321. *
  2322. * Arguments:
  2323. *
  2324. * pActiveDevice - Indicates which device we want to generate the event
  2325. * for.
  2326. *
  2327. * Return Value:
  2328. *
  2329. * Status
  2330. *
  2331. * History:
  2332. *
  2333. * 01/29/2001 Original Version
  2334. *
  2335. \**************************************************************************/
  2336. HRESULT CWiaDevMan::GenerateSafeConnectEvent(
  2337. ACTIVE_DEVICE *pActiveDevice)
  2338. {
  2339. HRESULT hr = S_OK;
  2340. if (pActiveDevice) {
  2341. //
  2342. // Check whether we have already thrown a connect event for the
  2343. // device. We don't want to throw it twice, so only throw it if
  2344. // the connect event state shows it hasn't been done yet.
  2345. //
  2346. if (!pActiveDevice->m_DrvWrapper.wasConnectEventThrown()) {
  2347. DBG_PRT(("CWiaDevMan::GenerateSafeConnectEvent, generating event for device (%ws)", pActiveDevice->GetDeviceID()));
  2348. //
  2349. // Generate the connect event
  2350. //
  2351. hr = GenerateEventForDevice(&WIA_EVENT_DEVICE_CONNECTED, pActiveDevice);
  2352. if (SUCCEEDED(hr)) {
  2353. //
  2354. // Mark that the event was generated
  2355. //
  2356. pActiveDevice->m_DrvWrapper.setConnectEventState(TRUE);
  2357. } else {
  2358. DBG_WRN(("CWiaDevMan::GenerateSafeConnectEvent, could not generate connect event for device (%ws)",
  2359. pActiveDevice->GetDeviceID()));
  2360. }
  2361. }
  2362. } else {
  2363. DBG_WRN(("CWiaDevMan::GenerateSafeConnectEvent, called with NULL parameter, ignoring request..."));
  2364. }
  2365. return hr;
  2366. }
  2367. /**************************************************************************\
  2368. * CWiaDevMan::GenerateSafeDisconnectEvent
  2369. *
  2370. * This function generates a disconnect event for a device, and clears the
  2371. * connect event flag set by GenerateSafeConnectEvent(...).
  2372. *
  2373. * Arguments:
  2374. *
  2375. * pActiveDevice - Indicates which device we want to generate the event
  2376. * for.
  2377. *
  2378. * Return Value:
  2379. *
  2380. * Status
  2381. *
  2382. * History:
  2383. *
  2384. * 01/29/2001 Original Version
  2385. *
  2386. \**************************************************************************/
  2387. HRESULT CWiaDevMan::GenerateSafeDisconnectEvent(
  2388. ACTIVE_DEVICE *pActiveDevice)
  2389. {
  2390. HRESULT hr = S_OK;
  2391. if (pActiveDevice) {
  2392. //
  2393. // Check the connect event flag for the device. We only want to
  2394. // throw the disconnect event if this bit is set, so it
  2395. // prevents us from throwing it twice.
  2396. //
  2397. if (pActiveDevice->m_DrvWrapper.wasConnectEventThrown()) {
  2398. DBG_PRT(("CWiaDevMan::GenerateSafeDisconnectEvent, generating event for device (%ws)", pActiveDevice->GetDeviceID()));
  2399. //
  2400. // Generate the disconnect event
  2401. //
  2402. hr = GenerateEventForDevice(&WIA_EVENT_DEVICE_DISCONNECTED, pActiveDevice);
  2403. //
  2404. // Whether we succeeded or not, clear the Connect Event State
  2405. //
  2406. pActiveDevice->m_DrvWrapper.setConnectEventState(FALSE);
  2407. }
  2408. } else {
  2409. DBG_WRN(("CWiaDevMan::GenerateSafeDisconnectEvent, called with NULL parameter, ignoring request..."));
  2410. }
  2411. return hr;
  2412. }
  2413. HKEY CWiaDevMan::GetHKeyFromMountPoint(WCHAR *wszMountPoint)
  2414. {
  2415. HKEY hDevRegKey = NULL;
  2416. DWORD dwError = 0;
  2417. DWORD dwDisposition = 0;
  2418. WCHAR wszKeyPath[MAX_PATH * 2];
  2419. if (!wszMountPoint) {
  2420. return NULL;
  2421. }
  2422. //
  2423. // Create the sub-key name. It will be something like:
  2424. // System\CurrentControlSet\Control\StillImage\MSCDeviceList\F:
  2425. //
  2426. lstrcpynW(wszKeyPath, REGSTR_PATH_WIA_MSCDEVICES_W, sizeof(wszKeyPath) / sizeof(wszKeyPath[0]));
  2427. lstrcpynW(wszKeyPath + lstrlenW(wszKeyPath), L"\\", sizeof(wszKeyPath) / sizeof(wszKeyPath[0]) - lstrlenW(wszKeyPath));
  2428. if (lstrlenW(wszMountPoint) < (int)((sizeof(wszKeyPath) / sizeof(wszKeyPath[0]) - lstrlenW(wszKeyPath)))) {
  2429. lstrcatW(wszKeyPath, wszMountPoint);
  2430. //
  2431. // Strip off the \ at the end of the mount point
  2432. //
  2433. wszKeyPath[lstrlenW(wszKeyPath) - 1] = L'\0';
  2434. } else {
  2435. dwError = ERROR_BAD_ARGUMENTS;
  2436. DBG_WRN(("CWiaDevMan::GetHKeyFromMountPoint, bad parameters, returning NULL for HKEY"));
  2437. return NULL;
  2438. }
  2439. //
  2440. // Since this is a MSC device, we don't have normal device registry key.
  2441. // So, we create a "fake" set of entries in a known place, and use those
  2442. // to store the relevant info for MSC devices. This is used mainly to
  2443. // store the user's event settings.
  2444. //
  2445. dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
  2446. wszKeyPath,
  2447. 0,
  2448. NULL,
  2449. REG_OPTION_NON_VOLATILE,
  2450. KEY_ALL_ACCESS,
  2451. NULL,
  2452. &hDevRegKey,
  2453. &dwDisposition);
  2454. if (dwError == ERROR_SUCCESS) {
  2455. if (dwDisposition == REG_CREATED_NEW_KEY) {
  2456. //
  2457. // This is a newly created key, so we have to fill in the
  2458. // relevant entries.
  2459. //
  2460. HRESULT hr = S_OK;
  2461. hr = CreateMSCRegEntries(hDevRegKey, wszMountPoint);
  2462. }
  2463. } else {
  2464. DBG_WRN(("CWiaDevMan::GetHKeyFromMountPoint, RegCreateKeyExW on (%ws) failed!", wszKeyPath));
  2465. }
  2466. return hDevRegKey;
  2467. }
  2468. HKEY CWiaDevMan::GetHKeyFromDevInfoData(SP_DEVINFO_DATA *pspDevInfoData)
  2469. {
  2470. HKEY hDevRegKey = NULL;
  2471. //
  2472. // Get device regkey.
  2473. //
  2474. if (pspDevInfoData) {
  2475. hDevRegKey = SetupDiOpenDevRegKey(m_DeviceInfoSet,
  2476. pspDevInfoData,
  2477. DICS_FLAG_GLOBAL,
  2478. 0,
  2479. DIREG_DRV,
  2480. KEY_READ | KEY_WRITE);
  2481. if(hDevRegKey == INVALID_HANDLE_VALUE){
  2482. hDevRegKey = SetupDiOpenDevRegKey(m_DeviceInfoSet,
  2483. pspDevInfoData,
  2484. DICS_FLAG_GLOBAL,
  2485. 0,
  2486. DIREG_DRV,
  2487. KEY_READ);
  2488. if(hDevRegKey == INVALID_HANDLE_VALUE){
  2489. DBG_WRN(("CWiaDevMan::GetHKeyFromDevInfoData, SetupDiOpenDevRegKey returned INVALID_HANDLE_VALUE"));
  2490. hDevRegKey = NULL;
  2491. }
  2492. }
  2493. }
  2494. return hDevRegKey;
  2495. }
  2496. HKEY CWiaDevMan::GetHKeyFromDevInterfaceData(SP_DEVICE_INTERFACE_DATA *pspDevInterfaceData)
  2497. {
  2498. HKEY hDevRegKey = NULL;
  2499. //
  2500. // Get device regkey using interface data
  2501. //
  2502. if (pspDevInterfaceData) {
  2503. hDevRegKey = SetupDiOpenDeviceInterfaceRegKey(m_DeviceInfoSet,
  2504. pspDevInterfaceData,
  2505. 0,
  2506. KEY_READ | KEY_WRITE);
  2507. if(hDevRegKey == INVALID_HANDLE_VALUE){
  2508. hDevRegKey = SetupDiOpenDeviceInterfaceRegKey(m_DeviceInfoSet,
  2509. pspDevInterfaceData,
  2510. 0,
  2511. KEY_READ);
  2512. if(hDevRegKey == INVALID_HANDLE_VALUE){
  2513. DBG_WRN(("CWiaDevMan::GetHKeyFromDevInterfaceData, SetupDiOpenDevRegKey returned INVALID_HANDLE_VALUE"));
  2514. hDevRegKey = NULL;
  2515. }
  2516. }
  2517. }
  2518. return hDevRegKey;
  2519. }
  2520. HKEY CWiaDevMan::GetDeviceHKey(
  2521. WCHAR *wszDeviceID,
  2522. WCHAR *wszSubKeyName)
  2523. {
  2524. TAKE_CRIT_SECT tcs(m_csDevList);
  2525. ACTIVE_DEVICE *pActiveDevice = NULL;
  2526. HKEY hKey = NULL;
  2527. pActiveDevice = IsInList(DEV_MAN_IN_LIST_DEV_ID, wszDeviceID);
  2528. if (pActiveDevice) {
  2529. hKey = GetDeviceHKey(pActiveDevice, wszSubKeyName);
  2530. //
  2531. // Release the active device since it was addref'd by IsInList
  2532. //
  2533. pActiveDevice->Release();
  2534. }
  2535. if (!IsValidHANDLE(hKey)) {
  2536. DBG_TRC(("CWiaDevMan::GetDeviceHKey (name), Key not found for (%ws), returning NULL", wszDeviceID));
  2537. }
  2538. return hKey;
  2539. }
  2540. HKEY CWiaDevMan::GetDeviceHKey(
  2541. ACTIVE_DEVICE *pActiveDevice,
  2542. WCHAR *wszSubKeyName)
  2543. {
  2544. DEVICE_INFO *pDevInfo = NULL;
  2545. HKEY hKeyTemp = NULL;
  2546. HKEY hKey = NULL;
  2547. DWORD dwRet = 0;
  2548. if (pActiveDevice) {
  2549. //
  2550. // Get the device's HKEY
  2551. //
  2552. pDevInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
  2553. if (pDevInfo) {
  2554. //
  2555. // If it's a volume device i.e. normal MSC like a card reader,
  2556. // then we don't have a Device HKEY, so skip this.
  2557. //
  2558. if (!(pDevInfo->dwInternalType & INTERNAL_DEV_TYPE_VOL)) {
  2559. //
  2560. // We have 3 cases: 1, it's a MSC camera
  2561. // 2, it's a normal DevNode device
  2562. // 3, it's an interface device
  2563. //
  2564. if (pDevInfo->dwInternalType & INTERNAL_DEV_TYPE_MSC_CAMERA) {
  2565. hKeyTemp = GetHKeyFromMountPoint(pDevInfo->wszAlternateID);
  2566. } else if (pDevInfo->dwInternalType & INTERNAL_DEV_TYPE_INTERFACE) {
  2567. hKeyTemp = GetHKeyFromDevInterfaceData(&pDevInfo->spDevInterfaceData);
  2568. } else {
  2569. hKeyTemp = GetHKeyFromDevInfoData(&pDevInfo->spDevInfoData);
  2570. }
  2571. }
  2572. //
  2573. // Set the return. Note that hKey may be over written with the subkey later on
  2574. //
  2575. hKey = hKeyTemp;
  2576. }
  2577. //
  2578. // If asked, get the subkey instead
  2579. //
  2580. if (wszSubKeyName) {
  2581. //
  2582. // Check that we have a valid device registry key first
  2583. //
  2584. if (IsValidHANDLE(hKeyTemp)) {
  2585. dwRet = RegCreateKeyExW(hKeyTemp,
  2586. wszSubKeyName,
  2587. NULL,
  2588. NULL,
  2589. REG_OPTION_NON_VOLATILE,
  2590. KEY_READ | KEY_WRITE,
  2591. NULL,
  2592. &hKey,
  2593. NULL);
  2594. if (dwRet != ERROR_SUCCESS) {
  2595. dwRet = RegCreateKeyExW(hKeyTemp,
  2596. wszSubKeyName,
  2597. NULL,
  2598. NULL,
  2599. REG_OPTION_NON_VOLATILE,
  2600. KEY_READ,
  2601. NULL,
  2602. &hKey,
  2603. NULL);
  2604. if (dwRet != ERROR_SUCCESS) {
  2605. hKey = NULL;
  2606. }
  2607. }
  2608. //
  2609. // Close the device registry key, we will be returning the sub-key instead
  2610. //
  2611. RegCloseKey(hKeyTemp);
  2612. }
  2613. }
  2614. }
  2615. if (!IsValidHANDLE(hKey)) {
  2616. DBG_TRC(("CWiaDevMan::GetDeviceHKey, Key not found for (%ws), returning NULL", pActiveDevice->GetDeviceID()));
  2617. }
  2618. return hKey;
  2619. }
  2620. HRESULT CWiaDevMan::UpdateDeviceRegistry(
  2621. DEVICE_INFO *pDevInfo)
  2622. {
  2623. HRESULT hr = S_OK;
  2624. HKEY hDevRegKey = NULL;
  2625. HKEY hKeyDevData = NULL;
  2626. if (!pDevInfo) {
  2627. return E_INVALIDARG;
  2628. }
  2629. //
  2630. // Grab the device's HKey
  2631. //
  2632. hDevRegKey = GetDeviceHKey(pDevInfo->wszDeviceInternalName, NULL);
  2633. if (IsValidHANDLE(hDevRegKey)) {
  2634. //
  2635. // Write any properties that may have changed. So far, we only allow updating of:
  2636. // Friendly name
  2637. // Port name
  2638. // BaudRate
  2639. //
  2640. DWORD dwRet = 0;
  2641. DWORD dwType = REG_SZ;
  2642. DWORD dwSize = 0;
  2643. //
  2644. // These properties are written to the device registry key
  2645. //
  2646. if (pDevInfo->wszLocalName) {
  2647. dwType = REG_SZ;
  2648. dwSize = (lstrlenW(pDevInfo->wszLocalName) + 1) * sizeof(WCHAR);
  2649. dwRet = RegSetValueExW(hDevRegKey,
  2650. REGSTR_VAL_FRIENDLY_NAME_W,
  2651. 0,
  2652. dwType,
  2653. (LPBYTE) pDevInfo->wszLocalName,
  2654. dwSize);
  2655. if (dwRet != ERROR_SUCCESS) {
  2656. DBG_WRN(("CWiaDevMan::UpdateDeviceRegistry, error updating %ws for device %ws", REGSTR_VAL_FRIENDLY_NAME_W, pDevInfo->wszDeviceInternalName));
  2657. }
  2658. }
  2659. if (pDevInfo->wszPortName) {
  2660. dwType = REG_SZ;
  2661. dwSize = (lstrlenW(pDevInfo->wszPortName) + 1) * sizeof(WCHAR);
  2662. dwRet = RegSetValueExW(hDevRegKey,
  2663. REGSTR_VAL_DEVICEPORT_W,
  2664. 0,
  2665. dwType,
  2666. (LPBYTE) pDevInfo->wszPortName,
  2667. dwSize);
  2668. if (dwRet != ERROR_SUCCESS) {
  2669. DBG_WRN(("CWiaDevMan::UpdateDeviceRegistry, error updating %ws for device %ws", REGSTR_VAL_DEVICEPORT_W, pDevInfo->wszDeviceInternalName));
  2670. }
  2671. }
  2672. //
  2673. // These properties are written to the device data registry key. Since we
  2674. // only have the device registry key open, we have to open the device data
  2675. // data key for these properties
  2676. //
  2677. dwRet = RegCreateKeyExW(hDevRegKey, REGSTR_VAL_DATA_W, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  2678. NULL, &hKeyDevData, NULL);
  2679. if (IsValidHANDLE(hKeyDevData)) {
  2680. if (pDevInfo->wszBaudRate) {
  2681. dwType = REG_SZ;
  2682. dwSize = (lstrlenW(pDevInfo->wszBaudRate) + 1) * sizeof(WCHAR);
  2683. dwRet = RegSetValueExW(hKeyDevData,
  2684. REGSTR_VAL_BAUDRATE,
  2685. 0,
  2686. dwType,
  2687. (LPBYTE) pDevInfo->wszBaudRate,
  2688. dwSize);
  2689. if (dwRet != ERROR_SUCCESS) {
  2690. DBG_WRN(("CWiaDevMan::UpdateDeviceRegistry, error updating %ws for device %ws", REGSTR_VAL_DEVICEPORT_W, pDevInfo->wszDeviceInternalName));
  2691. }
  2692. }
  2693. } else {
  2694. DBG_TRC(("CWiaDevMan::UpdateDeviceRegistry, could not find device data section in registry for %ws", pDevInfo->wszDeviceInternalName));
  2695. hr = E_INVALIDARG;
  2696. }
  2697. } else {
  2698. DBG_TRC(("CWiaDevMan::UpdateDeviceRegistry, could not find device registry key for %ws", pDevInfo->wszDeviceInternalName));
  2699. hr = E_INVALIDARG;
  2700. }
  2701. //
  2702. // Close the registry keys
  2703. //
  2704. if (IsValidHANDLE(hDevRegKey)) {
  2705. RegCloseKey(hDevRegKey);
  2706. }
  2707. if (IsValidHANDLE(hKeyDevData)) {
  2708. RegCloseKey(hKeyDevData);
  2709. }
  2710. return hr;
  2711. }
  2712. VOID CWiaDevMan::UnloadAllDrivers(
  2713. BOOL bForceUnload,
  2714. BOOL bGenEvents)
  2715. {
  2716. TAKE_CRIT_SECT tcs(m_csDevList);
  2717. //
  2718. // Walk list and unload all drivers.
  2719. //
  2720. //
  2721. // Walk through list of devices
  2722. //
  2723. LIST_ENTRY *pentry = NULL;
  2724. LIST_ENTRY *pentryNext = NULL;
  2725. ACTIVE_DEVICE *pActiveDevice = NULL;
  2726. {
  2727. //
  2728. // For each device in list, call the UnLoadDriver(...) method
  2729. //
  2730. for ( pentry = m_leDeviceListHead.Flink; pentry != &m_leDeviceListHead; pentry = pentryNext ) {
  2731. pentryNext = pentry->Flink;
  2732. pActiveDevice = CONTAINING_RECORD( pentry, ACTIVE_DEVICE,m_ListEntry );
  2733. //
  2734. // If asked, make sure we send out disconnect event, only for WIA devices
  2735. //
  2736. if (bGenEvents && pActiveDevice->m_DrvWrapper.IsWiaDevice()) {
  2737. //
  2738. // Only throw disconnect events for devices that are active
  2739. //
  2740. if (pActiveDevice->m_DrvWrapper.getDeviceState() & DEV_STATE_ACTIVE) {
  2741. GenerateSafeDisconnectEvent(pActiveDevice);
  2742. }
  2743. }
  2744. ProcessDeviceRemoval(pActiveDevice, TRUE);
  2745. }
  2746. }
  2747. }
  2748. void CALLBACK CWiaDevMan::ShellHWEventAPCProc(ULONG_PTR ulpParam)
  2749. {
  2750. SHHARDWAREEVENT *pShellHWEvent = (SHHARDWAREEVENT*)ulpParam;
  2751. CWiaDevMan *pDevMan = g_pDevMan;
  2752. if (!pShellHWEvent || !pDevMan) {
  2753. return;
  2754. }
  2755. switch (pShellHWEvent->dwEvent)
  2756. {
  2757. case SHHARDWAREEVENT_MOUNTPOINTARRIVED:
  2758. {
  2759. DBG_PRT(("MOUNTPOINTARRIVED"));
  2760. TAKE_CRIT_SECT tcs(pDevMan->m_csDevList);
  2761. //
  2762. // ReEnumerate volumes
  2763. //
  2764. pDevMan->EnumVolumes(DEV_MAN_GEN_EVENTS);
  2765. break;
  2766. }
  2767. case SHHARDWAREEVENT_MOUNTPOINTREMOVED:
  2768. {
  2769. DBG_PRT(("MOUNTPOINTREMOVED"));
  2770. LPCWSTR pszMountPoint = (LPCWSTR)(&(pShellHWEvent->rgbPayLoad)); // Do we need to worry about alignment?
  2771. TAKE_CRIT_SECT tcs(pDevMan->m_csDevList);
  2772. //
  2773. // If volume devices are enabled, then remove this mount point
  2774. //
  2775. if (pDevMan->VolumesAreEnabled()) {
  2776. ACTIVE_DEVICE *pActiveDevice;
  2777. pActiveDevice = pDevMan->IsInList(DEV_MAN_IN_LIST_ALT_ID, pszMountPoint);
  2778. if (pActiveDevice) {
  2779. pDevMan->RemoveDevice(pActiveDevice);
  2780. pActiveDevice->Release();
  2781. }
  2782. }
  2783. break;
  2784. }
  2785. case SHHARDWAREEVENT_VOLUMEARRIVED:
  2786. case SHHARDWAREEVENT_VOLUMEUPDATED:
  2787. case SHHARDWAREEVENT_VOLUMEREMOVED:
  2788. case SHHARDWAREEVENT_MOUNTDEVICEARRIVED:
  2789. case SHHARDWAREEVENT_MOUNTDEVICEUPDATED:
  2790. case SHHARDWAREEVENT_MOUNTDEVICEREMOVED:
  2791. default:
  2792. {
  2793. DBG_PRT(("DEFAULT_EVENT"));
  2794. TAKE_CRIT_SECT tcs(pDevMan->m_csDevList);
  2795. //
  2796. // ReEnumerate volumes
  2797. //
  2798. pDevMan->EnumVolumes(DEV_MAN_GEN_EVENTS);
  2799. }
  2800. break;
  2801. }
  2802. //
  2803. // Notice that it's a VirtualFree!
  2804. //
  2805. VirtualFree((void*)ulpParam, 0, MEM_RELEASE);
  2806. }