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.

2509 lines
67 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation
  3. Module Name:
  4. machine.cpp
  5. Abstract:
  6. This module implements CDevInfoList, CMachine and CMachineList
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "devmgr.h"
  12. extern "C" {
  13. #include <initguid.h>
  14. #include <dbt.h>
  15. #include <devguid.h>
  16. #include <wdmguid.h>
  17. }
  18. CONST TCHAR* DEVMGR_NOTIFY_CLASS_NAME = TEXT("DevMgrNotifyClass");
  19. CONST TCHAR* DEVMGR_REFRESH_MSG = TEXT("DevMgrRefreshOn");
  20. //
  21. // The constant is the size we use to allocate GUID list from within
  22. // stack when we have to build a GUID list. The aim of this is
  23. // that buiding a guid list take time and in many case, a minimum
  24. // buffer should retrive all of them. We do not want to get
  25. // the size first, allocate buffer and get it again.
  26. // 64 looks to be fair enough value because there are not
  27. // many classes out there today (and maybe, in the future).
  28. //
  29. const int GUID_LIST_INIT_SIZE = 64;
  30. //
  31. // CDevInfoList implementation
  32. //
  33. BOOL
  34. CDevInfoList::DiGetExtensionPropSheetPage(
  35. PSP_DEVINFO_DATA DevData,
  36. LPFNADDPROPSHEETPAGE pfnAddPropSheetPage,
  37. DWORD PageType,
  38. LPARAM lParam
  39. )
  40. {
  41. SP_PROPSHEETPAGE_REQUEST PropPageRequest;
  42. LPFNADDPROPSHEETPAGES AddPropPages;
  43. PropPageRequest.cbSize = sizeof(PropPageRequest);
  44. PropPageRequest.PageRequested = PageType;
  45. PropPageRequest.DeviceInfoSet = m_hDevInfo;
  46. PropPageRequest.DeviceInfoData = DevData;
  47. if (SPPSR_SELECT_DEVICE_RESOURCES == PageType) {
  48. HINSTANCE hModule = ::GetModuleHandle(TEXT("setupapi.dll"));
  49. if (hModule) {
  50. AddPropPages = (LPFNADDPROPSHEETPAGES)GetProcAddress(hModule, "ExtensionPropSheetPageProc");
  51. if (AddPropPages) {
  52. if (AddPropPages(&PropPageRequest, pfnAddPropSheetPage, lParam)) {
  53. return TRUE;
  54. }
  55. }
  56. }
  57. }
  58. return FALSE;
  59. }
  60. BOOL
  61. CDevInfoList::InstallDevInst(
  62. HWND hwndParent,
  63. LPCTSTR DeviceId,
  64. BOOL UpdateDriver,
  65. DWORD* pReboot
  66. )
  67. {
  68. BOOL Result = FALSE;
  69. HINSTANCE hLib = LoadLibrary(TEXT("newdev.dll"));
  70. LPFNINSTALLDEVINST InstallDevInst;
  71. DWORD Status = ERROR_SUCCESS;
  72. if (hLib) {
  73. InstallDevInst = (LPFNINSTALLDEVINST)GetProcAddress(hLib, "InstallDevInst");
  74. if (InstallDevInst) {
  75. Result = (*InstallDevInst)(hwndParent, DeviceId, UpdateDriver,
  76. pReboot);
  77. Status = GetLastError();
  78. }
  79. FreeLibrary(hLib);
  80. }
  81. //
  82. // We need to put back the error code that was set by newdev.dll's InstallDevInst
  83. // API. This last error gets overwritten by FreeLibrary which we don't care about.
  84. //
  85. SetLastError(Status);
  86. return Result;
  87. }
  88. BOOL
  89. CDevInfoList::RollbackDriver(
  90. HWND hwndParent,
  91. LPCTSTR RegistryKeyName,
  92. DWORD Flags,
  93. DWORD* pReboot
  94. )
  95. {
  96. BOOL Result = FALSE;
  97. HINSTANCE hLib = LoadLibrary(TEXT("newdev.dll"));
  98. LPFNROLLBACKDRIVER RollbackDriver;
  99. if (hLib) {
  100. RollbackDriver = (LPFNROLLBACKDRIVER)GetProcAddress(hLib, "RollbackDriver");
  101. if (RollbackDriver) {
  102. Result = (*RollbackDriver)(hwndParent, RegistryKeyName, Flags, pReboot);
  103. }
  104. FreeLibrary(hLib);
  105. }
  106. return Result;
  107. }
  108. DWORD
  109. CDevInfoList::DiGetFlags(
  110. PSP_DEVINFO_DATA DevData
  111. )
  112. {
  113. SP_DEVINSTALL_PARAMS dip;
  114. dip.cbSize = sizeof(dip);
  115. if (DiGetDeviceInstallParams(DevData, &dip)) {
  116. return dip.Flags;
  117. }
  118. return 0;
  119. }
  120. DWORD
  121. CDevInfoList::DiGetExFlags(
  122. PSP_DEVINFO_DATA DevData
  123. )
  124. {
  125. SP_DEVINSTALL_PARAMS dip;
  126. dip.cbSize = sizeof(dip);
  127. if (DiGetDeviceInstallParams(DevData, &dip)) {
  128. return dip.FlagsEx;
  129. }
  130. return 0;
  131. }
  132. BOOL
  133. CDevInfoList::DiTurnOnDiFlags(
  134. PSP_DEVINFO_DATA DevData,
  135. DWORD FlagsMask
  136. )
  137. {
  138. SP_DEVINSTALL_PARAMS dip;
  139. dip.cbSize = sizeof(dip);
  140. if (DiGetDeviceInstallParams(DevData, &dip)) {
  141. dip.Flags |= FlagsMask;
  142. return DiSetDeviceInstallParams(DevData, &dip);
  143. }
  144. return FALSE;
  145. }
  146. BOOL
  147. CDevInfoList::DiTurnOffDiFlags(
  148. PSP_DEVINFO_DATA DevData,
  149. DWORD FlagsMask
  150. )
  151. {
  152. SP_DEVINSTALL_PARAMS dip;
  153. dip.cbSize = sizeof(dip);
  154. if (DiGetDeviceInstallParams(DevData, &dip)) {
  155. dip.Flags &= ~FlagsMask;
  156. return DiSetDeviceInstallParams(DevData, &dip);
  157. }
  158. return FALSE;
  159. }
  160. BOOL
  161. CDevInfoList::DiTurnOnDiExFlags(
  162. PSP_DEVINFO_DATA DevData,
  163. DWORD FlagsMask
  164. )
  165. {
  166. SP_DEVINSTALL_PARAMS dip;
  167. dip.cbSize = sizeof(dip);
  168. if (DiGetDeviceInstallParams(DevData, &dip)) {
  169. dip.FlagsEx |= FlagsMask;
  170. return DiSetDeviceInstallParams(DevData, &dip);
  171. }
  172. return FALSE;
  173. }
  174. BOOL
  175. CDevInfoList::DiTurnOffDiExFlags(
  176. PSP_DEVINFO_DATA DevData,
  177. DWORD FlagsMask
  178. )
  179. {
  180. SP_DEVINSTALL_PARAMS dip;
  181. dip.cbSize = sizeof(dip);
  182. if (DiGetDeviceInstallParams(DevData, &dip)) {
  183. dip.FlagsEx &= ~FlagsMask;
  184. return DiSetDeviceInstallParams(DevData, &dip);
  185. }
  186. return FALSE;
  187. }
  188. void
  189. CDevInfoList::DiDestroyDeviceInfoList()
  190. {
  191. if (INVALID_HANDLE_VALUE != m_hDevInfo) {
  192. SetupDiDestroyDeviceInfoList(m_hDevInfo);
  193. m_hDevInfo = INVALID_HANDLE_VALUE;
  194. }
  195. }
  196. /////////////////////////////////////////////////////////////////////
  197. //// CMachine implementation
  198. ////
  199. //
  200. // For every single instance of DevMgr.dll, we maintain a CMachine list
  201. // from which different instances of IComponentData(and IComponent) will
  202. // attach to. The objects created(CDevice, Class, HDEVINFO and etc) are
  203. // shared by all the attached IComponentData and IComponent(the implementation
  204. // use CFolder as the controlling identify).
  205. // Everything changed to the CMachine or one of its object will inform
  206. // all the attached CFolders which would pass the information down to their
  207. // sub-objects(CResultView).
  208. // Imaging that you have two Device Manager window in the same console
  209. // and you do a refresh on one the window. The other window must also
  210. // do a refresh after the first one is done. Since both windows shares
  211. // the same machine(and will get the same notification when machine states
  212. // changed), we can keep the two windows in sync.
  213. /////////////////////////////////////////////////////////////////////
  214. CMachine::CMachine(
  215. LPCTSTR pMachineName
  216. )
  217. {
  218. InitializeCriticalSection(&m_CriticalSection);
  219. InitializeCriticalSection(&m_PropertySheetCriticalSection);
  220. InitializeCriticalSection(&m_ChildMachineCriticalSection);
  221. //
  222. // Get various privilege levels, like if the user is an administrator
  223. // or if the user is a Guest.
  224. //
  225. g_IsAdmin = pSetupIsUserAdmin();
  226. m_UserIsAGuest = SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_GUESTS);
  227. m_RefreshDisableCounter = 0;
  228. m_RefreshPending = FALSE;
  229. m_pComputer = NULL;
  230. m_hMachine = NULL;
  231. m_ParentMachine = NULL;
  232. m_Initialized = FALSE;
  233. TCHAR LocalName[MAX_PATH + 1];
  234. DWORD dwSize = ARRAYLEN(LocalName);
  235. if (!GetComputerName(LocalName, &dwSize)) {
  236. LocalName[0] = _T('\0');
  237. }
  238. m_strMachineFullName.Empty();
  239. m_strMachineDisplayName.Empty();
  240. if (pMachineName && _T('\0') != *pMachineName) {
  241. if ((_T('\\') == pMachineName[0]) && (_T('\\') == pMachineName[1])) {
  242. m_strMachineDisplayName = &pMachineName[2];
  243. m_strMachineFullName = pMachineName;
  244. } else {
  245. m_strMachineDisplayName = pMachineName;
  246. m_strMachineFullName = TEXT("\\\\");
  247. m_strMachineFullName+=pMachineName;
  248. }
  249. m_IsLocal = (0 == m_strMachineDisplayName.CompareNoCase(LocalName));
  250. }
  251. else {
  252. //
  253. // Local machine
  254. //
  255. m_strMachineDisplayName = LocalName;
  256. m_strMachineFullName = TEXT("\\\\") + m_strMachineDisplayName;
  257. m_IsLocal = TRUE;
  258. }
  259. m_hwndNotify = NULL;
  260. m_msgRefresh = 0;
  261. m_ShowNonPresentDevices = FALSE;
  262. m_PropertySheetShoudDestroy = FALSE;
  263. TCHAR Buffer[MAX_PATH];
  264. DWORD BufferLen;
  265. //
  266. // If the environment variable DEVMGR_SHOW_NONPRESENT_DEVICES does exist and it
  267. // is not 0 then we will show Phantom devices.
  268. //
  269. if (((BufferLen = ::GetEnvironmentVariable(TEXT("DEVMGR_SHOW_NONPRESENT_DEVICES"),
  270. Buffer,
  271. ARRAYLEN(Buffer))) != 0) &&
  272. ((BufferLen > 1) ||
  273. (lstrcmp(Buffer, TEXT("0"))))) {
  274. m_ShowNonPresentDevices = TRUE;
  275. }
  276. }
  277. BOOL
  278. CMachine::Initialize(
  279. IN HWND hwndParent,
  280. IN LPCTSTR DeviceId, OPTIONAL
  281. IN LPGUID ClassGuid OPTIONAL
  282. )
  283. {
  284. BOOL Result = TRUE;
  285. m_hwndParent = hwndParent;
  286. if (DeviceId && _T('\0') == *DeviceId) {
  287. DeviceId = NULL;
  288. }
  289. HCURSOR hCursorOld;
  290. hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  291. if (DeviceId || ClassGuid) {
  292. if (m_Initialized) {
  293. return TRUE;
  294. }
  295. if (CreateClassesAndDevices(DeviceId, ClassGuid)) {
  296. m_Initialized = TRUE;
  297. }
  298. } else {
  299. if (m_Initialized && m_hwndNotify && IsWindow(m_hwndNotify)) {
  300. return TRUE;
  301. }
  302. //
  303. // We are ready for device change notification, create the notify window
  304. //
  305. Result = CreateNotifyWindow();
  306. m_Initialized = TRUE;
  307. ScheduleRefresh();
  308. }
  309. if (hCursorOld) {
  310. SetCursor(hCursorOld);
  311. }
  312. return Result;
  313. }
  314. BOOL
  315. CMachine::ScheduleRefresh()
  316. {
  317. Lock();
  318. //
  319. // Only queue the the request if there is no requests outstanding
  320. // and we have a valid window handle/message to the notify window.
  321. //
  322. if (!m_RefreshPending && m_hwndNotify && m_msgRefresh) {
  323. //
  324. // Broadcast the message so that every instance runs on
  325. // the computer get the notification
  326. //
  327. ::PostMessage(HWND_BROADCAST, m_msgRefresh, 0, 0);
  328. }
  329. Unlock();
  330. return TRUE;
  331. }
  332. //
  333. // This function creates a data window to receive WM_DEVICECHANGE notification
  334. // so that we can refresh the device tree. It also registers a private
  335. // message so that anybody can post a refresh request.
  336. //
  337. BOOL
  338. CMachine::CreateNotifyWindow()
  339. {
  340. WNDCLASS wndClass;
  341. //
  342. // Lets see if the class has been registered.
  343. //
  344. if (!GetClassInfo(g_hInstance, DEVMGR_NOTIFY_CLASS_NAME, &wndClass)) {
  345. //
  346. // Register the class
  347. //
  348. memset(&wndClass, 0, sizeof(wndClass));
  349. wndClass.lpfnWndProc = dmNotifyWndProc;
  350. wndClass.hInstance = g_hInstance;
  351. wndClass.lpszClassName = DEVMGR_NOTIFY_CLASS_NAME;
  352. if (!RegisterClass(&wndClass)) {
  353. return FALSE;
  354. }
  355. }
  356. //
  357. // Register a private message for refresh. The name must contain
  358. // the target machine name so that every machine has its own message.
  359. //
  360. String strMsg = DEVMGR_REFRESH_MSG;
  361. strMsg += m_strMachineDisplayName;
  362. m_msgRefresh = RegisterWindowMessage(strMsg);
  363. if (m_msgRefresh) {
  364. //
  365. // Create a data window.
  366. //
  367. m_hwndNotify = CreateWindowEx(WS_EX_TOOLWINDOW, DEVMGR_NOTIFY_CLASS_NAME,
  368. TEXT(""),
  369. WS_DLGFRAME|WS_BORDER|WS_DISABLED,
  370. CW_USEDEFAULT, CW_USEDEFAULT,
  371. 0, 0, NULL, NULL, g_hInstance, (void*)this);
  372. return(NULL != m_hwndNotify);
  373. }
  374. return FALSE;
  375. }
  376. BOOL
  377. CMachine::DestroyNotifyWindow()
  378. {
  379. if (m_hwndNotify && IsWindow(m_hwndNotify)) {
  380. ::DestroyWindow(m_hwndNotify);
  381. m_hwndNotify = NULL;
  382. return TRUE;
  383. }
  384. //
  385. // The notify window does not exist.
  386. //
  387. return FALSE;
  388. }
  389. //
  390. // This is the WM_DEVICECHANGE window procedure running in the main thread
  391. // context. It listens to two messages:
  392. // (1). WM_DEVICECHANGE broadcasted by Configuration Manager on device
  393. // addition/removing.
  394. // (2). Private refresh message broadcasted by different instance
  395. // of Device Manager targeting on the same machine.
  396. // On WM_CREATE, we participate the WM_DEVICECHANGE notification chain
  397. // while on WM_DESTROY, we detach oursleves from the chain.
  398. // There are occasions that we have to detach and re-attach to the
  399. // chain duing the window life time, for example, during device uninstallation
  400. // or during re-enumeration. The EnableFresh function is the place
  401. // that does the attach/detach.
  402. //
  403. LRESULT
  404. dmNotifyWndProc(
  405. HWND hWnd,
  406. UINT uMsg,
  407. WPARAM wParam,
  408. LPARAM lParam
  409. )
  410. {
  411. CMachine* pThis;
  412. pThis = (CMachine*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  413. //
  414. // Special case for private refresh message
  415. //
  416. if (pThis && uMsg == pThis->m_msgRefresh) {
  417. pThis->Refresh();
  418. return FALSE;
  419. }
  420. switch (uMsg) {
  421. case WM_CREATE:
  422. pThis = (CMachine*)((CREATESTRUCT*)lParam)->lpCreateParams;
  423. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
  424. break;
  425. case WM_DEVICECHANGE:
  426. if (DBT_DEVNODES_CHANGED == wParam) {
  427. //
  428. // While we are in WM_DEVICECHANGE context,
  429. // no CM apis can be called because it would
  430. // deadlock. Here, we schedule a timer so that
  431. // we can handle the message later on.
  432. //
  433. SetTimer(hWnd, DM_NOTIFY_TIMERID, 1000, NULL);
  434. }
  435. break;
  436. case WM_TIMER:
  437. if (DM_NOTIFY_TIMERID == wParam) {
  438. KillTimer(hWnd, DM_NOTIFY_TIMERID);
  439. ASSERT(pThis);
  440. pThis->ScheduleRefresh();
  441. }
  442. break;
  443. default:
  444. break;
  445. }
  446. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  447. }
  448. //
  449. // This function attaches the given CFolder to the class.
  450. // An attached CFolder will get notified when there are state
  451. // changes in the class(Refresh, property changes, for example).
  452. //
  453. BOOL
  454. CMachine::AttachFolder(
  455. CFolder* pFolder
  456. )
  457. {
  458. ASSERT(pFolder);
  459. if (!IsFolderAttached(pFolder)) {
  460. pFolder->MachinePropertyChanged(this);
  461. m_listFolders.AddTail(pFolder);
  462. }
  463. return TRUE;
  464. }
  465. BOOL
  466. CMachine::IsFolderAttached(
  467. CFolder* pFolder
  468. )
  469. {
  470. if (!m_listFolders.IsEmpty()) {
  471. POSITION pos = m_listFolders.GetHeadPosition();
  472. while (NULL != pos) {
  473. if (pFolder == m_listFolders.GetNext(pos)) {
  474. return TRUE;
  475. }
  476. }
  477. }
  478. return FALSE;
  479. }
  480. void
  481. CMachine::DetachFolder(
  482. CFolder* pFolder
  483. )
  484. {
  485. POSITION nextpos = m_listFolders.GetHeadPosition();
  486. while (nextpos) {
  487. POSITION pos = nextpos;
  488. CFolder* pFolderToTest = m_listFolders.GetNext(nextpos);
  489. if (pFolderToTest == pFolder) {
  490. m_listFolders.RemoveAt(pos);
  491. break;
  492. }
  493. }
  494. }
  495. BOOL
  496. CMachine::AttachPropertySheet(
  497. HWND hwndPropertySheet
  498. )
  499. {
  500. ASSERT(hwndPropertySheet);
  501. EnterCriticalSection(&m_PropertySheetCriticalSection);
  502. m_listPropertySheets.AddTail(hwndPropertySheet);
  503. LeaveCriticalSection(&m_PropertySheetCriticalSection);
  504. return TRUE;
  505. }
  506. void
  507. CMachine::DetachPropertySheet(
  508. HWND hwndPropertySheet
  509. )
  510. {
  511. EnterCriticalSection(&m_PropertySheetCriticalSection);
  512. POSITION nextpos = m_listPropertySheets.GetHeadPosition();
  513. while (nextpos) {
  514. POSITION pos = nextpos;
  515. HWND hwndPropertySheetToTest = m_listPropertySheets.GetNext(nextpos);
  516. if (hwndPropertySheetToTest == hwndPropertySheet) {
  517. m_listPropertySheets.RemoveAt(pos);
  518. break;
  519. }
  520. }
  521. LeaveCriticalSection(&m_PropertySheetCriticalSection);
  522. }
  523. HWND
  524. CMachine::GetDeviceWindowHandle(
  525. LPCTSTR DeviceId
  526. )
  527. {
  528. HWND hwnd = NULL;
  529. EnterCriticalSection(&m_ChildMachineCriticalSection);
  530. //
  531. // Enumerate the list of Child CMachines
  532. //
  533. if (!m_listChildMachines.IsEmpty()) {
  534. PVOID DeviceContext;
  535. CDevice* pDevice;
  536. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  537. while (nextpos) {
  538. CMachine* pChildMachine = m_listChildMachines.GetNext(nextpos);
  539. //
  540. // Child machines will only have one device (if any at all)
  541. //
  542. if (pChildMachine->GetFirstDevice(&pDevice, DeviceContext) &&
  543. pDevice) {
  544. //
  545. // If the device Ids match then get the window handle
  546. //
  547. if (lstrcmpi(pDevice->GetDeviceID(), DeviceId) == 0) {
  548. hwnd = pDevice->m_psd.GetWindowHandle();
  549. break;
  550. }
  551. }
  552. }
  553. }
  554. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  555. return hwnd;
  556. }
  557. HWND
  558. CMachine::GetClassWindowHandle(
  559. LPGUID ClassGuid
  560. )
  561. {
  562. HWND hwnd = NULL;
  563. EnterCriticalSection(&m_ChildMachineCriticalSection);
  564. //
  565. // Enumerate the list of Child CMachines
  566. //
  567. if (!m_listChildMachines.IsEmpty()) {
  568. PVOID ClassContext;
  569. CClass* pClass;
  570. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  571. while (nextpos) {
  572. CMachine* pChildMachine = m_listChildMachines.GetNext(nextpos);
  573. //
  574. // Any child CMachine that has a device is a device property sheet.
  575. // We only want to look at the ones that have 0 devices since those
  576. // will be class property sheets.
  577. //
  578. if (pChildMachine->GetNumberOfDevices() == 0) {
  579. if (pChildMachine->GetFirstClass(&pClass, ClassContext) &&
  580. pClass) {
  581. //
  582. // If the ClassGuids match then get the window handle
  583. //
  584. if (IsEqualGUID(*ClassGuid, *pClass)) {
  585. hwnd = pClass->m_psd.GetWindowHandle();
  586. break;
  587. }
  588. }
  589. }
  590. }
  591. }
  592. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  593. return hwnd;
  594. }
  595. BOOL
  596. CMachine::AttachChildMachine(
  597. CMachine* ChildMachine
  598. )
  599. {
  600. ASSERT(ChildMachine);
  601. EnterCriticalSection(&m_ChildMachineCriticalSection);
  602. m_listChildMachines.AddTail(ChildMachine);
  603. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  604. return TRUE;
  605. }
  606. void
  607. CMachine::DetachChildMachine(
  608. CMachine* ChildMachine
  609. )
  610. {
  611. EnterCriticalSection(&m_ChildMachineCriticalSection);
  612. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  613. while (nextpos) {
  614. POSITION pos = nextpos;
  615. CMachine* CMachineToTest = m_listChildMachines.GetNext(nextpos);
  616. if (CMachineToTest == ChildMachine) {
  617. m_listChildMachines.RemoveAt(pos);
  618. break;
  619. }
  620. }
  621. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  622. }
  623. CMachine::~CMachine()
  624. {
  625. //
  626. // Turn off refresh. We need to do this in case there are any property
  627. // sheets that are still active.
  628. //
  629. EnableRefresh(FALSE);
  630. //
  631. // We first need to destroy all child CMachines
  632. //
  633. while (!m_listChildMachines.IsEmpty()) {
  634. //
  635. // Remove the first child machine from the list. We need to
  636. // do this in the critical section.
  637. //
  638. EnterCriticalSection(&m_ChildMachineCriticalSection);
  639. CMachine* ChildMachine = m_listChildMachines.RemoveHead();
  640. //
  641. // Set the m_ParentMachine to NULL so we won't try to remove it from
  642. // the list again.
  643. //
  644. ChildMachine->m_ParentMachine = NULL;
  645. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  646. delete ChildMachine;
  647. }
  648. //
  649. // We need to wait for all of the property sheets to be destroyed.
  650. //
  651. // We will check to see if there are any property pages still around, and
  652. // if there is we will wait for .5 seconds and then check again. After 5
  653. // seconds we will give up and just destroy the CMachine anyway.
  654. //
  655. int iSecondsCount = 0;
  656. while (!m_listPropertySheets.IsEmpty() &&
  657. (iSecondsCount++ < 10)) {
  658. //
  659. // Enumerate through all of the property sheets left and if IsWindow fails
  660. // then pull them from the list, otherwise call DestroyWindow on them.
  661. //
  662. // Since property sheets each run in their own thread we need to do this
  663. // in a critical section.
  664. //
  665. EnterCriticalSection(&m_PropertySheetCriticalSection);
  666. POSITION nextpos = m_listPropertySheets.GetHeadPosition();
  667. while (nextpos) {
  668. POSITION pos = nextpos;
  669. HWND hwndPropertySheetToTest = m_listPropertySheets.GetNext(nextpos);
  670. if (IsWindow(hwndPropertySheetToTest)) {
  671. //
  672. // There is still a valid window for this property sheet so
  673. // call DestroyWindow on it.
  674. //
  675. ::DestroyWindow(hwndPropertySheetToTest);
  676. } else {
  677. //
  678. // There is no window for this property sheet so just remove
  679. // it from the list
  680. //
  681. m_listPropertySheets.RemoveAt(pos);
  682. }
  683. }
  684. LeaveCriticalSection(&m_PropertySheetCriticalSection);
  685. //
  686. // Sleep for .5 seconds and then try again. This will give the property pages time to
  687. // finish up their work.
  688. //
  689. Sleep(500);
  690. }
  691. //
  692. // If we have created a device change data window for this machine,
  693. // destroy it.
  694. //
  695. DestroyNotifyWindow();
  696. DestroyClassesAndDevices();
  697. if (!m_listFolders.IsEmpty()) {
  698. m_listFolders.RemoveAll();
  699. }
  700. //
  701. // If we have a parent CMachine then we need to remove oursleves from
  702. // his list of Child CMachines.
  703. //
  704. if (m_ParentMachine) {
  705. m_ParentMachine->DetachChildMachine(this);
  706. }
  707. DeleteCriticalSection(&m_CriticalSection);
  708. DeleteCriticalSection(&m_PropertySheetCriticalSection);
  709. DeleteCriticalSection(&m_ChildMachineCriticalSection);
  710. }
  711. //
  712. // This function destroys all the CClass and CDevice we ever created.
  713. // No notification is sent for the attached folder
  714. //
  715. //
  716. void
  717. CMachine::DestroyClassesAndDevices()
  718. {
  719. if (m_pComputer) {
  720. delete m_pComputer;
  721. m_pComputer = NULL;
  722. }
  723. if (!m_listDevice.IsEmpty()) {
  724. POSITION pos = m_listDevice.GetHeadPosition();
  725. while (NULL != pos) {
  726. CDevice* pDevice = m_listDevice.GetNext(pos);
  727. delete pDevice;
  728. }
  729. m_listDevice.RemoveAll();
  730. }
  731. if (!m_listClass.IsEmpty()) {
  732. POSITION pos = m_listClass.GetHeadPosition();
  733. while (NULL != pos) {
  734. CClass* pClass = m_listClass.GetNext(pos);
  735. delete pClass;
  736. }
  737. m_listClass.RemoveAll();
  738. }
  739. if (m_ImageListData.cbSize) {
  740. DiDestroyClassImageList(&m_ImageListData);
  741. }
  742. CDevInfoList::DiDestroyDeviceInfoList();
  743. m_hMachine = NULL;
  744. }
  745. BOOL
  746. CMachine::BuildClassesFromGuidList(
  747. LPGUID GuidList,
  748. DWORD Guids
  749. )
  750. {
  751. DWORD Index;
  752. CClass* pClass;
  753. //
  754. // Build a list of CClass for each GUID.
  755. //
  756. for (Index = 0; Index < Guids; Index++) {
  757. SafePtr<CClass> ClassPtr;
  758. pClass = new CClass(this, &GuidList[Index]);
  759. ClassPtr.Attach(pClass);
  760. m_listClass.AddTail(ClassPtr);
  761. ClassPtr.Detach();
  762. }
  763. return TRUE;
  764. }
  765. //
  766. // Create CClass and CDevice for this machine.
  767. // If DeviceId is valid, this function will create the machine
  768. // with ONLY ONE device(and its CClass)
  769. //
  770. // PERFBUG Optimize this function!!!!!!!
  771. // This function is slow because SetupDiGetClassDevs can take a long
  772. // time (over 1 sec of a 300Mhz machine).
  773. // The other slow part is the call to DoNotCreateDevice which needs to
  774. // go through the service manager for all legacy devnodes to see
  775. // if they are Win32 services (which we don't display). This takes
  776. // around 10ms to get this information from the service manager on
  777. // a 300Mhz machine and their are almost 100 of these legacy devices.
  778. // This means another second of time.
  779. //
  780. //
  781. BOOL
  782. CMachine::CreateClassesAndDevices(
  783. IN LPCTSTR DeviceId, OPTIONAL
  784. IN LPGUID ClassGuid OPTIONAL
  785. )
  786. {
  787. SC_HANDLE SCMHandle = NULL;
  788. //
  789. // Preventing memory leak
  790. //
  791. ASSERT(NULL == m_pComputer);
  792. ASSERT(INVALID_HANDLE_VALUE == m_hDevInfo);
  793. ASSERT(NULL == m_hMachine);
  794. if (DeviceId || ClassGuid) {
  795. //
  796. // If the object is being created for a single device,
  797. // create a empty device info list. We will add the
  798. // device to the info list later.
  799. //
  800. m_hDevInfo = DiCreateDeviceInfoList(ClassGuid, m_hwndParent);
  801. } else {
  802. //
  803. // We have to pull out the entire devices/classes set
  804. // so create a device info list that contains all of them.
  805. //
  806. m_hDevInfo = DiGetClassDevs(NULL, NULL, m_hwndParent, DIGCF_ALLCLASSES | DIGCF_PROFILE);
  807. }
  808. //
  809. // NULL != INVALID_HANDLE_VALUE. We checked both just be safe.
  810. //
  811. if (INVALID_HANDLE_VALUE == m_hDevInfo || NULL == m_hDevInfo) {
  812. return FALSE;
  813. }
  814. SP_DEVINFO_LIST_DETAIL_DATA DevInfoDetailData;
  815. DevInfoDetailData.cbSize = sizeof(DevInfoDetailData);
  816. //
  817. // Use the HMACHINE returned from Setupapi so that
  818. // every call we make to Cfgmgr32.dll will use the
  819. // same HMACHINE. Two call of CM_Connect_Machine will
  820. // return different hMachines even though they refer to
  821. // the same machine name(and thus, different set of DEVNODES!).
  822. // The catch is that we will be able to call Setuapi and cfgmgr32
  823. // API without worrying about which hMachine to use.
  824. //
  825. if (DiGetDeviceInfoListDetail(&DevInfoDetailData)) {
  826. m_hMachine = DevInfoDetailData.RemoteMachineHandle;
  827. } else {
  828. //
  829. // Unable to get the devinfo detail information.
  830. // In this case we will just default to the local machine.
  831. //
  832. return FALSE;
  833. }
  834. //
  835. // Get class image list data;
  836. //
  837. m_ImageListData.cbSize = sizeof(m_ImageListData);
  838. if (DiGetClassImageList(&m_ImageListData)) {
  839. //
  840. // Add extra icons
  841. //
  842. HICON hIcon;
  843. if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DEVMGR))) != NULL) {
  844. m_ComputerIndex = ImageList_AddIcon(m_ImageListData.ImageList, hIcon);
  845. DestroyIcon(hIcon);
  846. }
  847. if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_RESOURCES))) != NULL) {
  848. m_ResourceIndex = ImageList_AddIcon(m_ImageListData.ImageList, hIcon);
  849. DestroyIcon(hIcon);
  850. }
  851. }
  852. //
  853. // If the object is created for a particular device,
  854. // do not create the entire device list because it is
  855. // a waste of time.
  856. //
  857. if (DeviceId) {
  858. SP_DEVINFO_DATA DevData;
  859. GUID DeviceClassGuid;
  860. DevData.cbSize = sizeof(DevData);
  861. if (DiOpenDeviceInfo(DeviceId, m_hwndParent, 0, &DevData) &&
  862. CmGetClassGuid(DevData.DevInst, DeviceClassGuid)) {
  863. //
  864. // Create a CClass for the device(without CClass, no
  865. // device can not be created).
  866. //
  867. CClass* pClass;
  868. SafePtr<CClass> ClassPtr;
  869. pClass = new CClass(this, &DeviceClassGuid);
  870. if (pClass) {
  871. ClassPtr.Attach(pClass);
  872. m_listClass.AddTail(ClassPtr);
  873. //
  874. // The class object has been inserted to the list
  875. // it is safe now to detach the object from the smart pointer
  876. // The class object will be deleted by the list
  877. //
  878. ClassPtr.Detach();
  879. //
  880. // Create the device
  881. //
  882. SafePtr<CDevice> DevicePtr;
  883. CDevice* pDevice;
  884. pDevice = new CDevice(this, pClass, &DevData);
  885. if (pDevice) {
  886. //
  887. // Guard the object
  888. //
  889. DevicePtr.Attach(pDevice);
  890. m_listDevice.AddTail(DevicePtr);
  891. //
  892. // Object added..
  893. //
  894. DevicePtr.Detach();
  895. pClass->AddDevice(pDevice);
  896. }
  897. }
  898. }
  899. //
  900. // We should have one class and one device object. no more no less.
  901. // we are done here.
  902. //
  903. return(1 == m_listClass.GetCount() && 1 == m_listDevice.GetCount());
  904. }
  905. //
  906. // If the object is for a specific class then just create the class and add
  907. // it to the CMachine.
  908. //
  909. else if (ClassGuid) {
  910. CClass* pClass;
  911. SafePtr<CClass> ClassPtr;
  912. pClass = new CClass(this, ClassGuid);
  913. if (pClass) {
  914. ClassPtr.Attach(pClass);
  915. m_listClass.AddTail(ClassPtr);
  916. //
  917. // The class object has been inserted to the list
  918. // it is safe now to detach the object from the smart pointer
  919. // The class object will be deleted by the list
  920. //
  921. ClassPtr.Detach();
  922. }
  923. //
  924. // We should have one class. no more no less.
  925. // we are done here.
  926. //
  927. return(1 == m_listClass.GetCount());
  928. }
  929. //
  930. // Build class guid list
  931. //
  932. DWORD ClassGuids, GuidsRequired;
  933. GuidsRequired = 0;
  934. //
  935. // We make a guess here to save us some time.
  936. //
  937. GUID LocalGuid[GUID_LIST_INIT_SIZE];
  938. ClassGuids = GUID_LIST_INIT_SIZE;
  939. if (DiBuildClassInfoList(0, LocalGuid, ClassGuids, &GuidsRequired)) {
  940. BuildClassesFromGuidList(LocalGuid, GuidsRequired);
  941. } else if (ERROR_INSUFFICIENT_BUFFER == GetLastError() && GuidsRequired) {
  942. //
  943. // The stack based buffer is too small, allocate buffer from
  944. // the heap.
  945. //
  946. BufferPtr<GUID> ClassGuidList(GuidsRequired);
  947. if (DiBuildClassInfoList(0, ClassGuidList, GuidsRequired, &ClassGuids)) {
  948. BuildClassesFromGuidList(ClassGuidList, ClassGuids);
  949. }
  950. }
  951. //
  952. // If we have any classes at all, create devices objects
  953. //
  954. if (!m_listClass.IsEmpty()) {
  955. DWORD Index = 0;
  956. SP_DEVINFO_DATA DevData;
  957. //
  958. // We need a handle to the service manager in the DoNotCreateDevice
  959. // function. We will open it once and pass it to this function rather
  960. // than opening and closing it for every device.
  961. //
  962. SCMHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
  963. //
  964. // Create every device in the devinfo list and
  965. // associate each device to its class.
  966. //
  967. DevData.cbSize = sizeof(DevData);
  968. while (DiEnumDeviceInfo(Index, &DevData)) {
  969. POSITION pos = m_listClass.GetHeadPosition();
  970. CClass* pClass;
  971. //
  972. // Find the class for this device
  973. //
  974. while (NULL != pos) {
  975. pClass = m_listClass.GetNext(pos);
  976. //
  977. // Match the ClassGuid for this device.
  978. // Note that if the device does not have a class guid (GUID_NULL)
  979. // then we will put it in class GUID_DEVCLASS_UNKNOWN)
  980. //
  981. if ((IsEqualGUID(DevData.ClassGuid, *pClass)) ||
  982. (IsEqualGUID(GUID_DEVCLASS_UNKNOWN, *pClass) &&
  983. IsEqualGUID(DevData.ClassGuid, GUID_NULL))) {
  984. //
  985. // Is this one of the special DevInst that we should
  986. // not create a CDevice for?
  987. //
  988. if (DoNotCreateDevice(SCMHandle, *pClass, DevData.DevInst)) {
  989. break;
  990. }
  991. //
  992. // Create the device
  993. //
  994. SafePtr<CDevice> DevicePtr;
  995. CDevice* pDevice;
  996. pDevice = new CDevice(this, pClass, &DevData);
  997. //
  998. // Guard the object
  999. //
  1000. DevicePtr.Attach(pDevice);
  1001. m_listDevice.AddTail(DevicePtr);
  1002. //
  1003. // Object added.
  1004. //
  1005. DevicePtr.Detach();
  1006. //
  1007. // Put the device under the class
  1008. //
  1009. pClass->AddDevice(pDevice);
  1010. break;
  1011. }
  1012. //
  1013. // No class than, no device
  1014. //
  1015. }
  1016. //
  1017. // next device
  1018. //
  1019. Index++;
  1020. }
  1021. CloseServiceHandle(SCMHandle);
  1022. //
  1023. // Create a device tree under computer
  1024. // the tree order comes from DEVNODE structure;
  1025. //
  1026. DEVNODE dnRoot = CmGetRootDevNode();
  1027. m_pComputer = new CComputer(this, dnRoot);
  1028. DEVNODE dnStart = CmGetChild(dnRoot);
  1029. CreateDeviceTree(m_pComputer, NULL, dnStart);
  1030. }
  1031. return TRUE;
  1032. }
  1033. //
  1034. // This function builds a device tree based on the Devnode tree retreived
  1035. // from configuration manager. Note that ALL CDevice are created before
  1036. // this function is called. This function establishs each CDevice relationship.
  1037. //
  1038. void
  1039. CMachine::CreateDeviceTree(
  1040. CDevice* pParent,
  1041. CDevice* pSibling,
  1042. DEVNODE dn
  1043. )
  1044. {
  1045. CDevice* pDevice;
  1046. DEVNODE dnChild;
  1047. while (dn) {
  1048. pDevice = DevNodeToDevice(dn);
  1049. if (pDevice) {
  1050. //
  1051. // No sibling ->this is the first child
  1052. //
  1053. if (!pSibling) {
  1054. pParent->SetChild(pDevice);
  1055. }
  1056. else {
  1057. pSibling->SetSibling(pDevice);
  1058. }
  1059. pDevice->SetParent(pParent);
  1060. pSibling = pDevice;
  1061. dnChild = CmGetChild(dn);
  1062. if (dnChild) {
  1063. CreateDeviceTree(pDevice, NULL, dnChild);
  1064. }
  1065. }
  1066. dn = CmGetSibling(dn);
  1067. }
  1068. }
  1069. //
  1070. // Find CDevice from the given devnode
  1071. //
  1072. CDevice*
  1073. CMachine::DevNodeToDevice(
  1074. DEVNODE dn
  1075. )
  1076. {
  1077. POSITION pos = m_listDevice.GetHeadPosition();
  1078. while (NULL != pos) {
  1079. CDevice* pDevice = m_listDevice.GetNext(pos);
  1080. if (pDevice->GetDevNode() == dn) {
  1081. return pDevice;
  1082. }
  1083. }
  1084. return NULL;
  1085. }
  1086. //
  1087. // This function reenumerates the devnode tree from the root, rebuilds the
  1088. // device tree and notifies every attached folder about the new device tree.
  1089. //
  1090. BOOL
  1091. CMachine::Reenumerate()
  1092. {
  1093. if (m_pComputer) {
  1094. //
  1095. // Temporarily disable refresh while we are doing reenumeration
  1096. // so that we will not keep refreshing the device tree.
  1097. //
  1098. EnableRefresh(FALSE);
  1099. CDialog WaitDialog(IDD_SCAN_PNP_HARDWARES);
  1100. WaitDialog.DoModaless(m_hwndParent, (LPARAM)&WaitDialog);
  1101. if (!CmReenumerate(
  1102. m_pComputer->GetDevNode(),
  1103. CM_REENUMERATE_SYNCHRONOUS | CM_REENUMERATE_RETRY_INSTALLATION
  1104. )) {
  1105. //
  1106. // Win2K doesn't support CM_REENUMERATE_RETRY_INSTALLATION, so we
  1107. // retry without the reinstall flag.
  1108. //
  1109. CmReenumerate(m_pComputer->GetDevNode(), CM_REENUMERATE_SYNCHRONOUS);
  1110. }
  1111. DestroyWindow(WaitDialog);
  1112. //
  1113. // reenumeration is done, schedule a refresh and enable refresh now.
  1114. //
  1115. ScheduleRefresh();
  1116. EnableRefresh(TRUE);
  1117. }
  1118. return TRUE;
  1119. }
  1120. //
  1121. // This function enable/disable refresh. A disble counter is kept to
  1122. // support multiple disabling/enabling. Only when the disable counter
  1123. // is zero, a refresh is possible.
  1124. // If a refresh is pending while we are enabling, we schedule a new
  1125. // request so that we will not lose any requests.
  1126. //
  1127. BOOL
  1128. CMachine::EnableRefresh(
  1129. BOOL fEnable
  1130. )
  1131. {
  1132. BOOL Result = TRUE;
  1133. Lock();
  1134. if (fEnable) {
  1135. if (m_RefreshDisableCounter < 0) {
  1136. m_RefreshDisableCounter++;
  1137. }
  1138. }
  1139. else {
  1140. m_RefreshDisableCounter--;
  1141. }
  1142. //
  1143. // If we are enabling refresh and there is one request pending,
  1144. // schedule it again. This makes sure that we will not lose
  1145. // any requests.
  1146. // We schedule a new refresh request instead of calling Refresh
  1147. // directly because we can be called by different threads while
  1148. // we want the refresh to be done in the main thread. The data window
  1149. // we created will receive the message and execute the refresh
  1150. // in the main thread context.
  1151. //
  1152. if (fEnable && m_RefreshPending) {
  1153. m_RefreshPending = FALSE;
  1154. ScheduleRefresh();
  1155. }
  1156. Unlock();
  1157. return Result;
  1158. }
  1159. //
  1160. //
  1161. // This function rebuilds the entire list of CClass and CDevice
  1162. // All attached CFolder are notified about the new machine.
  1163. //
  1164. // There are several occasions that we need to recreate the device tree:
  1165. // (1). On WM_DEVICECHANGE.
  1166. // (2). Device properties changed.
  1167. // (3). Device removal.
  1168. // (4). Device drivers updated and
  1169. // (5). Reenumeration requested by users.
  1170. // The requests may come from different threads and we must serialize
  1171. // the requests. A critical section and a new function(EnableRefresh) are added for
  1172. // for this purpose.
  1173. // Before doing anything on a device or class, one must call EnableRefesh(FALSE)
  1174. // to suspend Device change notification. When it is done with the change,
  1175. // one must call ScheduleRefesh function(if a refresh is necessary because of
  1176. // the changes) and then EnableRefresh(TRUE) to reenable the refresh.
  1177. //
  1178. BOOL
  1179. CMachine::Refresh()
  1180. {
  1181. BOOL Result = TRUE;
  1182. POSITION pos;
  1183. Lock();
  1184. if (0 == m_RefreshDisableCounter) {
  1185. HCURSOR hCursorOld;
  1186. hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1187. //
  1188. // Before we destroy all the classes and devices,
  1189. // notify every attached folder so that they can dis-engaged
  1190. // from us. After we created a new set of classes and devices,
  1191. // the notification will be sent again to each folder
  1192. // so that each folder can enagage to the machine again.
  1193. //
  1194. pos = m_listFolders.GetHeadPosition();
  1195. while (NULL != pos) {
  1196. ((CFolder*)m_listFolders.GetNext(pos))->MachinePropertyChanged(NULL);
  1197. }
  1198. //
  1199. // we can destroy all the "old" classes and devices now.
  1200. //
  1201. DestroyClassesAndDevices();
  1202. if (CreateClassesAndDevices()) {
  1203. //
  1204. // Notify every attach folder to recreate
  1205. //
  1206. if (!m_listFolders.IsEmpty()) {
  1207. pos = m_listFolders.GetHeadPosition();
  1208. while (NULL != pos) {
  1209. CFolder* pFolder = m_listFolders.GetNext(pos);
  1210. Result = SUCCEEDED(pFolder->MachinePropertyChanged(this));
  1211. }
  1212. }
  1213. //
  1214. // Notify every property page to refresh
  1215. //
  1216. if (!m_listChildMachines.IsEmpty()) {
  1217. EnterCriticalSection(&m_ChildMachineCriticalSection);
  1218. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  1219. while (nextpos) {
  1220. pos = nextpos;
  1221. CMachine* pMachineToNotify = m_listChildMachines.GetNext(nextpos);
  1222. pMachineToNotify->DoMiniRefresh();
  1223. }
  1224. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  1225. }
  1226. }
  1227. if (hCursorOld) {
  1228. SetCursor(hCursorOld);
  1229. }
  1230. m_RefreshPending = FALSE;
  1231. }
  1232. else {
  1233. //
  1234. // We need to refresh while the refresh is disabled
  1235. // Remember this so that when refresh is enabled, we
  1236. // can launch a refresh.
  1237. //
  1238. m_RefreshPending = TRUE;
  1239. }
  1240. Unlock();
  1241. return Result;
  1242. }
  1243. //
  1244. // A mini refresh is performed when the CMachine only has a single CClass or
  1245. // CDevice. This is because this will be the property sheet case. In this
  1246. // case we will see if the class or device represented by this property sheet
  1247. // still exists.
  1248. //
  1249. BOOL
  1250. CMachine::DoMiniRefresh()
  1251. {
  1252. BOOL Result = TRUE;
  1253. Lock();
  1254. //
  1255. // If the machine has one CDevice then we need to see if this device is
  1256. // still around.
  1257. //
  1258. if (1 == m_listDevice.GetCount()) {
  1259. PVOID Context;
  1260. CDevice* pDevice;
  1261. if (GetFirstDevice(&pDevice, Context)) {
  1262. //
  1263. // If the devnode did not go away we should tell it to refresh itself
  1264. // in case something changed.
  1265. //
  1266. ::PostMessage(pDevice->m_psd.GetWindowHandle(), PSM_QUERYSIBLINGS, QSC_PROPERTY_CHANGED, 0L);
  1267. }
  1268. }
  1269. //
  1270. // Note that currently we don't do anything in the class property sheet case.
  1271. // The reason for this is that classes can't really go away unless someone deletes
  1272. // them from the registry, which probably wills mess up lots of other things. Also
  1273. // all current class property sheets don't do anything anyway and so even if someone
  1274. // does delete the class key nothing bad will happen to the property sheet.
  1275. //
  1276. Unlock();
  1277. return Result;
  1278. }
  1279. BOOL
  1280. CMachine::GetFirstDevice(
  1281. CDevice** ppDevice,
  1282. PVOID& Context
  1283. )
  1284. {
  1285. ASSERT(ppDevice);
  1286. if (!m_listDevice.IsEmpty()) {
  1287. POSITION pos = m_listDevice.GetHeadPosition();
  1288. *ppDevice = m_listDevice.GetNext(pos);
  1289. Context = pos;
  1290. return TRUE;
  1291. }
  1292. *ppDevice = NULL;
  1293. Context = NULL;
  1294. return FALSE;
  1295. }
  1296. BOOL
  1297. CMachine::GetNextDevice(
  1298. CDevice** ppDevice,
  1299. PVOID& Context
  1300. )
  1301. {
  1302. ASSERT(ppDevice);
  1303. POSITION pos = (POSITION)Context;
  1304. if (NULL != pos) {
  1305. *ppDevice = m_listDevice.GetNext(pos);
  1306. Context = pos;
  1307. return TRUE;
  1308. }
  1309. *ppDevice = NULL;
  1310. return FALSE;
  1311. }
  1312. BOOL
  1313. CMachine::GetFirstClass(
  1314. CClass** ppClass,
  1315. PVOID& Context
  1316. )
  1317. {
  1318. ASSERT(ppClass);
  1319. if (!m_listClass.IsEmpty()) {
  1320. POSITION pos = m_listClass.GetHeadPosition();
  1321. *ppClass = m_listClass.GetNext(pos);
  1322. Context = pos;
  1323. return TRUE;
  1324. }
  1325. *ppClass = NULL;
  1326. Context = NULL;
  1327. return FALSE;
  1328. }
  1329. BOOL
  1330. CMachine::GetNextClass(
  1331. CClass** ppClass,
  1332. PVOID& Context
  1333. )
  1334. {
  1335. ASSERT(ppClass);
  1336. POSITION pos = (POSITION)Context;
  1337. if (NULL != pos) {
  1338. *ppClass = m_listClass.GetNext(pos);
  1339. Context = pos;
  1340. return TRUE;
  1341. }
  1342. *ppClass = NULL;
  1343. return FALSE;
  1344. }
  1345. BOOL
  1346. CMachine::GetInfDigitalSigner(
  1347. LPCTSTR FullInfPath,
  1348. String& DigitalSigner
  1349. )
  1350. /*++
  1351. This function returns whether the specified INF file is digitally signed
  1352. or not and returns the digital signer.
  1353. NOTE that this function can return TRUE, meaning the file is digitally
  1354. signed, but not fill in the DigitalSigner parameter if the catalog
  1355. file associated with this INF didn't specify one.
  1356. --*/
  1357. {
  1358. SP_INF_SIGNER_INFO InfSignerInfo;
  1359. BOOL bRet = FALSE;
  1360. if (m_UserIsAGuest || !IsLocal()) {
  1361. //
  1362. // If the user is loged in as a guest, or we are not on the local
  1363. // machine, then make the digital signer string be 'Not available'
  1364. //
  1365. DigitalSigner.LoadString(g_hInstance, IDS_NOT_AVAILABLE);
  1366. } else {
  1367. InfSignerInfo.cbSize = sizeof(InfSignerInfo);
  1368. bRet = SetupVerifyInfFile(FullInfPath,
  1369. NULL,
  1370. &InfSignerInfo
  1371. );
  1372. //
  1373. // If SetupVerifyInfFile sets one of the following errors then the
  1374. // INF file is Authenticode signed, and we will treat this as
  1375. // a success case.
  1376. //
  1377. if((GetLastError() == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  1378. (GetLastError() == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  1379. bRet = TRUE;
  1380. }
  1381. if (bRet && (InfSignerInfo.DigitalSigner[0] != TEXT('\0'))) {
  1382. DigitalSigner = (LPTSTR)InfSignerInfo.DigitalSigner;
  1383. }
  1384. }
  1385. return bRet;
  1386. }
  1387. BOOL
  1388. CMachine::DoNotCreateDevice(
  1389. SC_HANDLE SCMHandle,
  1390. LPGUID ClassGuid,
  1391. DEVINST DevInst
  1392. )
  1393. /*++
  1394. This function returns whether a CDevice should be created for this DevInst
  1395. or not. If a CDevice is not created for DevInst then it will never show up
  1396. in the device manager UI, even when "Show hidden devices" is turned on.
  1397. We don't create a CDevice in the following cases:
  1398. - DevInst is HTREE\ROOT\0
  1399. - DevInst is a Win32 Service.
  1400. --*/
  1401. {
  1402. SC_HANDLE ServiceHandle;
  1403. TCHAR ServiceName[MAX_PATH];
  1404. LPQUERY_SERVICE_CONFIG ServiceConfig = NULL;
  1405. DWORD ServiceConfigSize;
  1406. ULONG Size;
  1407. String strDeviceID;
  1408. BOOL Return = FALSE;
  1409. //
  1410. // If the DEVMGR_SHOW_NONPRESENT_DEVICES environment variable is not set then
  1411. // we do not want to show any Phantom devices.
  1412. //
  1413. if (!m_ShowNonPresentDevices) {
  1414. ULONG Status, Problem;
  1415. if ((!CmGetStatus(DevInst, &Status, &Problem)) &&
  1416. ((m_LastCR == CR_NO_SUCH_VALUE) ||
  1417. (m_LastCR == CR_NO_SUCH_DEVINST))) {
  1418. return TRUE;
  1419. }
  1420. }
  1421. //
  1422. // Check to see if this device is a Win32 service. Only
  1423. // legacy devices could be Win32 services.
  1424. //
  1425. if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_LEGACYDRIVER)) {
  1426. Size = sizeof(ServiceName);
  1427. if (CmGetRegistryProperty(DevInst,
  1428. CM_DRP_SERVICE,
  1429. (PVOID)ServiceName,
  1430. &Size
  1431. ) == CR_SUCCESS) {
  1432. //
  1433. // Open this particular service
  1434. //
  1435. if ((ServiceHandle = OpenService(SCMHandle, ServiceName, GENERIC_READ)) != NULL) {
  1436. //
  1437. // Get the service config
  1438. //
  1439. if ((!QueryServiceConfig(ServiceHandle, NULL, 0, &ServiceConfigSize)) &&
  1440. (ERROR_INSUFFICIENT_BUFFER == GetLastError())) {
  1441. if ((ServiceConfig = (LPQUERY_SERVICE_CONFIG)malloc(ServiceConfigSize)) != NULL) {
  1442. if (QueryServiceConfig(ServiceHandle, ServiceConfig, ServiceConfigSize, &ServiceConfigSize)) {
  1443. if (ServiceConfig->dwServiceType & (SERVICE_WIN32 | SERVICE_FILE_SYSTEM_DRIVER)) {
  1444. Return = TRUE;
  1445. }
  1446. }
  1447. free(ServiceConfig);
  1448. }
  1449. }
  1450. CloseServiceHandle(ServiceHandle);
  1451. }
  1452. }
  1453. }
  1454. //
  1455. // Check to see if this is the HTREE\ROOT\0 device. We don't
  1456. // want to create a CDevice for this phantom devnode.
  1457. //
  1458. // This is an else statement because the HTREE\ROOT\0 device is
  1459. // not in the legacy device class.
  1460. //
  1461. else {
  1462. CmGetDeviceIDString(DevInst, strDeviceID);
  1463. if (!_wcsicmp((LPTSTR)strDeviceID, TEXT("HTREE\\ROOT\\0"))) {
  1464. Return = TRUE;
  1465. }
  1466. }
  1467. return Return;
  1468. }
  1469. BOOL
  1470. CMachine::DiGetClassFriendlyNameString(
  1471. LPGUID Guid,
  1472. String& strClass
  1473. )
  1474. {
  1475. TCHAR DisplayName[LINE_LEN + 1];
  1476. //
  1477. // Try friendly name first. If it failed, try the class name
  1478. //
  1479. if (SetupDiGetClassDescriptionEx(Guid, DisplayName, ARRAYLEN(DisplayName),
  1480. NULL, GetRemoteMachineFullName(), NULL) ||
  1481. SetupDiClassNameFromGuidEx(Guid, DisplayName, ARRAYLEN(DisplayName),
  1482. NULL, GetRemoteMachineFullName(), NULL)) {
  1483. strClass = DisplayName;
  1484. return TRUE;
  1485. }
  1486. return FALSE;
  1487. }
  1488. DEVNODE
  1489. CMachine::CmGetParent(
  1490. DEVNODE dn
  1491. )
  1492. {
  1493. DEVNODE dnParent;
  1494. m_LastCR = CM_Get_Parent_Ex(&dnParent, dn, 0, m_hMachine);
  1495. if (CR_SUCCESS == m_LastCR) {
  1496. return dnParent;
  1497. }
  1498. return NULL;
  1499. }
  1500. DEVNODE
  1501. CMachine::CmGetChild(
  1502. DEVNODE dn
  1503. )
  1504. {
  1505. DEVNODE dnChild;
  1506. m_LastCR = CM_Get_Child_Ex(&dnChild, dn, 0, m_hMachine);
  1507. if (CR_SUCCESS == m_LastCR) {
  1508. return dnChild;
  1509. }
  1510. return NULL;
  1511. }
  1512. DEVNODE
  1513. CMachine::CmGetSibling(
  1514. DEVNODE dn
  1515. )
  1516. {
  1517. DEVNODE dnSibling;
  1518. m_LastCR = CM_Get_Sibling_Ex(&dnSibling, dn, 0, m_hMachine);
  1519. if (CR_SUCCESS == m_LastCR) {
  1520. return dnSibling;
  1521. }
  1522. return NULL;
  1523. }
  1524. DEVNODE
  1525. CMachine::CmGetRootDevNode()
  1526. {
  1527. DEVNODE dnRoot;
  1528. m_LastCR = CM_Locate_DevNode_Ex(&dnRoot, NULL, 0, m_hMachine);
  1529. if (CR_SUCCESS == m_LastCR) {
  1530. return dnRoot;
  1531. }
  1532. return NULL;
  1533. }
  1534. BOOL
  1535. CMachine::CmGetDeviceIDString(
  1536. DEVNODE dn,
  1537. String& str
  1538. )
  1539. {
  1540. TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
  1541. m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID), 0, m_hMachine);
  1542. if (CR_SUCCESS == m_LastCR) {
  1543. str = DeviceID;
  1544. return TRUE;
  1545. }
  1546. return FALSE;
  1547. }
  1548. BOOL
  1549. CMachine::CmGetConfigFlags(
  1550. DEVNODE dn,
  1551. DWORD* pFlags
  1552. )
  1553. {
  1554. DWORD Size;
  1555. Size = sizeof(DWORD);
  1556. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CONFIGFLAGS, pFlags, &Size);
  1557. return CR_SUCCESS == m_LastCR;
  1558. }
  1559. BOOL
  1560. CMachine::CmGetCapabilities(
  1561. DEVNODE dn,
  1562. DWORD* pCapabilities
  1563. )
  1564. {
  1565. DWORD Size;
  1566. Size = sizeof(DWORD);
  1567. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CAPABILITIES, pCapabilities, &Size);
  1568. return CR_SUCCESS == m_LastCR;
  1569. }
  1570. BOOL
  1571. CMachine::CmGetDescriptionString(
  1572. DEVNODE dn,
  1573. String& str
  1574. )
  1575. {
  1576. TCHAR Description[LINE_LEN + 1];
  1577. ULONG Size = sizeof(Description);
  1578. Description[0] = TEXT('\0');
  1579. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_FRIENDLYNAME, Description, &Size);
  1580. if ((CR_NO_SUCH_VALUE == m_LastCR) || (Description[0] == TEXT('\0'))) {
  1581. Size = sizeof(Description);
  1582. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_DEVICEDESC, Description,
  1583. &Size);
  1584. }
  1585. if ((CR_SUCCESS == m_LastCR) && (Description[0] != TEXT('\0'))) {
  1586. str = Description;
  1587. return TRUE;
  1588. }
  1589. return FALSE;
  1590. }
  1591. BOOL
  1592. CMachine::CmGetMFGString(
  1593. DEVNODE dn,
  1594. String& str
  1595. )
  1596. {
  1597. TCHAR MFG[LINE_LEN + 1];
  1598. ULONG Size = sizeof(MFG);
  1599. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_MFG, MFG, &Size);
  1600. if (CR_SUCCESS == m_LastCR) {
  1601. str = MFG;
  1602. return TRUE;
  1603. }
  1604. return FALSE;
  1605. }
  1606. BOOL
  1607. CMachine::CmGetProviderString(
  1608. DEVNODE dn,
  1609. String& str
  1610. )
  1611. {
  1612. TCHAR Provider[LINE_LEN + 1];
  1613. ULONG Size = sizeof(Provider);
  1614. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("ProviderName"),
  1615. Provider, &Size);
  1616. if (CR_SUCCESS == m_LastCR) {
  1617. str = Provider;
  1618. return TRUE;
  1619. }
  1620. return FALSE;
  1621. }
  1622. BOOL
  1623. CMachine::CmGetDriverDateString(
  1624. DEVNODE dn,
  1625. String& str
  1626. )
  1627. {
  1628. TCHAR DriverDate[LINE_LEN + 1];
  1629. ULONG Size = sizeof(DriverDate);
  1630. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverDate"),
  1631. DriverDate, &Size);
  1632. if (CR_SUCCESS == m_LastCR) {
  1633. str = DriverDate;
  1634. return TRUE;
  1635. }
  1636. return FALSE;
  1637. }
  1638. BOOL
  1639. CMachine::CmGetDriverDateData(
  1640. DEVNODE dn,
  1641. FILETIME *ft
  1642. )
  1643. {
  1644. ULONG Size = sizeof(*ft);
  1645. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverDateData"),
  1646. ft, &Size);
  1647. return(m_LastCR == CR_SUCCESS);
  1648. }
  1649. BOOL
  1650. CMachine::CmGetDriverVersionString(
  1651. DEVNODE dn,
  1652. String& str
  1653. )
  1654. {
  1655. TCHAR DriverVersion[LINE_LEN + 1];
  1656. ULONG Size = sizeof(DriverVersion);
  1657. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverVersion"),
  1658. DriverVersion, &Size);
  1659. if (CR_SUCCESS == m_LastCR) {
  1660. str = DriverVersion;
  1661. return TRUE;
  1662. }
  1663. return FALSE;
  1664. }
  1665. BOOL
  1666. CMachine::CmGetBusGuid(
  1667. DEVNODE dn,
  1668. LPGUID Guid
  1669. )
  1670. {
  1671. ULONG Size = sizeof(*Guid);
  1672. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_BUSTYPEGUID, (LPVOID)Guid, &Size);
  1673. if (CR_SUCCESS == m_LastCR) {
  1674. return TRUE;
  1675. }
  1676. return FALSE;
  1677. }
  1678. BOOL
  1679. CMachine::CmGetBusGuidString(
  1680. DEVNODE dn,
  1681. String& str
  1682. )
  1683. {
  1684. GUID BusGuid;
  1685. TCHAR BusGuidString[MAX_GUID_STRING_LEN];
  1686. ULONG Size;
  1687. while (dn) {
  1688. //
  1689. // We have to set the size on each loop
  1690. //
  1691. Size = sizeof(BusGuid);
  1692. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_BUSTYPEGUID, &BusGuid, &Size);
  1693. if (CR_SUCCESS == m_LastCR && GuidToString(&BusGuid, BusGuidString,
  1694. ARRAYLEN(BusGuidString))) {
  1695. str = BusGuidString;
  1696. return TRUE;
  1697. }
  1698. dn = CmGetParent(dn);
  1699. }
  1700. return FALSE;
  1701. }
  1702. BOOL
  1703. CMachine::CmGetClassGuid(
  1704. DEVNODE dn,
  1705. GUID& Guid
  1706. )
  1707. {
  1708. TCHAR szGuidString[MAX_GUID_STRING_LEN + 1];
  1709. ULONG Size = sizeof(szGuidString);
  1710. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CLASSGUID, szGuidString, &Size);
  1711. if (CR_SUCCESS == m_LastCR && GuidFromString(szGuidString, &Guid)) {
  1712. return TRUE;
  1713. }
  1714. //
  1715. // If we can't get the class GUID from the registry then most likely the device
  1716. // does not have a class GUID. If this is the case then we will return
  1717. // GUID_DEVCLASS_UNKNOWN
  1718. //
  1719. else {
  1720. memcpy(&Guid, &GUID_DEVCLASS_UNKNOWN, sizeof(GUID));
  1721. return TRUE;
  1722. }
  1723. }
  1724. BOOL
  1725. CMachine::CmGetStatus(
  1726. DEVNODE dn,
  1727. DWORD* pProblem,
  1728. DWORD* pStatus
  1729. )
  1730. {
  1731. ASSERT(pProblem && pStatus);
  1732. m_LastCR = CM_Get_DevNode_Status_Ex(pStatus, pProblem, dn, 0, m_hMachine);
  1733. return(CR_SUCCESS == m_LastCR);
  1734. }
  1735. BOOL
  1736. CMachine::CmGetKnownLogConf(
  1737. DEVNODE dn,
  1738. LOG_CONF* plc,
  1739. DWORD* plcType
  1740. )
  1741. {
  1742. ASSERT(plc);
  1743. *plc = 0;
  1744. if (plcType) {
  1745. *plcType = LOG_CONF_BITS + 1;
  1746. }
  1747. ULONG lcTypeFirst = ALLOC_LOG_CONF;
  1748. ULONG lcTypeLast = FORCED_LOG_CONF;
  1749. ASSERT(ALLOC_LOG_CONF + 1 == BOOT_LOG_CONF &&
  1750. BOOT_LOG_CONF + 1 == FORCED_LOG_CONF);
  1751. for (ULONG lcType = lcTypeFirst; lcType <= lcTypeLast; lcType++) {
  1752. m_LastCR = CM_Get_First_Log_Conf_Ex(plc, dn, lcType, m_hMachine);
  1753. if (CR_SUCCESS == m_LastCR) {
  1754. if (plcType) {
  1755. *plcType = lcType;
  1756. }
  1757. break;
  1758. }
  1759. }
  1760. return CR_SUCCESS == m_LastCR;
  1761. }
  1762. BOOL
  1763. CMachine::CmHasResources(
  1764. DEVNODE dn
  1765. )
  1766. {
  1767. for (ULONG lcType = 0; lcType < NUM_LOG_CONF; lcType++) {
  1768. m_LastCR = CM_Get_First_Log_Conf_Ex(NULL, dn, lcType, m_hMachine);
  1769. if (CR_SUCCESS == m_LastCR) {
  1770. break;
  1771. }
  1772. }
  1773. return CR_SUCCESS == m_LastCR;
  1774. }
  1775. BOOL
  1776. CMachine::CmReenumerate(
  1777. DEVNODE dn,
  1778. ULONG Flags
  1779. )
  1780. {
  1781. m_LastCR = CM_Reenumerate_DevNode_Ex(dn, Flags, m_hMachine);
  1782. return CR_SUCCESS == m_LastCR;
  1783. }
  1784. BOOL
  1785. CMachine::CmGetHwProfileFlags(
  1786. DEVNODE dn,
  1787. ULONG Profile,
  1788. ULONG* pFlags
  1789. )
  1790. {
  1791. TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
  1792. m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID),
  1793. 0, m_hMachine);
  1794. if (CR_SUCCESS == m_LastCR) {
  1795. return CmGetHwProfileFlags(DeviceID, Profile, pFlags);
  1796. }
  1797. return FALSE;
  1798. }
  1799. BOOL
  1800. CMachine::CmGetHwProfileFlags(
  1801. LPCTSTR DeviceID,
  1802. ULONG Profile,
  1803. ULONG* pFlags
  1804. )
  1805. {
  1806. m_LastCR = CM_Get_HW_Prof_Flags_Ex((LPTSTR)DeviceID, Profile, pFlags, 0,
  1807. m_hMachine);
  1808. return CR_SUCCESS == m_LastCR;
  1809. }
  1810. BOOL
  1811. CMachine::CmSetHwProfileFlags(
  1812. DEVNODE dn,
  1813. ULONG Profile,
  1814. ULONG Flags
  1815. )
  1816. {
  1817. TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
  1818. m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID),
  1819. 0, m_hMachine);
  1820. if (CR_SUCCESS == m_LastCR) {
  1821. return CmSetHwProfileFlags(DeviceID, Profile, Flags);
  1822. }
  1823. return FALSE;
  1824. }
  1825. BOOL
  1826. CMachine::CmSetHwProfileFlags(
  1827. LPCTSTR DeviceID,
  1828. ULONG Profile,
  1829. ULONG Flags
  1830. )
  1831. {
  1832. m_LastCR = CM_Set_HW_Prof_Flags_Ex((LPTSTR)DeviceID, Profile, Flags, 0,
  1833. m_hMachine);
  1834. return CR_SUCCESS == m_LastCR;
  1835. }
  1836. BOOL
  1837. CMachine::CmGetCurrentHwProfile(
  1838. ULONG* phwpf
  1839. )
  1840. {
  1841. HWPROFILEINFO hwpfInfo;
  1842. ASSERT(phwpf);
  1843. if (CmGetHwProfileInfo(0xFFFFFFFF, &hwpfInfo)) {
  1844. *phwpf = hwpfInfo.HWPI_ulHWProfile;
  1845. return TRUE;
  1846. }
  1847. return FALSE;
  1848. }
  1849. BOOL
  1850. CMachine::CmGetHwProfileInfo(
  1851. int Index,
  1852. PHWPROFILEINFO pHwProfileInfo
  1853. )
  1854. {
  1855. m_LastCR = CM_Get_Hardware_Profile_Info_Ex(Index, pHwProfileInfo, 0, m_hMachine);
  1856. return(CR_SUCCESS == m_LastCR);
  1857. }
  1858. ULONG
  1859. CMachine::CmGetResDesDataSize(
  1860. RES_DES rd
  1861. )
  1862. {
  1863. ULONG Size;
  1864. m_LastCR = CM_Get_Res_Des_Data_Size_Ex(&Size, rd, 0, m_hMachine);
  1865. if (CR_SUCCESS == m_LastCR) {
  1866. return Size;
  1867. }
  1868. return 0;
  1869. }
  1870. BOOL
  1871. CMachine::CmGetResDesData(
  1872. RES_DES rd,
  1873. PVOID Buffer,
  1874. ULONG BufferSize
  1875. )
  1876. {
  1877. m_LastCR = CM_Get_Res_Des_Data_Ex(rd, Buffer, BufferSize, 0, m_hMachine);
  1878. return CR_SUCCESS == m_LastCR;
  1879. }
  1880. BOOL
  1881. CMachine::CmGetNextResDes(
  1882. PRES_DES prdNext,
  1883. RES_DES rd,
  1884. RESOURCEID ForResource,
  1885. PRESOURCEID pTheResource
  1886. )
  1887. {
  1888. m_LastCR = CM_Get_Next_Res_Des_Ex(prdNext, rd, ForResource, pTheResource,
  1889. 0, m_hMachine);
  1890. return(CR_SUCCESS == m_LastCR);
  1891. }
  1892. void
  1893. CMachine::CmFreeResDesHandle(
  1894. RES_DES rd
  1895. )
  1896. {
  1897. m_LastCR = CM_Free_Res_Des_Handle(rd);
  1898. }
  1899. void
  1900. CMachine::CmFreeResDes(
  1901. PRES_DES prdPrev,
  1902. RES_DES rd
  1903. )
  1904. {
  1905. m_LastCR = CM_Free_Res_Des_Ex(prdPrev, rd, 0, m_hMachine);
  1906. }
  1907. void
  1908. CMachine::CmFreeLogConfHandle(
  1909. LOG_CONF lc
  1910. )
  1911. {
  1912. m_LastCR = CM_Free_Log_Conf_Handle(lc);
  1913. }
  1914. BOOL
  1915. CMachine::CmGetFirstLogConf(
  1916. DEVNODE dn,
  1917. LOG_CONF* plc,
  1918. ULONG Type
  1919. )
  1920. {
  1921. m_LastCR = CM_Get_First_Log_Conf_Ex(plc, dn, Type, m_hMachine);
  1922. return CR_SUCCESS == m_LastCR;
  1923. }
  1924. CONFIGRET
  1925. CMachine::CmGetRegistryProperty(
  1926. DEVNODE dn,
  1927. ULONG Property,
  1928. PVOID pBuffer,
  1929. ULONG* pBufferSize
  1930. )
  1931. {
  1932. return CM_Get_DevNode_Registry_Property_Ex(dn, Property, NULL,
  1933. pBuffer, pBufferSize,
  1934. 0, m_hMachine
  1935. );
  1936. }
  1937. CONFIGRET
  1938. CMachine::CmGetRegistrySoftwareProperty(
  1939. DEVNODE dn,
  1940. LPCTSTR ValueName,
  1941. PVOID pBuffer,
  1942. ULONG* pBufferSize
  1943. )
  1944. {
  1945. HKEY hKey;
  1946. DWORD Type = REG_SZ;
  1947. CONFIGRET CR;
  1948. if (CR_SUCCESS == (CR = CM_Open_DevNode_Key_Ex(dn, KEY_READ, 0, RegDisposition_OpenExisting,
  1949. &hKey, CM_REGISTRY_SOFTWARE, m_hMachine))) {
  1950. if (ERROR_SUCCESS != RegQueryValueEx(hKey, ValueName, NULL, &Type, (const PBYTE)pBuffer,
  1951. pBufferSize)) {
  1952. CR = CR_REGISTRY_ERROR;
  1953. }
  1954. RegCloseKey(hKey);
  1955. }
  1956. return CR;
  1957. }
  1958. CMachineList::~CMachineList()
  1959. {
  1960. if (!m_listMachines.IsEmpty()) {
  1961. POSITION pos = m_listMachines.GetHeadPosition();
  1962. CMachine* pMachine;
  1963. while (NULL != pos) {
  1964. pMachine = m_listMachines.GetNext(pos);
  1965. delete pMachine;
  1966. }
  1967. m_listMachines.RemoveAll();
  1968. }
  1969. }
  1970. //
  1971. // This function creates a machine object on the given machine name
  1972. // INPUT:
  1973. // MachineName -- the machine name. Must be in full qualified format
  1974. // NULL means the local machine
  1975. // ppMachine -- buffer to receive the newly create machine.
  1976. //
  1977. // OUTPUT:
  1978. // TRUE if the machine is created successfully. ppMachine
  1979. // is filled with the newly created Machine.
  1980. // FALSE if the function failed.
  1981. // NOTE:
  1982. // The caller should NOT free any machine object retruned
  1983. // from this function.
  1984. //
  1985. BOOL
  1986. CMachineList::CreateMachine(
  1987. LPCTSTR MachineName,
  1988. CMachine** ppMachine
  1989. )
  1990. {
  1991. ASSERT(ppMachine);
  1992. *ppMachine = NULL;
  1993. CMachine* pMachine = NULL;
  1994. if (!MachineName || _T('\0') == MachineName[0]) {
  1995. //
  1996. // Local machine.
  1997. //
  1998. String strMachineName;
  1999. strMachineName.GetComputerName();
  2000. pMachine = FindMachine(strMachineName);
  2001. }
  2002. else {
  2003. pMachine = FindMachine(MachineName);
  2004. }
  2005. if (NULL == pMachine) {
  2006. pMachine = new CMachine(MachineName);
  2007. m_listMachines.AddTail(pMachine);
  2008. }
  2009. *ppMachine = pMachine;
  2010. return NULL != pMachine;
  2011. }
  2012. CMachine*
  2013. CMachineList::FindMachine(
  2014. LPCTSTR MachineName
  2015. )
  2016. {
  2017. if (!m_listMachines.IsEmpty()) {
  2018. POSITION pos = m_listMachines.GetHeadPosition();
  2019. while (NULL != pos) {
  2020. CMachine* pMachine;
  2021. pMachine = m_listMachines.GetNext(pos);
  2022. if (!lstrcmpi(MachineName, pMachine->GetMachineFullName())) {
  2023. return pMachine;
  2024. }
  2025. }
  2026. }
  2027. return NULL;
  2028. }