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

3227 lines
86 KiB

  1. /*++
  2. Copyright (C) 1997-1999 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. //
  19. //private setupapi export
  20. //
  21. DWORD
  22. pSetupGuidFromString(
  23. PWCHAR GuidString,
  24. LPGUID Guid
  25. );
  26. CONST TCHAR* DEVMGR_NOTIFY_CLASS_NAME = TEXT("DevMgrNotifyClass");
  27. CONST TCHAR* DEVMGR_REFRESH_MSG = TEXT("DevMgrRefreshOn");
  28. //
  29. // The constant is the size we use to allocate GUID list from within
  30. // stack when we have to build a GUID list. The aim of this is
  31. // that buiding a guid list take time and in many case, a minimum
  32. // buffer should retrive all of them. We do not want to get
  33. // the size first, allocate buffer and get it again.
  34. // 64 looks to be fair enough value because there are not
  35. // many classes out there today (and maybe, in the future).
  36. //
  37. const int GUID_LIST_INIT_SIZE = 64;
  38. //
  39. // CDevInfoList implementation
  40. //
  41. BOOL
  42. CDevInfoList::DiGetExtensionPropSheetPage(
  43. PSP_DEVINFO_DATA DevData,
  44. LPFNADDPROPSHEETPAGE pfnAddPropSheetPage,
  45. DWORD PageType,
  46. LPARAM lParam
  47. )
  48. {
  49. SP_PROPSHEETPAGE_REQUEST PropPageRequest;
  50. LPFNADDPROPSHEETPAGES AddPropPages;
  51. PropPageRequest.cbSize = sizeof(PropPageRequest);
  52. PropPageRequest.PageRequested = PageType;
  53. PropPageRequest.DeviceInfoSet = m_hDevInfo;
  54. PropPageRequest.DeviceInfoData = DevData;
  55. if (SPPSR_SELECT_DEVICE_RESOURCES == PageType) {
  56. HINSTANCE hModule = ::GetModuleHandle(TEXT("setupapi.dll"));
  57. if (hModule) {
  58. AddPropPages = (LPFNADDPROPSHEETPAGES)GetProcAddress(hModule, "ExtensionPropSheetPageProc");
  59. if (AddPropPages) {
  60. if (AddPropPages(&PropPageRequest, pfnAddPropSheetPage, lParam)) {
  61. return TRUE;
  62. }
  63. }
  64. }
  65. }
  66. return FALSE;
  67. }
  68. BOOL
  69. CDevInfoList::InstallDevInst(
  70. HWND hwndParent,
  71. LPCTSTR DeviceId,
  72. BOOL UpdateDriver,
  73. DWORD* pReboot
  74. )
  75. {
  76. BOOL Result = FALSE;
  77. HINSTANCE hLib = LoadLibrary(TEXT("newdev.dll"));
  78. LPFNINSTALLDEVINST InstallDevInst;
  79. DWORD Status = ERROR_SUCCESS;
  80. if (hLib) {
  81. InstallDevInst = (LPFNINSTALLDEVINST)GetProcAddress(hLib, "InstallDevInst");
  82. if (InstallDevInst) {
  83. Result = (*InstallDevInst)(hwndParent, DeviceId, UpdateDriver,
  84. pReboot);
  85. Status = GetLastError();
  86. }
  87. }
  88. if (hLib) {
  89. FreeLibrary(hLib);
  90. }
  91. //
  92. // We need to put back the error code that was set by newdev.dll's InstallDevInst
  93. // API. This last error gets overwritten by FreeLibrary which we don't care about.
  94. //
  95. SetLastError(Status);
  96. return Result;
  97. }
  98. BOOL
  99. CDevInfoList::RollbackDriver(
  100. HWND hwndParent,
  101. LPCTSTR RegistryKeyName,
  102. DWORD Flags,
  103. DWORD* pReboot
  104. )
  105. {
  106. BOOL Result = FALSE;
  107. HINSTANCE hLib = LoadLibrary(TEXT("newdev.dll"));
  108. LPFNROLLBACKDRIVER RollbackDriver;
  109. if (hLib) {
  110. RollbackDriver = (LPFNROLLBACKDRIVER)GetProcAddress(hLib, "RollbackDriver");
  111. if (RollbackDriver) {
  112. Result = (*RollbackDriver)(hwndParent, RegistryKeyName, Flags, pReboot);
  113. }
  114. }
  115. if (hLib) {
  116. FreeLibrary(hLib);
  117. }
  118. return Result;
  119. }
  120. DWORD
  121. CDevInfoList::DiGetFlags(
  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.Flags;
  129. }
  130. return 0;
  131. }
  132. DWORD
  133. CDevInfoList::DiGetExFlags(
  134. PSP_DEVINFO_DATA DevData
  135. )
  136. {
  137. SP_DEVINSTALL_PARAMS dip;
  138. dip.cbSize = sizeof(dip);
  139. if (DiGetDeviceInstallParams(DevData, &dip)) {
  140. return dip.FlagsEx;
  141. }
  142. return 0;
  143. }
  144. BOOL
  145. CDevInfoList::DiTurnOnDiFlags(
  146. PSP_DEVINFO_DATA DevData,
  147. DWORD FlagsMask
  148. )
  149. {
  150. SP_DEVINSTALL_PARAMS dip;
  151. dip.cbSize = sizeof(dip);
  152. if (DiGetDeviceInstallParams(DevData, &dip)) {
  153. dip.Flags |= FlagsMask;
  154. return DiSetDeviceInstallParams(DevData, &dip);
  155. }
  156. return FALSE;
  157. }
  158. BOOL
  159. CDevInfoList::DiTurnOffDiFlags(
  160. PSP_DEVINFO_DATA DevData,
  161. DWORD FlagsMask
  162. )
  163. {
  164. SP_DEVINSTALL_PARAMS dip;
  165. dip.cbSize = sizeof(dip);
  166. if (DiGetDeviceInstallParams(DevData, &dip)) {
  167. dip.Flags &= ~FlagsMask;
  168. return DiSetDeviceInstallParams(DevData, &dip);
  169. }
  170. return FALSE;
  171. }
  172. BOOL
  173. CDevInfoList::DiTurnOnDiExFlags(
  174. PSP_DEVINFO_DATA DevData,
  175. DWORD FlagsMask
  176. )
  177. {
  178. SP_DEVINSTALL_PARAMS dip;
  179. dip.cbSize = sizeof(dip);
  180. if (DiGetDeviceInstallParams(DevData, &dip)) {
  181. dip.FlagsEx |= FlagsMask;
  182. return DiSetDeviceInstallParams(DevData, &dip);
  183. }
  184. return FALSE;
  185. }
  186. BOOL
  187. CDevInfoList::DiTurnOffDiExFlags(
  188. PSP_DEVINFO_DATA DevData,
  189. DWORD FlagsMask
  190. )
  191. {
  192. SP_DEVINSTALL_PARAMS dip;
  193. dip.cbSize = sizeof(dip);
  194. if (DiGetDeviceInstallParams(DevData, &dip)) {
  195. dip.FlagsEx &= ~FlagsMask;
  196. return DiSetDeviceInstallParams(DevData, &dip);
  197. }
  198. return FALSE;
  199. }
  200. void
  201. CDevInfoList::DiDestroyDeviceInfoList()
  202. {
  203. if (INVALID_HANDLE_VALUE != m_hDevInfo) {
  204. SetupDiDestroyDeviceInfoList(m_hDevInfo);
  205. m_hDevInfo = INVALID_HANDLE_VALUE;
  206. }
  207. }
  208. BOOL
  209. CDevInfoList::DiGetDeviceMFGString(
  210. PSP_DEVINFO_DATA DevData,
  211. TCHAR* pBuffer,
  212. DWORD Size,
  213. DWORD* pRequiredSize
  214. )
  215. {
  216. if (Size && !pBuffer) {
  217. SetLastError(ERROR_INVALID_PARAMETER);
  218. return FALSE;
  219. }
  220. DWORD ActualSize = 0;
  221. BOOL Result;
  222. Result = DiGetDeviceRegistryProperty(DevData, SPDRP_MFG, NULL,
  223. (PBYTE)pBuffer,
  224. Size * sizeof(TCHAR),
  225. &ActualSize);
  226. if (pRequiredSize) {
  227. *pRequiredSize = ActualSize / sizeof(TCHAR);
  228. }
  229. return Result;
  230. }
  231. BOOL
  232. CDevInfoList::DiGetDeviceMFGString(
  233. PSP_DEVINFO_DATA DevData,
  234. String& str
  235. )
  236. {
  237. DWORD RequiredSize = 0;
  238. TCHAR MFG[LINE_LEN];
  239. if (DiGetDeviceMFGString(DevData, MFG, ARRAYLEN(MFG), &RequiredSize)) {
  240. str = MFG;
  241. return TRUE;
  242. }
  243. return FALSE;
  244. }
  245. BOOL
  246. CDevInfoList::DiGetDeviceIDString(
  247. PSP_DEVINFO_DATA DevData,
  248. TCHAR* pBuffer,
  249. DWORD Size,
  250. DWORD* pRequiredSize
  251. )
  252. {
  253. if (Size && !pBuffer) {
  254. SetLastError(ERROR_INVALID_PARAMETER);
  255. return FALSE;
  256. }
  257. DWORD ActualSize = 0;
  258. BOOL Result;
  259. Result = DiGetDeviceRegistryProperty(DevData, SPDRP_HARDWAREID, NULL,
  260. (PBYTE) pBuffer,
  261. Size * sizeof(TCHAR), &ActualSize);
  262. if (pRequiredSize) {
  263. *pRequiredSize = ActualSize / sizeof(TCHAR);
  264. }
  265. return Result;
  266. }
  267. BOOL
  268. CDevInfoList::DiGetDeviceIDString(
  269. PSP_DEVINFO_DATA DevData,
  270. String& str
  271. )
  272. {
  273. BOOL Result;
  274. DWORD RequiredSize = 0;
  275. TCHAR DeviceId[MAX_DEVICE_ID_LEN];
  276. if (DiGetDeviceIDString(DevData, DeviceId, ARRAYLEN(DeviceId), &RequiredSize)) {
  277. str = DeviceId;
  278. return TRUE;
  279. }
  280. return FALSE;
  281. }
  282. /////////////////////////////////////////////////////////////////////
  283. //// CMachine implementation
  284. ////
  285. //
  286. // For every single instance of DevMgr.dll, we maintain a CMachine list
  287. // from which different instances of IComponentData(and IComponent) will
  288. // attach to. The objects created(CDevice, Class, HDEVINFO and etc) are
  289. // shared by all the attached IComponentData and IComponent(the implementation
  290. // use CFolder as the controlling identify).
  291. // Everything changed to the CMachine or one of its object will inform
  292. // all the attached CFolders which would pass the information down to their
  293. // sub-objects(CResultView).
  294. // Imaging that you have two Device Manager window in the same console
  295. // and you do a refresh on one the window. The other window must also
  296. // do a refresh after the first one is done. Since both windows shares
  297. // the same machine(and will get the same notification when machine states
  298. // changed), we can keep the two windows in sync.
  299. CMachine::CMachine(
  300. LPCTSTR pMachineName
  301. )
  302. {
  303. InitializeCriticalSection(&m_CriticalSection);
  304. InitializeCriticalSection(&m_PropertySheetCriticalSection);
  305. InitializeCriticalSection(&m_ChildMachineCriticalSection);
  306. //
  307. // Get various privilege levels, like if the user has the SE_LOAD_DRIVER_NAME
  308. // privileg or if the user is a Guest.
  309. //
  310. g_HasLoadDriverNamePrivilege = pSetupDoesUserHavePrivilege((PCTSTR)SE_LOAD_DRIVER_NAME);
  311. m_UserIsAGuest = SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_GUESTS);
  312. m_RefreshDisableCounter = 0;
  313. m_RefreshPending = FALSE;
  314. m_pComputer = NULL;
  315. m_hMachine = NULL;
  316. m_ParentMachine = NULL;
  317. m_Initialized = FALSE;
  318. TCHAR LocalName[MAX_PATH + 1];
  319. DWORD dwSize = sizeof(LocalName) / sizeof(TCHAR);
  320. if (!GetComputerName(LocalName, &dwSize)) {
  321. LocalName[0] = _T('\0');
  322. }
  323. m_strMachineFullName.Empty();
  324. m_strMachineDisplayName.Empty();
  325. //
  326. // Skip over any leading '\' chars
  327. //
  328. if (pMachineName && _T('\0') != *pMachineName) {
  329. int len = lstrlen(pMachineName);
  330. ASSERT(len >= 3 && _T('\\') == pMachineName[0] && _T('\\') == pMachineName[1]);
  331. m_strMachineDisplayName = &pMachineName[2];
  332. m_strMachineFullName = pMachineName;
  333. m_IsLocal = (0 == m_strMachineDisplayName.CompareNoCase(LocalName));
  334. }
  335. else {
  336. //
  337. // Local machine
  338. //
  339. m_strMachineDisplayName = LocalName;
  340. m_strMachineFullName = TEXT("\\\\") + m_strMachineDisplayName;
  341. m_IsLocal = TRUE;
  342. }
  343. m_hwndNotify = NULL;
  344. m_msgRefresh = 0;
  345. m_ShowNonPresentDevices = FALSE;
  346. m_PropertySheetShoudDestroy = FALSE;
  347. TCHAR Buffer[MAX_PATH];
  348. DWORD BufferLen;
  349. //
  350. // If the environment variable DEVMGR_SHOW_NONPRESENT_DEVICES does exist and it
  351. // is not 0 then we will show Phantom devices.
  352. //
  353. if (((BufferLen = ::GetEnvironmentVariable(TEXT("DEVMGR_SHOW_NONPRESENT_DEVICES"),
  354. Buffer,
  355. sizeof(Buffer)/sizeof(TCHAR))) != 0) &&
  356. ((BufferLen > 1) ||
  357. (lstrcmp(Buffer, TEXT("0"))))) {
  358. m_ShowNonPresentDevices = TRUE;
  359. }
  360. }
  361. BOOL
  362. CMachine::Initialize(
  363. IN HWND hwndParent,
  364. IN LPCTSTR DeviceId, OPTIONAL
  365. IN LPGUID ClassGuid OPTIONAL
  366. )
  367. {
  368. BOOL Result = TRUE;
  369. m_hwndParent = hwndParent;
  370. if (m_Initialized) {
  371. return TRUE;
  372. }
  373. if (DeviceId && _T('\0') == *DeviceId) {
  374. DeviceId = NULL;
  375. }
  376. HCURSOR hCursorOld;
  377. hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  378. if (DeviceId || ClassGuid) {
  379. //
  380. // We are ready for device change notification, create the notify window
  381. //
  382. //Result = CreateNotifyWindow();
  383. if (CreateClassesAndDevices(DeviceId, ClassGuid)) {
  384. m_Initialized = TRUE;
  385. }
  386. } else {
  387. //
  388. // We are ready for device change notification, create the notify window
  389. //
  390. Result = CreateNotifyWindow();
  391. m_Initialized = TRUE;
  392. ScheduleRefresh();
  393. }
  394. if (hCursorOld) {
  395. SetCursor(hCursorOld);
  396. }
  397. return Result;
  398. }
  399. BOOL
  400. CMachine::ScheduleRefresh()
  401. {
  402. Lock();
  403. //
  404. // Only queue the the request if there is no requests outstanding
  405. // and we have a valid window handle/message to the notify window.
  406. //
  407. if (!m_RefreshPending && m_hwndNotify && m_msgRefresh) {
  408. //
  409. // Broadcast the message so that every instance runs on
  410. // the computer get the notification
  411. //
  412. ::PostMessage(HWND_BROADCAST, m_msgRefresh, 0, 0);
  413. }
  414. Unlock();
  415. return TRUE;
  416. }
  417. //
  418. // This function creates a data window to receive WM_DEVICECHANGE notification
  419. // so that we can refresh the device tree. It also registers a private
  420. // message so that anybody can post a refresh request.
  421. //
  422. BOOL
  423. CMachine::CreateNotifyWindow()
  424. {
  425. WNDCLASS wndClass;
  426. //
  427. // Lets see if the class has been registered.
  428. //
  429. if (!GetClassInfo(g_hInstance, DEVMGR_NOTIFY_CLASS_NAME, &wndClass)) {
  430. //
  431. // Register the class
  432. //
  433. memset(&wndClass, 0, sizeof(wndClass));
  434. wndClass.lpfnWndProc = dmNotifyWndProc;
  435. wndClass.hInstance = g_hInstance;
  436. wndClass.lpszClassName = DEVMGR_NOTIFY_CLASS_NAME;
  437. if (!RegisterClass(&wndClass)) {
  438. return FALSE;
  439. }
  440. }
  441. //
  442. // Register a private message for refresh. The name must contain
  443. // the target machine name so that every machine has its own message.
  444. //
  445. String strMsg = DEVMGR_REFRESH_MSG;
  446. strMsg += m_strMachineDisplayName;
  447. m_msgRefresh = RegisterWindowMessage(strMsg);
  448. if (m_msgRefresh) {
  449. //
  450. // Create a data window.
  451. //
  452. m_hwndNotify = CreateWindowEx(WS_EX_TOOLWINDOW, DEVMGR_NOTIFY_CLASS_NAME,
  453. TEXT(""),
  454. WS_DLGFRAME|WS_BORDER|WS_DISABLED,
  455. CW_USEDEFAULT, CW_USEDEFAULT,
  456. 0, 0, NULL, NULL, g_hInstance, (void*)this);
  457. return(NULL != m_hwndNotify);
  458. }
  459. return FALSE;
  460. }
  461. //
  462. // This is the WM_DEVICECHANGE window procedure running in the main thread
  463. // context. It listens to two messages:
  464. // (1). WM_DEVICECHANGE broadcasted by Configuration Manager on device
  465. // addition/removing.
  466. // (2). Private refresh message broadcasted by different instance
  467. // of Device Manager targeting on the same machine.
  468. // On WM_CREATE, we participate the WM_DEVICECHANGE notification chain
  469. // while on WM_DESTROY, we detach oursleves from the chain.
  470. // There are occasions that we have to detach and re-attach to the
  471. // chain duing the window life time, for example, during device uninstallation
  472. // or during re-enumeration. The EnableFresh function is the place
  473. // that does the attach/detach.
  474. //
  475. //
  476. LRESULT
  477. dmNotifyWndProc(
  478. HWND hWnd,
  479. UINT uMsg,
  480. WPARAM wParam,
  481. LPARAM lParam
  482. )
  483. {
  484. CMachine* pThis;
  485. pThis = (CMachine*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  486. //
  487. // Special case for private refresh message
  488. //
  489. if (pThis && uMsg == pThis->m_msgRefresh) {
  490. pThis->Refresh();
  491. return FALSE;
  492. }
  493. switch (uMsg) {
  494. case WM_CREATE:
  495. {
  496. pThis = (CMachine*)((CREATESTRUCT*)lParam)->lpCreateParams;
  497. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
  498. break;
  499. }
  500. case WM_DEVICECHANGE:
  501. {
  502. if (DBT_DEVNODES_CHANGED == wParam) {
  503. //
  504. // While we are in WM_DEVICECHANGE context,
  505. // no CM apis can be called because it would
  506. // deadlock. Here, we schedule a timer so that
  507. // we can handle the message later on.
  508. //
  509. SetTimer(hWnd, DM_NOTIFY_TIMERID, 1000, NULL);
  510. }
  511. break;
  512. }
  513. case WM_TIMER:
  514. {
  515. if (DM_NOTIFY_TIMERID == wParam) {
  516. KillTimer(hWnd, DM_NOTIFY_TIMERID);
  517. ASSERT(pThis);
  518. pThis->ScheduleRefresh();
  519. }
  520. break;
  521. }
  522. default:
  523. break;
  524. }
  525. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  526. }
  527. //
  528. // This function attaches the given CFolder to the class.
  529. // An attached CFolder will get notified when there are state
  530. // changes in the class(Refresh, property changes, for example).
  531. //
  532. BOOL
  533. CMachine::AttachFolder(
  534. CFolder* pFolder
  535. )
  536. {
  537. ASSERT(pFolder);
  538. if (!IsFolderAttached(pFolder)) {
  539. pFolder->MachinePropertyChanged(this);
  540. m_listFolders.AddTail(pFolder);
  541. }
  542. return TRUE;
  543. }
  544. BOOL
  545. CMachine::IsFolderAttached(
  546. CFolder* pFolder
  547. )
  548. {
  549. if (!m_listFolders.IsEmpty()) {
  550. POSITION pos = m_listFolders.GetHeadPosition();
  551. while (NULL != pos) {
  552. if (pFolder == m_listFolders.GetNext(pos)) {
  553. return TRUE;
  554. }
  555. }
  556. }
  557. return FALSE;
  558. }
  559. void
  560. CMachine::DetachFolder(
  561. CFolder* pFolder
  562. )
  563. {
  564. POSITION nextpos = m_listFolders.GetHeadPosition();
  565. while (nextpos) {
  566. POSITION pos = nextpos;
  567. CFolder* pFolderToTest = m_listFolders.GetNext(nextpos);
  568. if (pFolderToTest == pFolder) {
  569. m_listFolders.RemoveAt(pos);
  570. break;
  571. }
  572. }
  573. }
  574. BOOL
  575. CMachine::AttachPropertySheet(
  576. HWND hwndPropertySheet
  577. )
  578. {
  579. ASSERT(hwndPropertySheet);
  580. EnterCriticalSection(&m_PropertySheetCriticalSection);
  581. m_listPropertySheets.AddTail(hwndPropertySheet);
  582. LeaveCriticalSection(&m_PropertySheetCriticalSection);
  583. return TRUE;
  584. }
  585. void
  586. CMachine::DetachPropertySheet(
  587. HWND hwndPropertySheet
  588. )
  589. {
  590. EnterCriticalSection(&m_PropertySheetCriticalSection);
  591. POSITION nextpos = m_listPropertySheets.GetHeadPosition();
  592. while (nextpos) {
  593. POSITION pos = nextpos;
  594. HWND hwndPropertySheetToTest = m_listPropertySheets.GetNext(nextpos);
  595. if (hwndPropertySheetToTest == hwndPropertySheet) {
  596. m_listPropertySheets.RemoveAt(pos);
  597. break;
  598. }
  599. }
  600. LeaveCriticalSection(&m_PropertySheetCriticalSection);
  601. }
  602. HWND
  603. CMachine::GetDeviceWindowHandle(
  604. LPCTSTR DeviceId
  605. )
  606. {
  607. HWND hwnd = NULL;
  608. EnterCriticalSection(&m_ChildMachineCriticalSection);
  609. //
  610. // Enumerate the list of Child CMachines
  611. //
  612. if (!m_listChildMachines.IsEmpty()) {
  613. PVOID DeviceContext;
  614. CDevice* pDevice;
  615. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  616. while (nextpos) {
  617. CMachine* pChildMachine = m_listChildMachines.GetNext(nextpos);
  618. //
  619. // Child machines will only have one device (if any at all)
  620. //
  621. if (pChildMachine->GetFirstDevice(&pDevice, DeviceContext) &&
  622. pDevice) {
  623. //
  624. // If the device Ids match then get the window handle
  625. //
  626. if (lstrcmpi(pDevice->GetDeviceID(), DeviceId) == 0) {
  627. hwnd = pDevice->m_psd.GetWindowHandle();
  628. break;
  629. }
  630. }
  631. }
  632. }
  633. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  634. return hwnd;
  635. }
  636. HWND
  637. CMachine::GetClassWindowHandle(
  638. LPGUID ClassGuid
  639. )
  640. {
  641. HWND hwnd = NULL;
  642. EnterCriticalSection(&m_ChildMachineCriticalSection);
  643. //
  644. // Enumerate the list of Child CMachines
  645. //
  646. if (!m_listChildMachines.IsEmpty()) {
  647. PVOID ClassContext;
  648. CClass* pClass;
  649. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  650. while (nextpos) {
  651. CMachine* pChildMachine = m_listChildMachines.GetNext(nextpos);
  652. //
  653. // Any child CMachine that has a device is a device property sheet.
  654. // We only want to look at the ones that have 0 devices since those
  655. // will be class property sheets.
  656. //
  657. if (pChildMachine->GetNumberOfDevices() == 0) {
  658. if (pChildMachine->GetFirstClass(&pClass, ClassContext) &&
  659. pClass) {
  660. //
  661. // If the ClassGuids match then get the window handle
  662. //
  663. if (IsEqualGUID(*ClassGuid, *pClass)) {
  664. hwnd = pClass->m_psd.GetWindowHandle();
  665. break;
  666. }
  667. }
  668. }
  669. }
  670. }
  671. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  672. return hwnd;
  673. }
  674. BOOL
  675. CMachine::AttachChildMachine(
  676. CMachine* ChildMachine
  677. )
  678. {
  679. ASSERT(ChildMachine);
  680. EnterCriticalSection(&m_ChildMachineCriticalSection);
  681. m_listChildMachines.AddTail(ChildMachine);
  682. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  683. return TRUE;
  684. }
  685. void
  686. CMachine::DetachChildMachine(
  687. CMachine* ChildMachine
  688. )
  689. {
  690. EnterCriticalSection(&m_ChildMachineCriticalSection);
  691. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  692. while (nextpos) {
  693. POSITION pos = nextpos;
  694. CMachine* CMachineToTest = m_listChildMachines.GetNext(nextpos);
  695. if (CMachineToTest == ChildMachine) {
  696. m_listChildMachines.RemoveAt(pos);
  697. break;
  698. }
  699. }
  700. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  701. }
  702. CMachine::~CMachine()
  703. {
  704. //
  705. // Turn off refresh. We need to do this in case there are any property
  706. // sheets that are still active.
  707. //
  708. EnableRefresh(FALSE);
  709. //
  710. // We first need to destroy all child CMachines
  711. //
  712. while (!m_listChildMachines.IsEmpty()) {
  713. //
  714. // Remove the first child machine from the list. We need to
  715. // do this in the critical section.
  716. //
  717. EnterCriticalSection(&m_ChildMachineCriticalSection);
  718. CMachine* ChildMachine = m_listChildMachines.RemoveHead();
  719. //
  720. // Set the m_ParentMachine to NULL so we won't try to remove it from
  721. // the list again.
  722. //
  723. ChildMachine->m_ParentMachine = NULL;
  724. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  725. delete ChildMachine;
  726. }
  727. //
  728. // We need to wait for all of the property sheets to be destroyed.
  729. //
  730. // We will check to see if there are any property pages still around, and
  731. // if there is we will wait for 1 second and then check again. After 5
  732. // seconds we will give up and just destroy the CMachine anyway.
  733. //
  734. int iSecondsCount = 0;
  735. while (!m_listPropertySheets.IsEmpty() &&
  736. (iSecondsCount++ < 10)) {
  737. //
  738. // Enumerate through all of the property sheets left and if IsWindow fails
  739. // then pull them from the list, otherwise call DestroyWindow on them.
  740. //
  741. // Since property sheets each run in their own thread we need to do this
  742. // in a critical section.
  743. //
  744. EnterCriticalSection(&m_PropertySheetCriticalSection);
  745. POSITION nextpos = m_listPropertySheets.GetHeadPosition();
  746. while (nextpos) {
  747. POSITION pos = nextpos;
  748. HWND hwndPropertySheetToTest = m_listPropertySheets.GetNext(nextpos);
  749. if (IsWindow(hwndPropertySheetToTest)) {
  750. //
  751. // There is still a valid window for this property sheet so
  752. // call DestroyWindow on it.
  753. //
  754. ::DestroyWindow(hwndPropertySheetToTest);
  755. } else {
  756. //
  757. // There is no window for this property sheet so just remove
  758. // it from the list
  759. //
  760. m_listPropertySheets.RemoveAt(pos);
  761. }
  762. }
  763. LeaveCriticalSection(&m_PropertySheetCriticalSection);
  764. //
  765. // Sleep for .5 seconds and then try again. This will give the property pages time to
  766. // finish up their work.
  767. //
  768. Sleep(500);
  769. }
  770. // if we have created a device change data window for this machine,
  771. // destroy it.
  772. if (m_hwndNotify && IsWindow(m_hwndNotify)) {
  773. ::DestroyWindow(m_hwndNotify);
  774. m_hwndNotify = NULL;
  775. }
  776. DestroyClassesAndDevices();
  777. if (!m_listFolders.IsEmpty()) {
  778. m_listFolders.RemoveAll();
  779. }
  780. //
  781. // If we have a parent CMachine then we need to remove oursleves from
  782. // his list of Child CMachines.
  783. //
  784. if (m_ParentMachine) {
  785. m_ParentMachine->DetachChildMachine(this);
  786. }
  787. DeleteCriticalSection(&m_CriticalSection);
  788. DeleteCriticalSection(&m_PropertySheetCriticalSection);
  789. DeleteCriticalSection(&m_ChildMachineCriticalSection);
  790. }
  791. //
  792. // This function destroys all the CClass and CDevice we ever created.
  793. // No notification is sent for the attached folder
  794. //
  795. //
  796. void
  797. CMachine::DestroyClassesAndDevices()
  798. {
  799. if (m_pComputer) {
  800. delete m_pComputer;
  801. m_pComputer = NULL;
  802. }
  803. if (!m_listDevice.IsEmpty()) {
  804. POSITION pos = m_listDevice.GetHeadPosition();
  805. while (NULL != pos) {
  806. CDevice* pDevice = m_listDevice.GetNext(pos);
  807. delete pDevice;
  808. }
  809. m_listDevice.RemoveAll();
  810. }
  811. if (!m_listClass.IsEmpty()) {
  812. POSITION pos = m_listClass.GetHeadPosition();
  813. while (NULL != pos) {
  814. CClass* pClass = m_listClass.GetNext(pos);
  815. delete pClass;
  816. }
  817. m_listClass.RemoveAll();
  818. }
  819. if (m_ImageListData.cbSize) {
  820. DiDestroyClassImageList(&m_ImageListData);
  821. }
  822. CDevInfoList::DiDestroyDeviceInfoList();
  823. m_hMachine = NULL;
  824. }
  825. BOOL
  826. CMachine::BuildClassesFromGuidList(
  827. LPGUID GuidList,
  828. DWORD Guids
  829. )
  830. {
  831. DWORD Index;
  832. CClass* pClass;
  833. //
  834. // Build a list of CClass for each GUID.
  835. //
  836. for (Index = 0; Index < Guids; Index++) {
  837. SafePtr<CClass> ClassPtr;
  838. pClass = new CClass(this, &GuidList[Index]);
  839. ClassPtr.Attach(pClass);
  840. m_listClass.AddTail(ClassPtr);
  841. ClassPtr.Detach();
  842. }
  843. return TRUE;
  844. }
  845. //
  846. // Create CClass and CDevice for this machine.
  847. // If DeviceId is valid, this function will create the machine
  848. // with ONLY ONE device(and its CClass)
  849. //
  850. // PERFBUG Optimize this function!!!!!!!
  851. // This function is slow because SetupDiGetClassDevs can take a long
  852. // time (over 1 sec of a 300Mhz machine).
  853. // The other slow part is the call to DoNotCreateDevice which needs to
  854. // go through the service manager for all legacy devnodes to see
  855. // if they are Win32 services (which we don't display). This takes
  856. // around 10ms to get this information from the service manager on
  857. // a 300Mhz machine and their are almost 100 of these legacy devices.
  858. // This means another second of time.
  859. //
  860. //
  861. BOOL
  862. CMachine::CreateClassesAndDevices(
  863. IN LPCTSTR DeviceId, OPTIONAL
  864. IN LPGUID ClassGuid OPTIONAL
  865. )
  866. {
  867. SC_HANDLE SCMHandle = NULL;
  868. //
  869. // Preventing memory leak
  870. //
  871. ASSERT(NULL == m_pComputer);
  872. ASSERT(INVALID_HANDLE_VALUE == m_hDevInfo);
  873. ASSERT(NULL == m_hMachine);
  874. //
  875. // If the object is being created for a single device,
  876. // create a empty device info list. We will add the
  877. // device to the info list later.
  878. //
  879. if (DeviceId || ClassGuid) {
  880. m_hDevInfo = DiCreateDeviceInfoList(ClassGuid, m_hwndParent);
  881. }
  882. else {
  883. //
  884. // We have to pull out the entire devices/classes set
  885. // so create a device info list that contains all of them.
  886. //
  887. m_hDevInfo = DiGetClassDevs(NULL, NULL, m_hwndParent, DIGCF_ALLCLASSES | DIGCF_PROFILE);
  888. }
  889. //
  890. // NULL != INVALID_HANDLE_VALUE. We checked both just be safe.
  891. //
  892. if (INVALID_HANDLE_VALUE == m_hDevInfo || NULL == m_hDevInfo) {
  893. return FALSE;
  894. }
  895. SP_DEVINFO_LIST_DETAIL_DATA DevInfoDetailData;
  896. DevInfoDetailData.cbSize = sizeof(DevInfoDetailData);
  897. //
  898. // Use the HMACHINE returned from Setupapi so that
  899. // every call we make to Cfgmgr32.dll will use the
  900. // same HMACHINE. Two call of CM_Connect_Machine will
  901. // return different hMachines even though they refer to
  902. // the same machine name(and thus, different set of DEVNODE!).
  903. // The catch is that we will be able to call Setuapi and cfgmgr32
  904. // API without worrying about which hMachine to use.
  905. //
  906. if (DiGetDeviceInfoListDetail(&DevInfoDetailData)) {
  907. m_hMachine = DevInfoDetailData.RemoteMachineHandle;
  908. } else {
  909. //
  910. // Unable to get the devinfo detail information.
  911. // In this case we will just default to the local machine.
  912. //
  913. m_hMachine = NULL;
  914. }
  915. //
  916. // Get class image list data;
  917. //
  918. m_ImageListData.cbSize = sizeof(m_ImageListData);
  919. if (DiGetClassImageList(&m_ImageListData)) {
  920. //
  921. // Add extra icons
  922. //
  923. HICON hIcon;
  924. if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DEVMGR))) != NULL) {
  925. m_ComputerIndex = ImageList_AddIcon(m_ImageListData.ImageList, hIcon);
  926. DestroyIcon(hIcon);
  927. }
  928. if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_RESOURCES))) != NULL) {
  929. m_ResourceIndex = ImageList_AddIcon(m_ImageListData.ImageList, hIcon);
  930. DestroyIcon(hIcon);
  931. }
  932. }
  933. //
  934. // If the object is created for a particular device,
  935. // do not create the entire device list because it is
  936. // a waste of time.
  937. //
  938. if (DeviceId) {
  939. SP_DEVINFO_DATA DevData;
  940. GUID DeviceClassGuid;
  941. DevData.cbSize = sizeof(DevData);
  942. if (DiOpenDeviceInfo(DeviceId, m_hwndParent, 0, &DevData) &&
  943. CmGetClassGuid(DevData.DevInst, DeviceClassGuid)) {
  944. //
  945. // Create a CClass for the device(without CClass, no
  946. // device can not be created).
  947. //
  948. CClass* pClass;
  949. SafePtr<CClass> ClassPtr;
  950. pClass = new CClass(this, &DeviceClassGuid);
  951. if (pClass) {
  952. ClassPtr.Attach(pClass);
  953. m_listClass.AddTail(ClassPtr);
  954. //
  955. // The class object has been inserted to the list
  956. // it is safe now to detach the object from the smart pointer
  957. // The class object will be deleted by the list
  958. //
  959. ClassPtr.Detach();
  960. //
  961. // Create the device
  962. //
  963. SafePtr<CDevice> DevicePtr;
  964. CDevice* pDevice;
  965. pDevice = new CDevice(this, pClass, &DevData);
  966. if (pDevice) {
  967. //
  968. // Guard the object
  969. //
  970. DevicePtr.Attach(pDevice);
  971. m_listDevice.AddTail(DevicePtr);
  972. //
  973. // Object added..
  974. //
  975. DevicePtr.Detach();
  976. pClass->AddDevice(pDevice);
  977. }
  978. }
  979. }
  980. //
  981. // We should have one class and one device object. no more no less.
  982. // we are done here.
  983. //
  984. return(1 == m_listClass.GetCount() && 1 == m_listDevice.GetCount());
  985. }
  986. //
  987. // If the object is for a specific class then just create the class and add
  988. // it to the CMachine.
  989. //
  990. else if (ClassGuid) {
  991. CClass* pClass;
  992. SafePtr<CClass> ClassPtr;
  993. pClass = new CClass(this, ClassGuid);
  994. if (pClass) {
  995. ClassPtr.Attach(pClass);
  996. m_listClass.AddTail(ClassPtr);
  997. //
  998. // The class object has been inserted to the list
  999. // it is safe now to detach the object from the smart pointer
  1000. // The class object will be deleted by the list
  1001. //
  1002. ClassPtr.Detach();
  1003. }
  1004. //
  1005. // We should have one class. no more no less.
  1006. // we are done here.
  1007. //
  1008. return(1 == m_listClass.GetCount());
  1009. }
  1010. //
  1011. // Build class guid list
  1012. //
  1013. DWORD ClassGuids, GuidsRequired;
  1014. GuidsRequired = 0;
  1015. //
  1016. // We make a guess here to save us some time.
  1017. //
  1018. GUID LocalGuid[GUID_LIST_INIT_SIZE];
  1019. ClassGuids = GUID_LIST_INIT_SIZE;
  1020. if (DiBuildClassInfoList(0, LocalGuid, ClassGuids, &GuidsRequired)) {
  1021. BuildClassesFromGuidList(LocalGuid, GuidsRequired);
  1022. } else if (ERROR_INSUFFICIENT_BUFFER == GetLastError() && GuidsRequired) {
  1023. //
  1024. // The stack based buffer is too small, allocate buffer from
  1025. // the heap.
  1026. //
  1027. BufferPtr<GUID> ClassGuidList(GuidsRequired);
  1028. if (DiBuildClassInfoList(0, ClassGuidList, GuidsRequired, &ClassGuids)) {
  1029. BuildClassesFromGuidList(ClassGuidList, ClassGuids);
  1030. }
  1031. }
  1032. //
  1033. // If we have any classes at all, create devices objects
  1034. //
  1035. if (!m_listClass.IsEmpty()) {
  1036. DWORD Index = 0;
  1037. SP_DEVINFO_DATA DevData;
  1038. //
  1039. // We need a handle to the service manager in the DoNotCreateDevice
  1040. // function. We will open it once and pass it to this function rather
  1041. // than opening and closing it for every device.
  1042. //
  1043. SCMHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
  1044. //
  1045. // Create every device in the devinfo list and
  1046. // associate each device to its class.
  1047. //
  1048. DevData.cbSize = sizeof(DevData);
  1049. while (DiEnumDeviceInfo(Index, &DevData)) {
  1050. POSITION pos = m_listClass.GetHeadPosition();
  1051. CClass* pClass;
  1052. //
  1053. // Find the class for this device
  1054. //
  1055. while (NULL != pos) {
  1056. pClass = m_listClass.GetNext(pos);
  1057. //
  1058. // Match the ClassGuid for this device.
  1059. // Note that if the device does not have a class guid (GUID_NULL)
  1060. // then we will put it in class GUID_DEVCLASS_UNKNOWN)
  1061. //
  1062. if ((IsEqualGUID(DevData.ClassGuid, *pClass)) ||
  1063. (IsEqualGUID(GUID_DEVCLASS_UNKNOWN, *pClass) &&
  1064. IsEqualGUID(DevData.ClassGuid, GUID_NULL))) {
  1065. //
  1066. // Is this one of the special DevInst that we should
  1067. // not create a CDevice for?
  1068. //
  1069. if (DoNotCreateDevice(SCMHandle, *pClass, DevData.DevInst)) {
  1070. break;
  1071. }
  1072. //
  1073. // Create the device
  1074. //
  1075. SafePtr<CDevice> DevicePtr;
  1076. CDevice* pDevice;
  1077. pDevice = new CDevice(this, pClass, &DevData);
  1078. //
  1079. // Guard the object
  1080. //
  1081. DevicePtr.Attach(pDevice);
  1082. m_listDevice.AddTail(DevicePtr);
  1083. //
  1084. // Object added.
  1085. //
  1086. DevicePtr.Detach();
  1087. //
  1088. // Put the device under the class
  1089. //
  1090. pClass->AddDevice(pDevice);
  1091. break;
  1092. }
  1093. //
  1094. // No class than, no device
  1095. //
  1096. }
  1097. //
  1098. // next device
  1099. //
  1100. Index++;
  1101. }
  1102. CloseServiceHandle(SCMHandle);
  1103. //
  1104. // Create a device tree under computer
  1105. // the tree order comes from DEVNODE structure;
  1106. //
  1107. DEVNODE dnRoot = CmGetRootDevNode();
  1108. m_pComputer = new CComputer(this, dnRoot);
  1109. DEVNODE dnStart = CmGetChild(dnRoot);
  1110. CreateDeviceTree(m_pComputer, NULL, dnStart);
  1111. }
  1112. return TRUE;
  1113. }
  1114. //
  1115. // This function builds a device tree based on the Devnode tree retreived
  1116. // from configuration manager. Note that ALL CDevice are created before
  1117. // this function is called. This function establishs each CDevice relationship.
  1118. //
  1119. void
  1120. CMachine::CreateDeviceTree(
  1121. CDevice* pParent,
  1122. CDevice* pSibling,
  1123. DEVNODE dn
  1124. )
  1125. {
  1126. CDevice* pDevice;
  1127. DEVNODE dnChild, dnSibling;
  1128. while (dn) {
  1129. pDevice = DevNodeToDevice(dn);
  1130. if (pDevice) {
  1131. //
  1132. // No sibling ->this is the first child
  1133. //
  1134. if (!pSibling) {
  1135. pParent->SetChild(pDevice);
  1136. }
  1137. else {
  1138. pSibling->SetSibling(pDevice);
  1139. }
  1140. pDevice->SetParent(pParent);
  1141. pSibling = pDevice;
  1142. dnChild = CmGetChild(dn);
  1143. if (dnChild) {
  1144. CreateDeviceTree(pDevice, NULL, dnChild);
  1145. }
  1146. }
  1147. dn = CmGetSibling(dn);
  1148. }
  1149. }
  1150. //
  1151. // Find CDevice from the given devnode
  1152. //
  1153. CDevice*
  1154. CMachine::DevNodeToDevice(
  1155. DEVNODE dn
  1156. )
  1157. {
  1158. POSITION pos = m_listDevice.GetHeadPosition();
  1159. while (NULL != pos) {
  1160. CDevice* pDevice = m_listDevice.GetNext(pos);
  1161. if (pDevice->GetDevNode() == dn) {
  1162. return pDevice;
  1163. }
  1164. }
  1165. return NULL;
  1166. }
  1167. //
  1168. // Find CDevice from the given device id
  1169. //
  1170. CDevice*
  1171. CMachine::DeviceIDToDevice(
  1172. LPCTSTR DeviceID
  1173. )
  1174. {
  1175. if (!DeviceID) {
  1176. return NULL;
  1177. }
  1178. POSITION pos = m_listDevice.GetHeadPosition();
  1179. while (NULL != pos) {
  1180. CDevice* pDevice = m_listDevice.GetNext(pos);
  1181. if (*pDevice == DeviceID) {
  1182. return pDevice;
  1183. }
  1184. }
  1185. return NULL;
  1186. }
  1187. //
  1188. // Find CClass from the given GUID
  1189. //
  1190. CClass*
  1191. CMachine::ClassGuidToClass(
  1192. LPGUID ClassGuid
  1193. )
  1194. {
  1195. if (!ClassGuid) {
  1196. return NULL;
  1197. }
  1198. POSITION pos = m_listClass.GetHeadPosition();
  1199. while (NULL != pos) {
  1200. CClass* pClass = m_listClass.GetNext(pos);
  1201. if (IsEqualGUID(*ClassGuid, *pClass)) {
  1202. return pClass;
  1203. }
  1204. }
  1205. return NULL;
  1206. }
  1207. BOOL
  1208. CMachine::LoadStringWithMachineName(
  1209. int StringId,
  1210. LPTSTR Buffer,
  1211. DWORD* BufferLen
  1212. )
  1213. {
  1214. if (!BufferLen || *BufferLen && !Buffer) {
  1215. SetLastError(ERROR_INVALID_PARAMETER);
  1216. return FALSE;
  1217. }
  1218. TCHAR Format[LINE_LEN];
  1219. TCHAR Temp[1024];
  1220. LoadResourceString(StringId, Format, ARRAYLEN(Format));
  1221. if (IsLocal()) {
  1222. TCHAR LocalComputer[LINE_LEN];
  1223. LoadResourceString(IDS_LOCAL_MACHINE, LocalComputer, ARRAYLEN(LocalComputer));
  1224. wsprintf(Temp, Format, LocalComputer);
  1225. }
  1226. else {
  1227. wsprintf(Temp, Format, (LPCTSTR)m_strMachineFullName);
  1228. }
  1229. DWORD Len = lstrlen(Temp);
  1230. if (*BufferLen > Len) {
  1231. lstrcpyn(Buffer, Temp, Len + 1);
  1232. *BufferLen = Len;
  1233. return TRUE;
  1234. }
  1235. else {
  1236. SetLastError(ERROR_BUFFER_OVERFLOW);
  1237. *BufferLen = Len;
  1238. return FALSE;
  1239. }
  1240. }
  1241. //
  1242. // This function reenumerates the devnode tree from the root, rebuilds the
  1243. // device tree and notifies every attached folder about the new device tree.
  1244. //
  1245. BOOL
  1246. CMachine::Reenumerate()
  1247. {
  1248. BOOL Result = FALSE;
  1249. if (m_pComputer) {
  1250. //
  1251. // Temporarily disable refresh while we are doing reenumeration
  1252. // so that we will not keep refreshing the device tree.
  1253. //
  1254. EnableRefresh(FALSE);
  1255. CDialog WaitDialog(IDD_SCAN_PNP_HARDWARES);
  1256. WaitDialog.DoModaless(m_hwndParent, (LPARAM)&WaitDialog);
  1257. if (!CmReenumerate(
  1258. m_pComputer->GetDevNode(),
  1259. CM_REENUMERATE_SYNCHRONOUS | CM_REENUMERATE_RETRY_INSTALLATION
  1260. )) {
  1261. //
  1262. // Win2K doesn't support CM_REENUMERATE_RETRY_INSTALLATION, so we
  1263. // retry without the reinstall flag.
  1264. //
  1265. CmReenumerate(m_pComputer->GetDevNode(), CM_REENUMERATE_SYNCHRONOUS);
  1266. }
  1267. DestroyWindow(WaitDialog);
  1268. //
  1269. // reenumeration is done, schedule a refresh and enable refresh now.
  1270. //
  1271. ScheduleRefresh();
  1272. EnableRefresh(TRUE);
  1273. }
  1274. return TRUE;
  1275. }
  1276. //
  1277. // This function enable/disable refresh. A disble counter is kept to
  1278. // support multiple disabling/enabling. Only when the disable counter
  1279. // is zero, a refresh is possible.
  1280. // If a refresh is pending while we are enabling, we schedule a new
  1281. // request so that we will not lose any requests.
  1282. //
  1283. BOOL
  1284. CMachine::EnableRefresh(
  1285. BOOL fEnable
  1286. )
  1287. {
  1288. BOOL Result = TRUE;
  1289. Lock();
  1290. if (fEnable) {
  1291. if (m_RefreshDisableCounter < 0) {
  1292. m_RefreshDisableCounter++;
  1293. }
  1294. }
  1295. else {
  1296. m_RefreshDisableCounter--;
  1297. }
  1298. //
  1299. // If we are enabling refresh and there is one request pending,
  1300. // schedule it again. This makes sure that we will not lose
  1301. // any requests.
  1302. // We schedule a new refresh request instead of calling Refresh
  1303. // directly because we can be called by different threads while
  1304. // we want the refresh to be done in the main thread. The data window
  1305. // we created will receive the message and execute the refresh
  1306. // in the main thread context.
  1307. //
  1308. if (fEnable && m_RefreshPending) {
  1309. m_RefreshPending = FALSE;
  1310. ScheduleRefresh();
  1311. }
  1312. Unlock();
  1313. return Result;
  1314. }
  1315. //
  1316. //
  1317. // This function rebuilds the entire list of CClass and CDevice
  1318. // All attached CFolder are notified about the new machine.
  1319. //
  1320. // There are several occasions that we need to recreate the device tree:
  1321. // (1). On WM_DEVICECHANGE.
  1322. // (2). Device properties changed.
  1323. // (3). Device removal.
  1324. // (4). Device drivers updated and
  1325. // (5). Reenumeration requested by users.
  1326. // The requests may come from different threads and we must serialize
  1327. // the requests. A critical section and a new function(EnableRefresh) are added for
  1328. // for this purpose.
  1329. // Before doing anything on a device or class, one must call EnableRefesh(FALSE)
  1330. // to suspend Device change notification. When it is done with the change,
  1331. // one must call ScheduleRefesh function(if a refresh is necessary because of
  1332. // the changes) and then EnableRefresh(TRUE) to reenable the refresh.
  1333. //
  1334. BOOL
  1335. CMachine::Refresh()
  1336. {
  1337. BOOL Result = TRUE;
  1338. POSITION pos;
  1339. Lock();
  1340. if (0 == m_RefreshDisableCounter) {
  1341. HCURSOR hCursorOld;
  1342. hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1343. //
  1344. // Before we destroy all the classes and devices,
  1345. // notify every attached folder so that they can dis-engaged
  1346. // from us. After we created a new set of classes and devices,
  1347. // the notification will be sent again to each folder
  1348. // so that each folder can enagage to the machine again.
  1349. //
  1350. pos = m_listFolders.GetHeadPosition();
  1351. while (NULL != pos) {
  1352. ((CFolder*)m_listFolders.GetNext(pos))->MachinePropertyChanged(NULL);
  1353. }
  1354. //
  1355. // we can destroy all the "old" classes and devices now.
  1356. //
  1357. DestroyClassesAndDevices();
  1358. if (CreateClassesAndDevices()) {
  1359. //
  1360. // Notify every attach folder to recreate
  1361. //
  1362. if (!m_listFolders.IsEmpty()) {
  1363. pos = m_listFolders.GetHeadPosition();
  1364. while (NULL != pos) {
  1365. CFolder* pFolder = m_listFolders.GetNext(pos);
  1366. Result = SUCCEEDED(pFolder->MachinePropertyChanged(this));
  1367. }
  1368. }
  1369. //
  1370. // Notify every property page to refresh
  1371. //
  1372. if (!m_listChildMachines.IsEmpty()) {
  1373. EnterCriticalSection(&m_ChildMachineCriticalSection);
  1374. POSITION nextpos = m_listChildMachines.GetHeadPosition();
  1375. while (nextpos) {
  1376. pos = nextpos;
  1377. CMachine* pMachineToNotify = m_listChildMachines.GetNext(nextpos);
  1378. pMachineToNotify->DoMiniRefresh();
  1379. }
  1380. LeaveCriticalSection(&m_ChildMachineCriticalSection);
  1381. }
  1382. }
  1383. if (hCursorOld) {
  1384. SetCursor(hCursorOld);
  1385. }
  1386. m_RefreshPending = FALSE;
  1387. }
  1388. else {
  1389. //
  1390. // We need to refresh while the refresh is disabled
  1391. // Remember this so that when refresh is enabled, we
  1392. // can launch a refresh.
  1393. //
  1394. m_RefreshPending = TRUE;
  1395. }
  1396. Unlock();
  1397. return Result;
  1398. }
  1399. //
  1400. // A mini refresh is performed when the CMachine only has a single CClass or
  1401. // CDevice. This is because this will be the property sheet case. In this
  1402. // case we will see if the class or device represented by this property sheet
  1403. // still exists. If it doesn't then we will destroy the property sheet.
  1404. //
  1405. BOOL
  1406. CMachine::DoMiniRefresh()
  1407. {
  1408. BOOL Result = TRUE;
  1409. Lock();
  1410. //
  1411. // If the machine has one CDevice then we need to see if this device is
  1412. // still around.
  1413. //
  1414. if (1 == m_listDevice.GetCount()) {
  1415. DEVNODE dn;
  1416. PVOID Context;
  1417. CDevice* pDevice;
  1418. if (GetFirstDevice(&pDevice, Context)) {
  1419. /*
  1420. //
  1421. // We need to verify two things here. First is that we can locate
  1422. // this device instance id, at least as a phantom. The second is
  1423. // we need to make sure that the devnode is the same as that of the
  1424. // property sheet. If we can't locate this device instance id, or
  1425. // the devnode is different then we need to destroy the property
  1426. // sheet. The device instance id will go away if the user uninstalls
  1427. // this device. The devnode will be different if this device goes
  1428. // from a live devnode to a phantom or vice versa.
  1429. //
  1430. if ((CM_Locate_DevNode_Ex(&dn,
  1431. (DEVNODEID)pDevice->GetDeviceID(),
  1432. CM_LOCATE_DEVNODE_PHANTOM,
  1433. m_hMachine
  1434. ) != CR_SUCCESS) ||
  1435. (dn != pDevice->GetDevNode())) {
  1436. //
  1437. // Either this device instance id has been uninstalled or the devnode
  1438. // has been changed, this means we need to destroy the property sheet.
  1439. //
  1440. Result = FALSE;
  1441. } else {
  1442. */
  1443. //
  1444. // If the devnode did not go away we should tell it to refresh itself
  1445. // in case something changed.
  1446. //
  1447. ::PostMessage(pDevice->m_psd.GetWindowHandle(), PSM_QUERYSIBLINGS, QSC_PROPERTY_CHANGED, 0L);
  1448. // }
  1449. }
  1450. }
  1451. //
  1452. // Note that currently we don't do anything in the class property sheet case.
  1453. // The reason for this is that classes can't really go away unless someone deletes
  1454. // them from the registry, which probably wills mess up lots of other things. Also
  1455. // all current class property sheets don't do anything anyway and so even if someone
  1456. // does delete the class key nothing bad will happen to the property sheet.
  1457. //
  1458. Unlock();
  1459. return Result;
  1460. }
  1461. BOOL
  1462. CMachine::GetFirstDevice(
  1463. CDevice** ppDevice,
  1464. PVOID& Context
  1465. )
  1466. {
  1467. ASSERT(ppDevice);
  1468. if (!m_listDevice.IsEmpty()) {
  1469. POSITION pos = m_listDevice.GetHeadPosition();
  1470. *ppDevice = m_listDevice.GetNext(pos);
  1471. Context = pos;
  1472. return TRUE;
  1473. }
  1474. *ppDevice = NULL;
  1475. Context = NULL;
  1476. return FALSE;
  1477. }
  1478. BOOL
  1479. CMachine::GetNextDevice(
  1480. CDevice** ppDevice,
  1481. PVOID& Context
  1482. )
  1483. {
  1484. ASSERT(ppDevice);
  1485. POSITION pos = (POSITION)Context;
  1486. if (NULL != pos) {
  1487. *ppDevice = m_listDevice.GetNext(pos);
  1488. Context = pos;
  1489. return TRUE;
  1490. }
  1491. *ppDevice = NULL;
  1492. return FALSE;
  1493. }
  1494. BOOL
  1495. CMachine::GetFirstClass(
  1496. CClass** ppClass,
  1497. PVOID& Context
  1498. )
  1499. {
  1500. ASSERT(ppClass);
  1501. if (!m_listClass.IsEmpty()) {
  1502. POSITION pos = m_listClass.GetHeadPosition();
  1503. *ppClass = m_listClass.GetNext(pos);
  1504. Context = pos;
  1505. return TRUE;
  1506. }
  1507. *ppClass = NULL;
  1508. Context = NULL;
  1509. return FALSE;
  1510. }
  1511. BOOL
  1512. CMachine::GetNextClass(
  1513. CClass** ppClass,
  1514. PVOID& Context
  1515. )
  1516. {
  1517. ASSERT(ppClass);
  1518. POSITION pos = (POSITION)Context;
  1519. if (NULL != pos) {
  1520. *ppClass = m_listClass.GetNext(pos);
  1521. Context = pos;
  1522. return TRUE;
  1523. }
  1524. *ppClass = NULL;
  1525. return FALSE;
  1526. }
  1527. BOOL
  1528. CMachine::pGetOriginalInfName(
  1529. LPTSTR InfName,
  1530. String& OriginalInfName
  1531. )
  1532. {
  1533. SP_ORIGINAL_FILE_INFO InfOriginalFileInformation;
  1534. PSP_INF_INFORMATION pInfInformation;
  1535. DWORD InfInformationSize;
  1536. BOOL bRet;
  1537. ZeroMemory(&InfOriginalFileInformation, sizeof(InfOriginalFileInformation));
  1538. InfInformationSize = 8192; // I'd rather have this too big and succeed first time, than read the INF twice
  1539. pInfInformation = (PSP_INF_INFORMATION)LocalAlloc(LPTR, InfInformationSize);
  1540. if (pInfInformation != NULL) {
  1541. bRet = SetupGetInfInformation(InfName,
  1542. INFINFO_INF_NAME_IS_ABSOLUTE,
  1543. pInfInformation,
  1544. InfInformationSize,
  1545. &InfInformationSize
  1546. );
  1547. DWORD Error = GetLastError();
  1548. //
  1549. // If buffer was too small then make the buffer larger and try again.
  1550. //
  1551. if (!bRet && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  1552. PVOID newbuff = LocalReAlloc(pInfInformation, InfInformationSize, LPTR);
  1553. if (!newbuff) {
  1554. LocalFree(pInfInformation);
  1555. pInfInformation = NULL;
  1556. } else {
  1557. pInfInformation = (PSP_INF_INFORMATION)newbuff;
  1558. bRet = SetupGetInfInformation(InfName,
  1559. INFINFO_INF_NAME_IS_ABSOLUTE,
  1560. pInfInformation,
  1561. InfInformationSize,
  1562. &InfInformationSize
  1563. );
  1564. }
  1565. }
  1566. if (bRet) {
  1567. InfOriginalFileInformation.cbSize = sizeof(InfOriginalFileInformation);
  1568. if (SetupQueryInfOriginalFileInformation(pInfInformation, 0, NULL, &InfOriginalFileInformation)) {
  1569. if (InfOriginalFileInformation.OriginalInfName[0]!=0) {
  1570. //
  1571. // we have a "real" inf name
  1572. //
  1573. OriginalInfName = InfOriginalFileInformation.OriginalInfName;
  1574. }
  1575. }
  1576. }
  1577. //
  1578. // Assume that this INF has not been renamed
  1579. //
  1580. else {
  1581. OriginalInfName = MyGetFileTitle(InfName);
  1582. }
  1583. if (pInfInformation != NULL) {
  1584. LocalFree(pInfInformation);
  1585. pInfInformation = NULL;
  1586. }
  1587. }
  1588. return TRUE;
  1589. }
  1590. BOOL
  1591. CMachine::GetDigitalSigner(
  1592. LPTSTR FullInfPath,
  1593. String& DigitalSigner
  1594. )
  1595. {
  1596. SP_INF_SIGNER_INFO InfSignerInfo;
  1597. BOOL bRet = FALSE;
  1598. if (m_UserIsAGuest || !IsLocal()) {
  1599. //
  1600. // If the user is loged in as a guest, or we are not on the local
  1601. // machine, then make the digital signer string be 'Not available'
  1602. //
  1603. DigitalSigner.LoadString(g_hInstance, IDS_NOT_AVAILABLE);
  1604. } else {
  1605. InfSignerInfo.cbSize = sizeof(InfSignerInfo);
  1606. bRet = SetupVerifyInfFile(FullInfPath,
  1607. NULL,
  1608. &InfSignerInfo
  1609. );
  1610. if (bRet && (InfSignerInfo.DigitalSigner[0] != TEXT('\0'))) {
  1611. DigitalSigner = (LPTSTR)InfSignerInfo.DigitalSigner;
  1612. }
  1613. }
  1614. return bRet;
  1615. }
  1616. BOOL
  1617. CMachine::DoNotCreateDevice(
  1618. SC_HANDLE SCMHandle,
  1619. LPGUID ClassGuid,
  1620. DEVINST DevInst
  1621. )
  1622. /*++
  1623. This function returns whether a CDevice should be created for this DevInst
  1624. or not. If a CDevice is not created for DevInst then it will never show up
  1625. in the device manager UI, even when "Show hidden devices" is turned on.
  1626. We don't create a CDevice in the following cases:
  1627. - DevInst is HTREE\ROOT\0
  1628. - DevInst is a Win32 Service.
  1629. --*/
  1630. {
  1631. SC_HANDLE ServiceHandle;
  1632. TCHAR ServiceName[MAX_PATH];
  1633. LPQUERY_SERVICE_CONFIG ServiceConfig = NULL;
  1634. DWORD ServiceConfigSize;
  1635. ULONG Size;
  1636. String strDeviceID;
  1637. BOOL Return = FALSE;
  1638. //
  1639. // If the DEVMGR_SHOW_NONPRESENT_DEVICES environment variable is not set then
  1640. // we do not want to show any Phantom devices.
  1641. //
  1642. if (!m_ShowNonPresentDevices) {
  1643. ULONG Status, Problem;
  1644. if ((!CmGetStatus(DevInst, &Status, &Problem)) &&
  1645. ((m_LastCR == CR_NO_SUCH_VALUE) ||
  1646. (m_LastCR == CR_NO_SUCH_DEVINST))) {
  1647. return TRUE;
  1648. }
  1649. }
  1650. //
  1651. // Check to see if this device is a Win32 service. Only
  1652. // legacy devices could be Win32 services.
  1653. //
  1654. if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_LEGACYDRIVER)) {
  1655. Size = sizeof(ServiceName);
  1656. if (CmGetRegistryProperty(DevInst,
  1657. CM_DRP_SERVICE,
  1658. (PVOID)ServiceName,
  1659. &Size
  1660. ) == CR_SUCCESS) {
  1661. //
  1662. // Open this particular service
  1663. //
  1664. if ((ServiceHandle = OpenService(SCMHandle, ServiceName, GENERIC_READ)) != NULL) {
  1665. //
  1666. // Get the service config
  1667. //
  1668. if ((!QueryServiceConfig(ServiceHandle, NULL, 0, &ServiceConfigSize)) &&
  1669. (ERROR_INSUFFICIENT_BUFFER == GetLastError())) {
  1670. if ((ServiceConfig = (LPQUERY_SERVICE_CONFIG)malloc(ServiceConfigSize)) != NULL) {
  1671. if (QueryServiceConfig(ServiceHandle, ServiceConfig, ServiceConfigSize, &ServiceConfigSize)) {
  1672. if (ServiceConfig->dwServiceType & (SERVICE_WIN32 | SERVICE_FILE_SYSTEM_DRIVER)) {
  1673. Return = TRUE;
  1674. }
  1675. }
  1676. free(ServiceConfig);
  1677. }
  1678. }
  1679. CloseServiceHandle(ServiceHandle);
  1680. }
  1681. }
  1682. }
  1683. //
  1684. // Check to see if this is the HTREE\ROOT\0 device. We don't
  1685. // want to create a CDevice for this phantom devnode.
  1686. //
  1687. // This is an else statement because the HTREE\ROOT\0 device is
  1688. // not in the legacy device class.
  1689. //
  1690. else {
  1691. CmGetDeviceIDString(DevInst, strDeviceID);
  1692. if (!lstrcmpi((LPTSTR)strDeviceID, TEXT("HTREE\\ROOT\\0"))) {
  1693. Return = TRUE;
  1694. }
  1695. }
  1696. return Return;
  1697. }
  1698. BOOL
  1699. CMachine::DiGetClassFriendlyNameString(
  1700. LPGUID Guid,
  1701. String& strClass
  1702. )
  1703. {
  1704. TCHAR DisplayName[LINE_LEN + 1];
  1705. //
  1706. // Try friendly name first. If it failed, try the class name
  1707. //
  1708. if (SetupDiGetClassDescriptionEx(Guid, DisplayName, ARRAYLEN(DisplayName),
  1709. NULL, GetRemoteMachineFullName(), NULL) ||
  1710. SetupDiClassNameFromGuidEx(Guid, DisplayName, ARRAYLEN(DisplayName),
  1711. NULL, GetRemoteMachineFullName(), NULL)) {
  1712. strClass = DisplayName;
  1713. return TRUE;
  1714. }
  1715. return FALSE;
  1716. }
  1717. DEVNODE
  1718. CMachine::CmGetParent(
  1719. DEVNODE dn
  1720. )
  1721. {
  1722. DEVNODE dnParent;
  1723. m_LastCR = CM_Get_Parent_Ex(&dnParent, dn, 0, m_hMachine);
  1724. if (CR_SUCCESS == m_LastCR) {
  1725. return dnParent;
  1726. }
  1727. return NULL;
  1728. }
  1729. DEVNODE
  1730. CMachine::CmGetChild(
  1731. DEVNODE dn
  1732. )
  1733. {
  1734. DEVNODE dnChild;
  1735. m_LastCR = CM_Get_Child_Ex(&dnChild, dn, 0, m_hMachine);
  1736. if (CR_SUCCESS == m_LastCR) {
  1737. return dnChild;
  1738. }
  1739. return NULL;
  1740. }
  1741. DEVNODE
  1742. CMachine::CmGetSibling(
  1743. DEVNODE dn
  1744. )
  1745. {
  1746. DEVNODE dnSibling;
  1747. m_LastCR = CM_Get_Sibling_Ex(&dnSibling, dn, 0, m_hMachine);
  1748. if (CR_SUCCESS == m_LastCR) {
  1749. return dnSibling;
  1750. }
  1751. return NULL;
  1752. }
  1753. DEVNODE
  1754. CMachine::CmGetRootDevNode()
  1755. {
  1756. DEVNODE dnRoot;
  1757. m_LastCR = CM_Locate_DevNode_Ex(&dnRoot, NULL, 0, m_hMachine);
  1758. if (CR_SUCCESS == m_LastCR) {
  1759. return dnRoot;
  1760. }
  1761. return NULL;
  1762. }
  1763. BOOL
  1764. CMachine::CmGetDeviceIDString(
  1765. DEVNODE dn,
  1766. String& str
  1767. )
  1768. {
  1769. TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
  1770. m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID), 0, m_hMachine);
  1771. if (CR_SUCCESS == m_LastCR) {
  1772. str = DeviceID;
  1773. return TRUE;
  1774. }
  1775. return FALSE;
  1776. }
  1777. BOOL
  1778. CMachine::CmGetConfigFlags(
  1779. DEVNODE dn,
  1780. DWORD* pFlags
  1781. )
  1782. {
  1783. DWORD Size;
  1784. Size = sizeof(DWORD);
  1785. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CONFIGFLAGS, pFlags, &Size);
  1786. return CR_SUCCESS == m_LastCR;
  1787. }
  1788. BOOL
  1789. CMachine::CmGetCapabilities(
  1790. DEVNODE dn,
  1791. DWORD* pCapabilities
  1792. )
  1793. {
  1794. DWORD Size;
  1795. Size = sizeof(DWORD);
  1796. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CAPABILITIES, pCapabilities, &Size);
  1797. return CR_SUCCESS == m_LastCR;
  1798. }
  1799. BOOL
  1800. CMachine::CmGetDescriptionString(
  1801. DEVNODE dn,
  1802. String& str
  1803. )
  1804. {
  1805. TCHAR Description[LINE_LEN + 1];
  1806. ULONG Size = sizeof(Description);
  1807. Description[0] = TEXT('\0');
  1808. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_FRIENDLYNAME, Description, &Size);
  1809. if ((CR_NO_SUCH_VALUE == m_LastCR) || (Description[0] == TEXT('\0'))) {
  1810. Size = sizeof(Description);
  1811. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_DEVICEDESC, Description,
  1812. &Size);
  1813. }
  1814. if ((CR_SUCCESS == m_LastCR) && (Description[0] != TEXT('\0'))) {
  1815. str = Description;
  1816. return TRUE;
  1817. }
  1818. return FALSE;
  1819. }
  1820. BOOL
  1821. CMachine::CmGetMFGString(
  1822. DEVNODE dn,
  1823. String& str
  1824. )
  1825. {
  1826. TCHAR MFG[LINE_LEN + 1];
  1827. ULONG Size = sizeof(MFG);
  1828. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_MFG, MFG, &Size);
  1829. if (CR_SUCCESS == m_LastCR) {
  1830. str = MFG;
  1831. return TRUE;
  1832. }
  1833. return FALSE;
  1834. }
  1835. BOOL
  1836. CMachine::CmGetProviderString(
  1837. DEVNODE dn,
  1838. String& str
  1839. )
  1840. {
  1841. TCHAR Provider[LINE_LEN + 1];
  1842. ULONG Size = sizeof(Provider);
  1843. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("ProviderName"),
  1844. Provider, &Size);
  1845. if (CR_SUCCESS == m_LastCR) {
  1846. str = Provider;
  1847. return TRUE;
  1848. }
  1849. return FALSE;
  1850. }
  1851. BOOL
  1852. CMachine::CmGetDriverDateString(
  1853. DEVNODE dn,
  1854. String& str
  1855. )
  1856. {
  1857. TCHAR DriverDate[LINE_LEN + 1];
  1858. ULONG Size = sizeof(DriverDate);
  1859. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverDate"),
  1860. DriverDate, &Size);
  1861. if (CR_SUCCESS == m_LastCR) {
  1862. str = DriverDate;
  1863. return TRUE;
  1864. }
  1865. return FALSE;
  1866. }
  1867. BOOL
  1868. CMachine::CmGetDriverDateData(
  1869. DEVNODE dn,
  1870. FILETIME *ft
  1871. )
  1872. {
  1873. ULONG Size = sizeof(*ft);
  1874. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverDateData"),
  1875. ft, &Size);
  1876. return(m_LastCR == CR_SUCCESS);
  1877. }
  1878. BOOL
  1879. CMachine::CmGetDriverVersionString(
  1880. DEVNODE dn,
  1881. String& str
  1882. )
  1883. {
  1884. TCHAR DriverVersion[LINE_LEN + 1];
  1885. ULONG Size = sizeof(DriverVersion);
  1886. m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverVersion"),
  1887. DriverVersion, &Size);
  1888. if (CR_SUCCESS == m_LastCR) {
  1889. str = DriverVersion;
  1890. return TRUE;
  1891. }
  1892. return FALSE;
  1893. }
  1894. BOOL
  1895. CMachine::CmGetBusGuid(
  1896. DEVNODE dn,
  1897. LPGUID Guid
  1898. )
  1899. {
  1900. ULONG Size = sizeof(*Guid);
  1901. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_BUSTYPEGUID, (LPVOID)Guid, &Size);
  1902. if (CR_SUCCESS == m_LastCR) {
  1903. return TRUE;
  1904. }
  1905. return FALSE;
  1906. }
  1907. BOOL
  1908. CMachine::CmGetBusGuidString(
  1909. DEVNODE dn,
  1910. String& str
  1911. )
  1912. {
  1913. GUID BusGuid;
  1914. TCHAR BusGuidString[MAX_GUID_STRING_LEN];
  1915. ULONG Size;
  1916. while (dn) {
  1917. //
  1918. // We have to set the size on each loop
  1919. //
  1920. Size = sizeof(BusGuid);
  1921. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_BUSTYPEGUID, &BusGuid, &Size);
  1922. if (CR_SUCCESS == m_LastCR && GuidToString(&BusGuid, BusGuidString,
  1923. ARRAYLEN(BusGuidString))) {
  1924. str = BusGuidString;
  1925. return TRUE;
  1926. }
  1927. dn = CmGetParent(dn);
  1928. }
  1929. return FALSE;
  1930. }
  1931. BOOL
  1932. CMachine::CmGetClassGuid(
  1933. DEVNODE dn,
  1934. GUID& Guid
  1935. )
  1936. {
  1937. TCHAR szGuidString[MAX_GUID_STRING_LEN + 1];
  1938. ULONG Size = sizeof(szGuidString);
  1939. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CLASSGUID, szGuidString, &Size);
  1940. if (CR_SUCCESS == m_LastCR && GuidFromString(szGuidString, &Guid)) {
  1941. return TRUE;
  1942. }
  1943. //
  1944. // If we can't get the class GUID from the registry then most likely the device
  1945. // does not have a class GUID. If this is the case then we will return
  1946. // GUID_DEVCLASS_UNKNOWN
  1947. //
  1948. else {
  1949. memcpy(&Guid, &GUID_DEVCLASS_UNKNOWN, sizeof(GUID));
  1950. return TRUE;
  1951. }
  1952. }
  1953. BOOL
  1954. CMachine::CmGetHardwareIDs(
  1955. DEVNODE dn,
  1956. PVOID Buffer,
  1957. ULONG* BufferLen
  1958. )
  1959. {
  1960. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_HARDWAREID, Buffer, BufferLen);
  1961. return CR_SUCCESS == m_LastCR;
  1962. }
  1963. BOOL
  1964. CMachine::CmGetCompatibleIDs(
  1965. DEVNODE dn,
  1966. PVOID Buffer,
  1967. ULONG* BufferLen
  1968. )
  1969. {
  1970. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_COMPATIBLEIDS, Buffer, BufferLen);
  1971. return CR_SUCCESS == m_LastCR;
  1972. }
  1973. LPTSTR
  1974. FormatString(
  1975. LPCTSTR format,
  1976. ...
  1977. )
  1978. {
  1979. LPTSTR str = NULL;
  1980. va_list arglist;
  1981. va_start(arglist, format);
  1982. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1983. format,
  1984. 0,
  1985. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  1986. (LPTSTR)&str,
  1987. 0,
  1988. &arglist
  1989. ) == 0) {
  1990. str = NULL;
  1991. }
  1992. va_end(arglist);
  1993. return str;
  1994. }
  1995. STDAPI_(CONFIGRET) GetLocationInformation(
  1996. DEVNODE dn,
  1997. LPTSTR Location,
  1998. ULONG LocationLen,
  1999. HMACHINE hMachine
  2000. )
  2001. /*++
  2002. Slot x (LocationInformation)
  2003. Slot x
  2004. LocationInformation
  2005. on parent bus
  2006. --*/
  2007. {
  2008. CONFIGRET LastCR;
  2009. DEVNODE dnParent;
  2010. ULONG ulSize;
  2011. DWORD UINumber;
  2012. TCHAR Buffer[MAX_PATH];
  2013. TCHAR UINumberDescFormat[MAX_PATH];
  2014. TCHAR Format[MAX_PATH];
  2015. Buffer[0] = TEXT('\0');
  2016. //
  2017. // We will first get any LocationInformation for the device. This will either
  2018. // be in the LocationInformationOverride value in the devices driver (software) key
  2019. // or if that is not present we will look for the LocationInformation value in
  2020. // the devices device (hardware) key.
  2021. //
  2022. HKEY hKey;
  2023. DWORD Type = REG_SZ;
  2024. ulSize = sizeof(Buffer);
  2025. if (CR_SUCCESS == CM_Open_DevNode_Key_Ex(dn,
  2026. KEY_READ,
  2027. 0,
  2028. RegDisposition_OpenExisting,
  2029. &hKey,
  2030. CM_REGISTRY_SOFTWARE,
  2031. hMachine
  2032. )) {
  2033. RegQueryValueEx(hKey,
  2034. REGSTR_VAL_LOCATION_INFORMATION_OVERRIDE,
  2035. NULL,
  2036. &Type,
  2037. (const PBYTE)Buffer,
  2038. &ulSize
  2039. );
  2040. RegCloseKey(hKey);
  2041. }
  2042. //
  2043. // If the buffer is empty then we didn't get the LocationInformationOverride
  2044. // value in the device's software key. So, we will see if their is a
  2045. // LocationInformation value in the device's hardware key.
  2046. //
  2047. if (Buffer[0] == TEXT('\0')) {
  2048. ulSize = sizeof(Buffer);
  2049. CM_Get_DevNode_Registry_Property_Ex(dn,
  2050. CM_DRP_LOCATION_INFORMATION,
  2051. NULL,
  2052. Buffer,
  2053. &ulSize,
  2054. 0,
  2055. hMachine
  2056. );
  2057. }
  2058. //
  2059. // UINumber has precedence over all other location information so check if this
  2060. // device has a UINumber.
  2061. //
  2062. ulSize = sizeof(UINumber);
  2063. if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dn,
  2064. CM_DRP_UI_NUMBER,
  2065. NULL,
  2066. &UINumber,
  2067. &ulSize,
  2068. 0,
  2069. hMachine
  2070. )) == CR_SUCCESS) &&
  2071. (ulSize > 0)) {
  2072. UINumberDescFormat[0] = TEXT('\0');
  2073. ulSize = sizeof(UINumberDescFormat);
  2074. //
  2075. // Get the UINumber description format string from the device's parent,
  2076. // if there is one, otherwise default to 'Location %1'
  2077. if ((CM_Get_Parent_Ex(&dnParent, dn, 0, hMachine) == CR_SUCCESS) &&
  2078. (CM_Get_DevNode_Registry_Property_Ex(dnParent,
  2079. CM_DRP_UI_NUMBER_DESC_FORMAT,
  2080. NULL,
  2081. UINumberDescFormat,
  2082. &ulSize,
  2083. 0,
  2084. hMachine) == CR_SUCCESS) &&
  2085. *UINumberDescFormat) {
  2086. } else {
  2087. ::LoadString(g_hInstance, IDS_UI_NUMBER_DESC_FORMAT, UINumberDescFormat, sizeof(UINumberDescFormat)/sizeof(TCHAR));
  2088. }
  2089. LPTSTR UINumberBuffer = NULL;
  2090. //
  2091. // Fill in the UINumber string
  2092. //
  2093. UINumberBuffer = FormatString(UINumberDescFormat, UINumber);
  2094. if (UINumberBuffer) {
  2095. lstrcpy((LPTSTR)Location, UINumberBuffer);
  2096. LocalFree(UINumberBuffer);
  2097. } else {
  2098. Location[0] = TEXT('\0');
  2099. }
  2100. //
  2101. // If we also have LocationInformation then tack that on the end of the string
  2102. // as well.
  2103. //
  2104. if (*Buffer) {
  2105. lstrcat((LPTSTR)Location, TEXT(" ("));
  2106. lstrcat((LPTSTR)Location, Buffer);
  2107. lstrcat((LPTSTR)Location, TEXT(")"));
  2108. }
  2109. }
  2110. //
  2111. // We don't have a UINumber but we do have LocationInformation
  2112. //
  2113. else if (*Buffer) {
  2114. ::LoadString(g_hInstance, IDS_LOCATION, Format, sizeof(Format)/sizeof(TCHAR));
  2115. wsprintf((LPTSTR)Location, Format, Buffer);
  2116. }
  2117. //
  2118. // We don't have a UINumber or LocationInformation so we need to get a description
  2119. // of the parent of this device.
  2120. //
  2121. else {
  2122. if ((LastCR = CM_Get_Parent_Ex(&dnParent, dn, 0, hMachine)) == CR_SUCCESS) {
  2123. //
  2124. // Try the registry for FRIENDLYNAME
  2125. //
  2126. Buffer[0] = TEXT('\0');
  2127. ulSize = sizeof(Buffer);
  2128. if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dnParent,
  2129. CM_DRP_FRIENDLYNAME,
  2130. NULL,
  2131. Buffer,
  2132. &ulSize,
  2133. 0,
  2134. hMachine
  2135. )) != CR_SUCCESS) ||
  2136. !*Buffer) {
  2137. //
  2138. // Try the registry for DEVICEDESC
  2139. //
  2140. ulSize = sizeof(Buffer);
  2141. if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dnParent,
  2142. CM_DRP_DEVICEDESC,
  2143. NULL,
  2144. Buffer,
  2145. &ulSize,
  2146. 0,
  2147. hMachine
  2148. )) != CR_SUCCESS) ||
  2149. !*Buffer) {
  2150. ulSize = sizeof(Buffer);
  2151. if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dnParent,
  2152. CM_DRP_CLASS,
  2153. NULL,
  2154. Buffer,
  2155. &ulSize,
  2156. 0,
  2157. hMachine
  2158. )) != CR_SUCCESS) ||
  2159. !*Buffer) {
  2160. //
  2161. // no parent, or parent name.
  2162. //
  2163. Buffer[0] = TEXT('\0');
  2164. }
  2165. }
  2166. }
  2167. }
  2168. if (*Buffer) {
  2169. //
  2170. // We have a description of the parent
  2171. //
  2172. ::LoadString(g_hInstance, IDS_LOCATION_NOUINUMBER, Format, sizeof(Format)/sizeof(TCHAR));
  2173. wsprintf((LPTSTR)Location, Format, Buffer);
  2174. } else {
  2175. //
  2176. // We don't have any information so we will just say Unknown
  2177. //
  2178. ::LoadString(g_hInstance, IDS_UNKNOWN, Location, LocationLen);
  2179. }
  2180. }
  2181. return CR_SUCCESS;
  2182. }
  2183. BOOL
  2184. CMachine::CmGetStatus(
  2185. DEVNODE dn,
  2186. DWORD* pProblem,
  2187. DWORD* pStatus
  2188. )
  2189. {
  2190. ASSERT(pProblem && pStatus);
  2191. m_LastCR = CM_Get_DevNode_Status_Ex(pStatus, pProblem, dn, 0, m_hMachine);
  2192. return(CR_SUCCESS == m_LastCR);
  2193. }
  2194. BOOL
  2195. CMachine::CmGetKnownLogConf(
  2196. DEVNODE dn,
  2197. LOG_CONF* plc,
  2198. DWORD* plcType
  2199. )
  2200. {
  2201. ASSERT(plc);
  2202. *plc = 0;
  2203. if (plcType) {
  2204. *plcType = LOG_CONF_BITS + 1;
  2205. }
  2206. ULONG lcTypeFirst = ALLOC_LOG_CONF;
  2207. ULONG lcTypeLast = FORCED_LOG_CONF;
  2208. ASSERT(ALLOC_LOG_CONF + 1 == BOOT_LOG_CONF &&
  2209. BOOT_LOG_CONF + 1 == FORCED_LOG_CONF);
  2210. for (ULONG lcType = lcTypeFirst; lcType <= lcTypeLast; lcType++) {
  2211. m_LastCR = CM_Get_First_Log_Conf_Ex(plc, dn, lcType, m_hMachine);
  2212. if (CR_SUCCESS == m_LastCR) {
  2213. if (plcType) {
  2214. *plcType = lcType;
  2215. }
  2216. break;
  2217. }
  2218. }
  2219. return CR_SUCCESS == m_LastCR;
  2220. }
  2221. BOOL
  2222. CMachine::CmHasResources(
  2223. DEVNODE dn
  2224. )
  2225. {
  2226. for (ULONG lcType = 0; lcType < NUM_LOG_CONF; lcType++) {
  2227. m_LastCR = CM_Get_First_Log_Conf_Ex(NULL, dn, lcType, m_hMachine);
  2228. if (CR_SUCCESS == m_LastCR) {
  2229. break;
  2230. }
  2231. }
  2232. return CR_SUCCESS == m_LastCR;
  2233. }
  2234. BOOL
  2235. CMachine::CmReenumerate(
  2236. DEVNODE dn,
  2237. ULONG Flags
  2238. )
  2239. {
  2240. m_LastCR = CM_Reenumerate_DevNode_Ex(dn, Flags, m_hMachine);
  2241. return CR_SUCCESS == m_LastCR;
  2242. }
  2243. BOOL
  2244. CMachine::CmGetHwProfileFlags(
  2245. DEVNODE dn,
  2246. ULONG Profile,
  2247. ULONG* pFlags
  2248. )
  2249. {
  2250. TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
  2251. m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID),
  2252. 0, m_hMachine);
  2253. if (CR_SUCCESS == m_LastCR) {
  2254. return CmGetHwProfileFlags(DeviceID, Profile, pFlags);
  2255. }
  2256. return FALSE;
  2257. }
  2258. BOOL
  2259. CMachine::CmGetHwProfileFlags(
  2260. LPCTSTR DeviceID,
  2261. ULONG Profile,
  2262. ULONG* pFlags
  2263. )
  2264. {
  2265. m_LastCR = CM_Get_HW_Prof_Flags_Ex((LPTSTR)DeviceID, Profile, pFlags, 0,
  2266. m_hMachine);
  2267. return CR_SUCCESS == m_LastCR;
  2268. }
  2269. BOOL
  2270. CMachine::CmSetHwProfileFlags(
  2271. DEVNODE dn,
  2272. ULONG Profile,
  2273. ULONG Flags
  2274. )
  2275. {
  2276. TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
  2277. m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID),
  2278. 0, m_hMachine);
  2279. if (CR_SUCCESS == m_LastCR) {
  2280. return CmSetHwProfileFlags(DeviceID, Profile, Flags);
  2281. }
  2282. return FALSE;
  2283. }
  2284. BOOL
  2285. CMachine::CmSetHwProfileFlags(
  2286. LPCTSTR DeviceID,
  2287. ULONG Profile,
  2288. ULONG Flags
  2289. )
  2290. {
  2291. m_LastCR = CM_Set_HW_Prof_Flags_Ex((LPTSTR)DeviceID, Profile, Flags, 0,
  2292. m_hMachine);
  2293. return CR_SUCCESS == m_LastCR;
  2294. }
  2295. BOOL
  2296. CMachine::CmHasDrivers(
  2297. DEVNODE dn
  2298. )
  2299. {
  2300. ULONG Size = 0;
  2301. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_DRIVER, NULL, &Size);
  2302. if (CR_BUFFER_SMALL != m_LastCR) {
  2303. Size = 0;
  2304. m_LastCR = CmGetRegistryProperty(dn, CM_DRP_SERVICE, NULL, &Size);
  2305. }
  2306. return(CR_BUFFER_SMALL == m_LastCR);
  2307. }
  2308. BOOL
  2309. CMachine::CmGetCurrentHwProfile(
  2310. ULONG* phwpf
  2311. )
  2312. {
  2313. HWPROFILEINFO hwpfInfo;
  2314. ASSERT(phwpf);
  2315. if (CmGetHwProfileInfo(0xFFFFFFFF, &hwpfInfo)) {
  2316. *phwpf = hwpfInfo.HWPI_ulHWProfile;
  2317. return TRUE;
  2318. }
  2319. return FALSE;
  2320. }
  2321. BOOL
  2322. CMachine::CmGetHwProfileInfo(
  2323. int Index,
  2324. PHWPROFILEINFO pHwProfileInfo
  2325. )
  2326. {
  2327. m_LastCR = CM_Get_Hardware_Profile_Info_Ex(Index, pHwProfileInfo, 0, m_hMachine);
  2328. return(CR_SUCCESS == m_LastCR);
  2329. }
  2330. ULONG
  2331. CMachine::CmGetResDesDataSize(
  2332. RES_DES rd
  2333. )
  2334. {
  2335. ULONG Size;
  2336. m_LastCR = CM_Get_Res_Des_Data_Size_Ex(&Size, rd, 0, m_hMachine);
  2337. if (CR_SUCCESS == m_LastCR) {
  2338. return Size;
  2339. }
  2340. return 0;
  2341. }
  2342. BOOL
  2343. CMachine::CmGetResDesData(
  2344. RES_DES rd,
  2345. PVOID Buffer,
  2346. ULONG BufferSize
  2347. )
  2348. {
  2349. m_LastCR = CM_Get_Res_Des_Data_Ex(rd, Buffer, BufferSize, 0, m_hMachine);
  2350. return CR_SUCCESS == m_LastCR;
  2351. }
  2352. BOOL
  2353. CMachine::CmGetNextResDes(
  2354. PRES_DES prdNext,
  2355. RES_DES rd,
  2356. RESOURCEID ForResource,
  2357. PRESOURCEID pTheResource
  2358. )
  2359. {
  2360. m_LastCR = CM_Get_Next_Res_Des_Ex(prdNext, rd, ForResource, pTheResource,
  2361. 0, m_hMachine);
  2362. return(CR_SUCCESS == m_LastCR);
  2363. }
  2364. void
  2365. CMachine::CmFreeResDesHandle(
  2366. RES_DES rd
  2367. )
  2368. {
  2369. m_LastCR = CM_Free_Res_Des_Handle(rd);
  2370. }
  2371. void
  2372. CMachine::CmFreeResDes(
  2373. PRES_DES prdPrev,
  2374. RES_DES rd
  2375. )
  2376. {
  2377. m_LastCR = CM_Free_Res_Des_Ex(prdPrev, rd, 0, m_hMachine);
  2378. }
  2379. void
  2380. CMachine::CmFreeLogConfHandle(
  2381. LOG_CONF lc
  2382. )
  2383. {
  2384. m_LastCR = CM_Free_Log_Conf_Handle(lc);
  2385. }
  2386. int
  2387. CMachine::CmGetNumberOfBasicLogConf(
  2388. DEVNODE dn
  2389. )
  2390. {
  2391. LOG_CONF lcFirst;
  2392. int nLC = 0;
  2393. if (CmGetFirstLogConf(dn, &lcFirst, BASIC_LOG_CONF)) {
  2394. LOG_CONF lcNext;
  2395. BOOL NoMore = FALSE;
  2396. do {
  2397. NoMore = !CmGetNextLogConf(&lcNext, lcFirst, BASIC_LOG_CONF);
  2398. CmFreeLogConfHandle(lcFirst);
  2399. lcFirst = lcNext;
  2400. nLC++;
  2401. } while (NoMore);
  2402. }
  2403. return nLC;
  2404. }
  2405. BOOL
  2406. CMachine::CmGetFirstLogConf(
  2407. DEVNODE dn,
  2408. LOG_CONF* plc,
  2409. ULONG Type
  2410. )
  2411. {
  2412. m_LastCR = CM_Get_First_Log_Conf_Ex(plc, dn, Type, m_hMachine);
  2413. return CR_SUCCESS == m_LastCR;
  2414. }
  2415. BOOL
  2416. CMachine::CmGetNextLogConf(
  2417. LOG_CONF* plcNext,
  2418. LOG_CONF lcRef,
  2419. ULONG Type
  2420. )
  2421. {
  2422. m_LastCR = CM_Get_Next_Log_Conf_Ex(plcNext, lcRef, Type, m_hMachine);
  2423. return CR_SUCCESS == m_LastCR;
  2424. }
  2425. ULONG
  2426. CMachine::CmGetArbitratorFreeDataSize(
  2427. DEVNODE dn,
  2428. RESOURCEID ResType
  2429. )
  2430. {
  2431. ULONG Size;
  2432. m_LastCR = CM_Query_Arbitrator_Free_Size_Ex(&Size, dn, ResType,
  2433. 0, m_hMachine);
  2434. if (CR_SUCCESS == m_LastCR) {
  2435. return Size;
  2436. }
  2437. return 0;
  2438. }
  2439. BOOL
  2440. CMachine::CmGetArbitratorFreeData(
  2441. DEVNODE dn,
  2442. PVOID pBuffer,
  2443. ULONG BufferSize,
  2444. RESOURCEID ResType
  2445. )
  2446. {
  2447. m_LastCR = CM_Query_Arbitrator_Free_Data_Ex(pBuffer, BufferSize, dn,
  2448. ResType, 0, m_hMachine
  2449. );
  2450. return CR_SUCCESS == m_LastCR;
  2451. }
  2452. BOOL
  2453. CMachine::CmTestRangeAvailable(
  2454. RANGE_LIST RangeList,
  2455. DWORDLONG dlBase,
  2456. DWORDLONG dlEnd
  2457. )
  2458. {
  2459. m_LastCR = CM_Test_Range_Available(dlBase, dlEnd, RangeList, 0);
  2460. return(CR_SUCCESS == m_LastCR);
  2461. }
  2462. void
  2463. CMachine::CmDeleteRange(
  2464. RANGE_LIST RangeList,
  2465. DWORDLONG dlBase,
  2466. DWORDLONG dlLen
  2467. )
  2468. {
  2469. DWORDLONG dlEnd = dlBase + dlLen - 1;
  2470. m_LastCR = CM_Delete_Range(dlBase, dlEnd, RangeList, 0);
  2471. }
  2472. BOOL
  2473. CMachine::CmGetFirstRange(
  2474. RANGE_LIST RangeList,
  2475. DWORDLONG* pdlBase,
  2476. DWORDLONG* pdlLen,
  2477. RANGE_ELEMENT* pre
  2478. )
  2479. {
  2480. m_LastCR = CM_First_Range(RangeList, pdlBase, pdlLen, pre, 0);
  2481. if (CR_SUCCESS == m_LastCR) {
  2482. *pdlLen = *pdlLen - *pdlBase + 1;
  2483. return TRUE;
  2484. }
  2485. return FALSE;
  2486. }
  2487. BOOL
  2488. CMachine::CmGetNextRange(
  2489. RANGE_ELEMENT* pre,
  2490. DWORDLONG* pdlBase,
  2491. DWORDLONG* pdlLen
  2492. )
  2493. {
  2494. m_LastCR = CM_Next_Range(pre, pdlBase, pdlLen, 0);
  2495. if (CR_SUCCESS == m_LastCR) {
  2496. *pdlLen = *pdlLen - *pdlBase + 1;
  2497. return TRUE;
  2498. }
  2499. return FALSE;
  2500. }
  2501. void
  2502. CMachine::CmFreeRangeList(
  2503. RANGE_LIST RangeList
  2504. )
  2505. {
  2506. m_LastCR = CM_Free_Range_List(RangeList, 0);
  2507. }
  2508. CONFIGRET
  2509. CMachine::CmGetRegistryProperty(
  2510. DEVNODE dn,
  2511. ULONG Property,
  2512. PVOID pBuffer,
  2513. ULONG* pBufferSize
  2514. )
  2515. {
  2516. return CM_Get_DevNode_Registry_Property_Ex(dn, Property, NULL,
  2517. pBuffer, pBufferSize,
  2518. 0, m_hMachine
  2519. );
  2520. }
  2521. CONFIGRET
  2522. CMachine::CmGetRegistrySoftwareProperty(
  2523. DEVNODE dn,
  2524. LPCTSTR ValueName,
  2525. PVOID pBuffer,
  2526. ULONG* pBufferSize
  2527. )
  2528. {
  2529. HKEY hKey;
  2530. DWORD Type = REG_SZ;
  2531. CONFIGRET CR;
  2532. if (CR_SUCCESS == (CR = CM_Open_DevNode_Key_Ex(dn, KEY_READ, 0, RegDisposition_OpenExisting,
  2533. &hKey, CM_REGISTRY_SOFTWARE, m_hMachine))) {
  2534. if (ERROR_SUCCESS != RegQueryValueEx(hKey, ValueName, NULL, &Type, (const PBYTE)pBuffer,
  2535. pBufferSize)) {
  2536. CR = CR_REGISTRY_ERROR;
  2537. }
  2538. RegCloseKey(hKey);
  2539. }
  2540. return CR;
  2541. }
  2542. BOOL
  2543. CMachine::CmGetDeviceIdListSize(
  2544. LPCTSTR Filter,
  2545. ULONG* Size,
  2546. ULONG Flags
  2547. )
  2548. {
  2549. m_LastCR = CM_Get_Device_ID_List_Size_Ex(Size, Filter, Flags, m_hMachine);
  2550. return CR_SUCCESS == m_LastCR;
  2551. }
  2552. BOOL
  2553. CMachine::CmGetDeviceIdList(
  2554. LPCTSTR Filter,
  2555. TCHAR* Buffer,
  2556. ULONG BufferSize,
  2557. ULONG Flags
  2558. )
  2559. {
  2560. m_LastCR = CM_Get_Device_ID_List_Ex(Filter, Buffer, BufferSize, Flags, m_hMachine);
  2561. return CR_SUCCESS == m_LastCR;
  2562. }
  2563. CMachineList::~CMachineList()
  2564. {
  2565. if (!m_listMachines.IsEmpty()) {
  2566. POSITION pos = m_listMachines.GetHeadPosition();
  2567. CMachine* pMachine;
  2568. while (NULL != pos) {
  2569. pMachine = m_listMachines.GetNext(pos);
  2570. delete pMachine;
  2571. }
  2572. m_listMachines.RemoveAll();
  2573. }
  2574. }
  2575. //
  2576. // This function creates a machine object on the given machine name
  2577. // INPUT:
  2578. // hwndParent -- Window Handle to be used as the owner window
  2579. // of all possible windows this function may create
  2580. // MachineName -- the machine name. Must be in full qualified format
  2581. // NULL means the local machine
  2582. // ppMachine -- buffer to receive the newly create machine.
  2583. //
  2584. // OUTPUT:
  2585. // TRUE if the machine is created successfully. ppMachine
  2586. // is filled with the newly created Machine.
  2587. // FALSE if the function failed.
  2588. // NOTE:
  2589. // The caller should NOT free any machine object retruned
  2590. // from this function.
  2591. //
  2592. BOOL
  2593. CMachineList::CreateMachine(
  2594. HWND hwndParent,
  2595. LPCTSTR MachineName,
  2596. CMachine** ppMachine
  2597. )
  2598. {
  2599. ASSERT(ppMachine);
  2600. *ppMachine = NULL;
  2601. CMachine* pMachine = NULL;
  2602. if (!MachineName || _T('\0') == MachineName[0]) {
  2603. //
  2604. // Local machine.
  2605. //
  2606. String strMachineName;
  2607. strMachineName.GetComputerName();
  2608. pMachine = FindMachine(strMachineName);
  2609. }
  2610. else {
  2611. pMachine = FindMachine(MachineName);
  2612. }
  2613. if (NULL == pMachine) {
  2614. pMachine = new CMachine(MachineName);
  2615. m_listMachines.AddTail(pMachine);
  2616. }
  2617. *ppMachine = pMachine;
  2618. return NULL != pMachine;
  2619. }
  2620. CMachine*
  2621. CMachineList::FindMachine(
  2622. LPCTSTR MachineName
  2623. )
  2624. {
  2625. if (!m_listMachines.IsEmpty()) {
  2626. POSITION pos = m_listMachines.GetHeadPosition();
  2627. while (NULL != pos) {
  2628. CMachine* pMachine;
  2629. pMachine = m_listMachines.GetNext(pos);
  2630. if (!lstrcmpi(MachineName, pMachine->GetMachineFullName())) {
  2631. return pMachine;
  2632. }
  2633. }
  2634. }
  2635. return NULL;
  2636. }