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.

1256 lines
35 KiB

  1. /*++
  2. Copyright (C) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. globals.cpp
  5. Abstract:
  6. This module implements global functions needed for the program.
  7. It also contain global variables/classes.
  8. Author:
  9. William Hsieh (williamh) created
  10. Revision History:
  11. --*/
  12. #include "devmgr.h"
  13. #include <winioctl.h>
  14. #include <shlobj.h>
  15. #define NO_SHELL_TREE_TYPE
  16. #include <shlobjp.h>
  17. //
  18. // global classes and variables
  19. //
  20. // this, of course, our dll's instance handle.
  21. HINSTANCE g_hInstance = NULL;
  22. //
  23. // A CMachineList is created for each instance of DLL. It is shared
  24. // by all the CComponentData the instance might create. The class CMachine
  25. // contains all the information about all the classes and devices on the
  26. // machine. Each CComponent should register itself to CMachine. This way,
  27. // A CComponent will get notification whenever there are changes in
  28. // the CMachine(Refresh, Property changes on a device, for example).
  29. // We do not rely on MMC's view notification(UpdatAllView) because
  30. // it only reaches all the CComponents created by a CComponenetData.
  31. //
  32. //
  33. CMachineList g_MachineList;
  34. CMemoryException g_MemoryException(TRUE);
  35. String g_strStartupMachineName;
  36. String g_strStartupDeviceId;
  37. String g_strStartupCommand;
  38. String g_strDevMgr;
  39. BOOL g_HasLoadDriverNamePrivilege = FALSE;
  40. CPrintDialog g_PrintDlg;
  41. //
  42. // UUID consts
  43. //
  44. const CLSID CLSID_DEVMGR = {0x74246BFC,0x4C96,0x11D0,{0xAB,0xEF,0x00,0x20,0xAF,0x6B,0x0B,0x7A}};
  45. const CLSID CLSID_DEVMGR_EXTENSION = {0x90087284,0xd6d6,0x11d0,{0x83,0x53,0x00,0xa0,0xc9,0x06,0x40,0xbf}};
  46. const CLSID CLSID_SYSTOOLS = {0x476e6448,0xaaff,0x11d0,{0xb9,0x44,0x00,0xc0,0x4f,0xd8,0xd5,0xb0}};
  47. const CLSID CLSID_DEVMGR_ABOUT = {0x94abaf2a,0x892a,0x11d1,{0xbb,0xc4,0x00,0xa0,0xc9,0x06,0x40,0xbf}};
  48. const TCHAR* const CLSID_STRING_DEVMGR = TEXT("{74246bfc-4c96-11d0-abef-0020af6b0b7a}");
  49. const TCHAR* const CLSID_STRING_DEVMGR_EXTENSION = TEXT("{90087284-d6d6-11d0-8353-00a0c90640bf}");
  50. const TCHAR* const CLSID_STRING_SYSTOOLS = TEXT("{476e6448-aaff-11d0-b944-00c04fd8d5b0}");
  51. const TCHAR* const CLSID_STRING_DEVMGR_ABOUT = TEXT("{94abaf2a-892a-11d1-bbc4-00a0c90640bf}");
  52. //
  53. // ProgID
  54. //
  55. const TCHAR* const PROGID_DEVMGR = TEXT("DevMgrSnapin.DevMgrSnapin.1");
  56. const TCHAR* const PROGID_DEVMGREXT = TEXT("DevMgrExtension.DevMgrExtension.1");
  57. const TCHAR* const PROGID_DEVMGR_ABOUT = TEXT("DevMgrAbout.DevMgrAbout.1");
  58. const TCHAR* const ENV_NAME_SYSTEMDRIVE = TEXT("SystemDrive");
  59. //
  60. // Node types const
  61. //
  62. const NODEINFO NodeInfo[TOTAL_COOKIE_TYPES] =
  63. {
  64. { COOKIE_TYPE_SCOPEITEM_DEVMGR,
  65. IDS_NAME_DEVMGR,
  66. IDS_DISPLAYNAME_SCOPE_DEVMGR,
  67. {0xc41dfb2a,0x4d5b,0x11d0,{0xab,0xef,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  68. TEXT("{c41dfb2a-4d5b-11d0-abef-0020af6b0b7a}")
  69. },
  70. { COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ,
  71. IDS_NAME_IRQ,
  72. 0,
  73. {0x494535fe,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  74. TEXT("{494535fe-5aa2-11d0-abf0-0020af6b0b7a}")
  75. },
  76. { COOKIE_TYPE_RESULTITEM_RESOURCE_DMA,
  77. IDS_NAME_DMA,
  78. 0,
  79. {0x49f0df4e,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  80. TEXT("{49f0df4e-5aa2-11d0-abf0-0020af6b0b7a}")
  81. },
  82. { COOKIE_TYPE_RESULTITEM_RESOURCE_IO,
  83. IDS_NAME_IO,
  84. 0,
  85. {0xa2958d7a,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  86. TEXT("{a2958d7a-5aa2-11d0-abf0-0020af6b0b7a}")
  87. },
  88. { COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY,
  89. IDS_NAME_MEMORY,
  90. 0,
  91. {0xa2958d7b,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  92. TEXT("{a2958d7b-5aa2-11d0-abf0-0020af6b0b7a}")
  93. },
  94. { COOKIE_TYPE_RESULTITEM_COMPUTER,
  95. IDS_NAME_COMPUTER,
  96. 0,
  97. {0xa2958d7c,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  98. TEXT("{a2958d7c-5aa2-11d0-abf0-0020af6b0b7a}")
  99. },
  100. { COOKIE_TYPE_RESULTITEM_DEVICE,
  101. IDS_NAME_DEVICE,
  102. 0,
  103. {0xa2958d7d,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  104. TEXT("{a2958d7d-5aa2-11d0-abf0-0020af6b0b7a}")
  105. },
  106. { COOKIE_TYPE_RESULTITEM_CLASS,
  107. IDS_NAME_CLASS,
  108. 0,
  109. {0xe677e204,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  110. TEXT("{e677e204-5aa2-11d0-abf0-0020af6b0b7a}")
  111. },
  112. { COOKIE_TYPE_RESULTITEM_RESTYPE,
  113. IDS_NAME_RESOURCES,
  114. 0,
  115. {0xa2958d7e,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
  116. TEXT("{a2958d7e-5aa2-11d0-abf0-0020af6b0b7a}")
  117. }
  118. };
  119. const IID IID_IDMTVOCX = \
  120. {0x142525f2,0x59d8,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}};
  121. const IID IID_ISnapinCallback = \
  122. {0x8e0ba98a,0xd161,0x11d0,{0x83,0x53,0x00,0xa0,0xc9,0x06,0x40,0xbf}};
  123. //
  124. // cliboard format strings
  125. //
  126. const TCHAR* const MMC_SNAPIN_MACHINE_NAME = TEXT("MMC_SNAPIN_MACHINE_NAME");
  127. const TCHAR* const SNAPIN_INTERNAL = TEXT("SNAPIN_INTERNAL");
  128. const TCHAR* const DEVMGR_SNAPIN_CLASS_GUID = TEXT("DEVMGR_SNAPIN_CLASS_GUID");
  129. const TCHAR* const DEVMGR_SNAPIN_DEVICE_ID = TEXT("DEVMGR_SNAPIN_DEVICE_ID");
  130. const TCHAR* const DEVMGR_COMMAND_PROPERTY = TEXT("Property");
  131. const TCHAR* const REG_PATH_DEVICE_MANAGER = TEXT("SOFTWARE\\Microsoft\\DeviceManager");
  132. const TCHAR* const REG_STR_BUS_TYPES = TEXT("BusTypes");
  133. const TCHAR* const REG_STR_TROUBLESHOOTERS = TEXT("TroubleShooters");
  134. const TCHAR* const DEVMGR_HELP_FILE_NAME = TEXT("devmgr.hlp");
  135. const TCHAR* const DEVMGR_HTML_HELP_FILE_NAME = TEXT("\\help\\devmgr.chm");
  136. // lookup table to translate problem number to its text resource id.
  137. const PROBLEMINFO g_ProblemInfo[] =
  138. {
  139. {IDS_PROB_NOPROBLEM, 0}, // NO PROBLEM
  140. {IDS_PROB_NOT_CONFIGURED, PIF_CODE_EMBEDDED}, // CM_PROB_NOT_CONFIGURED
  141. {IDS_PROB_DEVLOADERFAILED, PIF_CODE_EMBEDDED}, // CM_PROB_DEVLOADER_FAILED
  142. {IDS_PROB_OUT_OF_MEMORY, PIF_CODE_EMBEDDED}, // CM_PROB_OUT_OF_MEMORY
  143. {IDS_PROB_WRONG_TYPE, PIF_CODE_EMBEDDED}, // CM_PROB_ENTRY_IS_WRONG_TYPE
  144. {IDS_PROB_LACKEDARBITRATOR, PIF_CODE_EMBEDDED}, // CM_PROB_LACKED_ARBITRATOR
  145. {IDS_PROB_BOOT_CONFIG_CONFLICT, PIF_CODE_EMBEDDED}, // CM_PROB_BOOT_CONFIG_CONFLICT
  146. {IDS_PROB_FAILED_FILTER, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_FILTER
  147. {IDS_PROB_DEVLOADER_NOT_FOUND, PIF_CODE_EMBEDDED}, // CM_PROB_DEVLOADER_NOT_FOUND
  148. {IDS_PROB_INVALID_DATA, PIF_CODE_EMBEDDED}, // CM_PROB_INVALID_DATA
  149. {IDS_PROB_FAILED_START, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_START
  150. {IDS_PROB_LIAR, PIF_CODE_EMBEDDED}, // CM_PROB_LIAR
  151. {IDS_PROB_NORMAL_CONFLICT, PIF_CODE_EMBEDDED}, // CM_PROB_NORMAL_CONFLICT
  152. {IDS_PROB_NOT_VERIFIED, PIF_CODE_EMBEDDED}, // CM_PROB_NOT_VERIFIED
  153. {IDS_PROB_NEEDRESTART, PIF_CODE_EMBEDDED}, // CM_PROB_NEED_RESTART
  154. {IDS_PROB_REENUMERATION, PIF_CODE_EMBEDDED}, // CM_PROB_REENUMERATION
  155. {IDS_PROB_PARTIALCONFIG, PIF_CODE_EMBEDDED}, // CM_PROB_PARTIAL_LOG_CONF
  156. {IDS_PROB_UNKNOWN_RESOURCE, PIF_CODE_EMBEDDED}, // CM_PROB_UNKNOWN_RESOURCE
  157. {IDS_PROB_REINSTALL, PIF_CODE_EMBEDDED}, // CM_PROB_REINSTALL
  158. {IDS_PROB_REGISTRY, PIF_CODE_EMBEDDED}, // CM_PROB_REGISTRY
  159. {IDS_PROB_SYSTEMFAILURE, PIF_CODE_EMBEDDED}, // CM_PROB_VXDLDR
  160. {IDS_PROB_WILL_BE_REMOVED, PIF_CODE_EMBEDDED}, // CM_PROB_WILL_BE_REMOVED
  161. {IDS_PROB_DISABLED, PIF_CODE_EMBEDDED}, // CM_PROB_DISABLED
  162. {IDS_PROB_SYSTEMFAILURE, PIF_CODE_EMBEDDED}, // CM_PROB_DEVLOADER_NOT_READY
  163. {IDS_DEVICE_NOT_THERE, PIF_CODE_EMBEDDED}, // CM_PROB_DEVICE_NOT_THERE
  164. {IDS_PROB_MOVED, PIF_CODE_EMBEDDED}, // CM_PROB_MOVED
  165. {IDS_PROB_TOO_EARLY, PIF_CODE_EMBEDDED}, // CM_PROB_TOO_EARLY
  166. {IDS_PROB_NO_VALID_LOG_CONF, PIF_CODE_EMBEDDED}, // CM_PROB_NO_VALID_LOG_CONF
  167. {IDS_PROB_FAILEDINSTALL, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_INSTALL
  168. {IDS_PROB_HARDWAREDISABLED, PIF_CODE_EMBEDDED}, // CM_PROB_HARDWARE_DISABLED
  169. {IDS_PROB_CANT_SHARE_IRQ, PIF_CODE_EMBEDDED}, // CM_PROB_CANT_SHARE_IRQ
  170. {IDS_PROB_FAILED_ADD, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_ADD
  171. {IDS_PROB_DISABLED_SERVICE, PIF_CODE_EMBEDDED}, // CM_PROB_DISABLED_SERVICE
  172. {IDS_PROB_TRANSLATION_FAILED, PIF_CODE_EMBEDDED}, // CM_PROB_TRANSLATION_FAILED
  173. {IDS_PROB_NO_SOFTCONFIG, PIF_CODE_EMBEDDED}, // CM_PROB_NO_SOFTCONFIG
  174. {IDS_PROB_BIOS_TABLE, PIF_CODE_EMBEDDED}, // CM_PROB_BIOS_TABLE
  175. {IDS_PROB_IRQ_TRANSLATION_FAILED, PIF_CODE_EMBEDDED}, // CM_PROB_IRQ_TRANSLATION_FAILED
  176. {IDS_PROB_FAILED_DRIVER_ENTRY, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_DRIVER_ENTRY
  177. {IDS_PROB_DRIVER_FAILED_PRIOR_UNLOAD, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD
  178. {IDS_PROB_DRIVER_FAILED_LOAD, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_FAILED_LOAD
  179. {IDS_PROB_DRIVER_SERVICE_KEY_INVALID, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_SERVICE_KEY_INVALID
  180. {IDS_PROB_LEGACY_SERVICE_NO_DEVICES, PIF_CODE_EMBEDDED}, // CM_PROB_LEGACY_SERVICE_NO_DEVICES
  181. {IDS_PROB_DUPLICATE_DEVICE, PIF_CODE_EMBEDDED}, // CM_PROB_DUPLICATE_DEVICE
  182. {IDS_PROB_FAILED_POST_START, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_POST_START
  183. {IDS_PROB_HALTED, PIF_CODE_EMBEDDED}, // CM_PROB_HALTED
  184. {IDS_PROB_PHANTOM, PIF_CODE_EMBEDDED}, // CM_PROB_PHANTOM
  185. {IDS_PROB_SYSTEM_SHUTDOWN, PIF_CODE_EMBEDDED}, // CM_PROB_SYSTEM_SHUTDOWN
  186. {IDS_PROB_HELD_FOR_EJECT, PIF_CODE_EMBEDDED}, // CM_PROB_HELD_FOR_EJECT
  187. {IDS_PROB_DRIVER_BLOCKED, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_BLOCKED
  188. {IDS_PROB_REGISTRY_TOO_LARGE, PIF_CODE_EMBEDDED}, // CM_PROB_REGISTRY_TOO_LARGE
  189. {IDS_PROB_UNKNOWN_WITHCODE, PIF_CODE_EMBEDDED} // UNKNOWN PROBLEM
  190. };
  191. //
  192. // Global functions
  193. //
  194. #if DBG
  195. //
  196. // Debugging aids
  197. //
  198. void
  199. Trace(
  200. LPCTSTR format,
  201. ...
  202. )
  203. {
  204. // according to wsprintf specification, the max buffer size is
  205. // 1024
  206. TCHAR Buffer[1024];
  207. va_list arglist;
  208. va_start(arglist, format);
  209. wvsprintf(Buffer, format, arglist);
  210. va_end(arglist);
  211. OutputDebugString(TEXT("DEVMGR: "));
  212. OutputDebugString(Buffer);
  213. OutputDebugString(TEXT("\r\n"));
  214. }
  215. #endif
  216. inline
  217. BOOL
  218. IsBlankChar(TCHAR ch)
  219. {
  220. return (_T(' ') == ch || _T('\t') == ch);
  221. }
  222. inline
  223. LPTSTR
  224. SkipBlankChars(
  225. LPTSTR psz
  226. )
  227. {
  228. while (IsBlankChar(*psz))
  229. psz++;
  230. return psz;
  231. }
  232. // We import the following two "private" apis to avoid linking with rpcrt4.dll
  233. // which contains UuidFromString and StringToUuid functions.
  234. extern "C" {
  235. extern DWORD pSetupGuidFromString(LPCTSTR GuidString, LPGUID pGuid);
  236. extern DWORD pSetupStringFromGuid(const GUID* pGuid, LPTSTR Buffer, DWORD BufferLen);
  237. }
  238. //
  239. // This function converts a given string to GUID
  240. // INPUT:
  241. // GuidString -- the null terminated guid string
  242. // LPGUID -- buffer to receive the GUID
  243. // OUTPUT:
  244. // TRUE if the conversion succeeded.
  245. // FALSE if failed.
  246. //
  247. inline
  248. BOOL
  249. GuidFromString(
  250. LPCTSTR GuidString,
  251. LPGUID pGuid
  252. )
  253. {
  254. return ERROR_SUCCESS == pSetupGuidFromString(GuidString, pGuid);
  255. }
  256. // This function converts the given GUID to a string
  257. // INPUT:
  258. // pGuid -- the guid
  259. // Buffer -- the buffer to receive the string
  260. // BufferLen -- the buffer size in char unit
  261. // OUTPUT:
  262. // TRUE if the conversion succeeded.
  263. // FLASE if failed.
  264. //
  265. //
  266. inline
  267. BOOL
  268. GuidToString(
  269. LPGUID pGuid,
  270. LPTSTR Buffer,
  271. DWORD BufferLen
  272. )
  273. {
  274. return ERROR_SUCCESS == pSetupStringFromGuid(pGuid, Buffer, BufferLen);
  275. }
  276. //
  277. // This function allocates an OLE string from OLE task memory pool
  278. // It does necessary char set conversion before copying the string.
  279. //
  280. // INPUT: LPCTSTR str -- the initial string
  281. // OUTPUT: LPOLESTR -- the result OLE string. NULL if the function fails.
  282. //
  283. LPOLESTR
  284. AllocOleTaskString(
  285. LPCTSTR str
  286. )
  287. {
  288. if (!str)
  289. {
  290. SetLastError(ERROR_INVALID_PARAMETER);
  291. return NULL;
  292. }
  293. // if _UNICODE is defined, OLECHAR == WCHAR
  294. // if OLE2ANSI is defined, OLECHAR == CHAR
  295. #if defined(UNICODE) || defined(OLE2ANSI)
  296. size_t Len = lstrlen(str);
  297. // allocate the null terminate char also.
  298. LPOLESTR olestr = (LPOLESTR)::CoTaskMemAlloc((Len + 1) * sizeof(TCHAR));
  299. if (olestr)
  300. {
  301. lstrcpy((LPTSTR)olestr, str);
  302. return olestr;
  303. }
  304. return NULL;
  305. #else
  306. // OLE is in UNICODE while TCHAR is CHAR
  307. // We need to convert ANSI(TCHAR) to WCHAR
  308. size_t Len = strlen(str);
  309. LPOLESTR olestr = (LPOLESTR)::CoTaskMemAlloc((Len + 1) * sizeof(WCHAR));
  310. if (olestr)
  311. {
  312. MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)olestr, Len + 1);
  313. return olestr;
  314. }
  315. return NULL;
  316. #endif
  317. }
  318. inline
  319. void
  320. FreeOleTaskString(
  321. LPOLESTR olestr
  322. )
  323. {
  324. if (olestr)
  325. {
  326. ::CoTaskMemFree(olestr);
  327. }
  328. }
  329. //
  330. // This function addes the given menu item to snapin
  331. // INPUT:
  332. // iNameStringId -- menu item text resource id
  333. // iStatusBarStringId -- status bar text resource id.
  334. // iCommandId -- command id to be assigned to the menu item
  335. // InsertionPointId -- Insertion point id
  336. // Flags -- flags
  337. // SpecialFlags -- special flags
  338. // OUTPUT:
  339. // HRESULT
  340. //
  341. HRESULT
  342. AddMenuItem(
  343. LPCONTEXTMENUCALLBACK pCallback,
  344. int iNameStringId,
  345. int iStatusBarStringId,
  346. long lCommandId,
  347. long InsertionPointId,
  348. long Flags,
  349. long SpecialFlags
  350. )
  351. {
  352. ASSERT(pCallback);
  353. CONTEXTMENUITEM tCMI;
  354. memset(&tCMI, 0, sizeof(tCMI));
  355. tCMI.lCommandID = lCommandId;
  356. tCMI.lInsertionPointID = InsertionPointId;
  357. tCMI.fFlags = Flags;
  358. tCMI.fSpecialFlags = SpecialFlags;
  359. TCHAR Name[MAX_PATH];
  360. TCHAR Status[MAX_PATH];
  361. ::LoadString(g_hInstance, iNameStringId, Name, ARRAYLEN(Name));
  362. tCMI.strName = Name;
  363. if (iStatusBarStringId) {
  364. ::LoadString(g_hInstance, iStatusBarStringId, Status, ARRAYLEN(Status));
  365. tCMI.strStatusBarText = Status;
  366. }
  367. return pCallback->AddItem(&tCMI);
  368. }
  369. //
  370. // This function verifies the given machine name can be accessed remotely.
  371. // INPUT:
  372. // MachineName -- the machine name. The machine name must be
  373. // led by "\\\\".
  374. // OUTPUT:
  375. // BOOL TRUE for success and FALSE for failure. Check GetLastError() for failure
  376. // reason.
  377. //
  378. BOOL
  379. VerifyMachineName(
  380. LPCTSTR MachineName
  381. )
  382. {
  383. CONFIGRET cr = CR_SUCCESS;
  384. HMACHINE hMachine = NULL;
  385. HKEY hRemoteKey = NULL;
  386. HKEY hClass = NULL;
  387. if (MachineName)
  388. {
  389. int len = lstrlen(MachineName);
  390. //
  391. // empty means local machine.
  392. //
  393. if (!len)
  394. {
  395. return TRUE;
  396. }
  397. if (len > 2 && _T('\\') == MachineName[0] && _T('\\') == MachineName[1])
  398. {
  399. //
  400. // make sure we can connect the machine using cfgmgr32.
  401. //
  402. cr = CM_Connect_Machine(MachineName, &hMachine);
  403. //
  404. // We could not connect to the machine using cfgmgr32
  405. //
  406. if (CR_SUCCESS != cr)
  407. {
  408. goto clean0;
  409. }
  410. //
  411. // make sure we can connect to the registry of the remote machine
  412. //
  413. if (RegConnectRegistry(MachineName, HKEY_LOCAL_MACHINE,
  414. &hRemoteKey) != ERROR_SUCCESS) {
  415. cr = CR_REGISTRY_ERROR;
  416. goto clean0;
  417. }
  418. cr = CM_Open_Class_Key_Ex(NULL,
  419. NULL,
  420. KEY_READ,
  421. RegDisposition_OpenExisting,
  422. &hClass,
  423. CM_OPEN_CLASS_KEY_INSTALLER,
  424. hMachine
  425. );
  426. }
  427. }
  428. clean0:
  429. if (hMachine) {
  430. CM_Disconnect_Machine(hMachine);
  431. }
  432. if (hRemoteKey) {
  433. RegCloseKey(hRemoteKey);
  434. }
  435. if (hClass) {
  436. RegCloseKey(hClass);
  437. }
  438. //
  439. // We will basically set two different error codes for this API, since we need
  440. // to present this information to the user.
  441. // 1) SPAPI_E_MACHINE_UNABAILABLE
  442. // 2) ERROR_ACCESS_DENIED.
  443. //
  444. if (CR_SUCCESS == cr) {
  445. SetLastError(NO_ERROR);
  446. } else if (CR_MACHINE_UNAVAILABLE == cr) {
  447. SetLastError(SPAPI_E_MACHINE_UNAVAILABLE);
  448. } else {
  449. SetLastError(ERROR_ACCESS_DENIED);
  450. }
  451. return (CR_SUCCESS == cr);
  452. }
  453. // This function loads the string designated by the given
  454. // string id(resource id) from the module's resource to the provided
  455. // buffer. It returns the required buffer size(in chars) to hold the string,
  456. // not including the terminated NULL chars. Last error will be set
  457. // appropaitely.
  458. //
  459. // input: int StringId -- the resource id of the string to be loaded.
  460. // LPTSTR Buffer -- provided buffer to receive the string
  461. // UINT BufferSize -- the size of Buffer in chars
  462. // output:
  463. // UINT the required buffer size to receive the string
  464. // if it returns 0, GetLastError() returns the error code.
  465. //
  466. UINT
  467. LoadResourceString(
  468. int StringId,
  469. LPTSTR Buffer,
  470. UINT BufferSize
  471. )
  472. {
  473. // do some trivial tests.
  474. if (BufferSize && !Buffer)
  475. {
  476. SetLastError(ERROR_INVALID_PARAMETER);
  477. return 0;
  478. }
  479. // if caller provides buffer, try to load the string with the given buffer
  480. // and length.
  481. UINT FinalLen;
  482. if (Buffer)
  483. {
  484. FinalLen = ::LoadString(g_hInstance, StringId, Buffer, BufferSize);
  485. if (BufferSize > FinalLen)
  486. {
  487. return FinalLen;
  488. }
  489. }
  490. // Either the caller does not provide the buffer or the given buffer
  491. // is too small. Try to figure out the requried size.
  492. //
  493. // first use a stack-based buffer to get the string. If the buffer
  494. // is big enough, we are happy.
  495. TCHAR Temp[256];
  496. UINT ArrayLen = ARRAYLEN(Temp);
  497. FinalLen = ::LoadString(g_hInstance, StringId, Temp, ArrayLen);
  498. DWORD LastError = ERROR_SUCCESS;
  499. if (ArrayLen <= FinalLen)
  500. {
  501. // the stack-based buffer is too small, use heap-based buffer.
  502. // we have not got all the chars. we increase the buffer size of 256
  503. // chars each time it fails. The initial size is 512(256+256)
  504. // the max size is 32K
  505. ArrayLen = 256;
  506. TCHAR* HeapBuffer;
  507. FinalLen = 0;
  508. while (ArrayLen < 0x8000)
  509. {
  510. ArrayLen += 256;
  511. HeapBuffer = new TCHAR[ArrayLen];
  512. if (HeapBuffer)
  513. {
  514. FinalLen = ::LoadString(g_hInstance, StringId, HeapBuffer, ArrayLen);
  515. delete [] HeapBuffer;
  516. if (FinalLen < ArrayLen)
  517. break;
  518. }
  519. else
  520. {
  521. LastError = ERROR_NOT_ENOUGH_MEMORY;
  522. break;
  523. }
  524. }
  525. if (ERROR_SUCCESS != LastError)
  526. {
  527. SetLastError(LastError);
  528. FinalLen = 0;
  529. }
  530. }
  531. return FinalLen;
  532. }
  533. // This function get the problem text designated by the given problem number
  534. // for the given devnode on the given machine.
  535. //
  536. //
  537. // input: HMACHINE hMachine -- machine handle(NULL for local machine)
  538. // DEVNODE DevNode -- the device
  539. // ULONG ProblemNumber -- the problem number
  540. // LPTSTR Buffer -- provided buffer to receive the string
  541. // UINT BufferSize -- the size of Buffer in chars
  542. // output:
  543. // UINT the required buffer size to receive the string
  544. // if it returns 0, GetLastError() returns the error code.
  545. //
  546. UINT
  547. GetDeviceProblemText(
  548. HMACHINE hMachine,
  549. DEVNODE DevNode,
  550. ULONG ProblemNumber,
  551. LPTSTR Buffer,
  552. UINT BufferSize
  553. )
  554. {
  555. //
  556. // first does a trivial test
  557. //
  558. if (!Buffer && BufferSize)
  559. {
  560. SetLastError(ERROR_INVALID_PARAMETER);
  561. return 0;
  562. }
  563. int StringId;
  564. TCHAR* pMainText;
  565. UINT RequiredSize;
  566. UINT Length;
  567. pMainText = NULL;
  568. RequiredSize = 0;
  569. PROBLEMINFO pi;
  570. // get the PROBLEMINFO for the problem number
  571. pi = g_ProblemInfo[min(ProblemNumber, DEVMGR_NUM_CM_PROB-1)];
  572. // figure out the main text length
  573. Length = LoadResourceString(pi.StringId, Buffer, BufferSize);
  574. if (Length)
  575. {
  576. try
  577. {
  578. BufferPtr<TCHAR> MainTextPtr(Length + 1);
  579. LoadResourceString(pi.StringId, MainTextPtr, Length + 1);
  580. if (pi.Flags & PIF_CODE_EMBEDDED)
  581. {
  582. // embedded problem code in the main text.
  583. Length = LoadResourceString(IDS_PROB_CODE, NULL, 0);
  584. if (Length)
  585. {
  586. BufferPtr<TCHAR> FormatPtr(Length + 1);
  587. LoadResourceString(IDS_PROB_CODE, FormatPtr, Length + 1);
  588. BufferPtr<TCHAR> CodeTextPtr(Length + 1 + 32);
  589. wsprintf(CodeTextPtr, FormatPtr, ProblemNumber);
  590. pMainText = new TCHAR[lstrlen(MainTextPtr) + lstrlen(CodeTextPtr) + 32];
  591. wsprintf(pMainText, MainTextPtr, CodeTextPtr);
  592. }
  593. }
  594. else
  595. {
  596. pMainText = new TCHAR[Length + 1];
  597. lstrcpy(pMainText, MainTextPtr);
  598. }
  599. RequiredSize += lstrlen(pMainText);
  600. // copy the main text
  601. if (RequiredSize && BufferSize > RequiredSize)
  602. {
  603. lstrcpy(Buffer, pMainText);
  604. }
  605. }
  606. catch (CMemoryException* e)
  607. {
  608. e->Delete();
  609. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  610. RequiredSize = 0;
  611. }
  612. }
  613. if (pMainText)
  614. {
  615. delete [] pMainText;
  616. }
  617. return RequiredSize;
  618. }
  619. //
  620. // This function creates and shows a message box
  621. // INPUT:
  622. // hwndParent -- the window handle servers as the parent window to the
  623. // message box
  624. // MsgId -- string id for message box body. The string can be
  625. // a format string.
  626. // CaptionId -- string id for caption. if 0, default is device manager
  627. // Type -- the standard message box flags(MB_xxxx)
  628. // ... -- parameters to MsgId string if it contains any
  629. // format chars.
  630. //OUTPUT:
  631. // return value from MessageBox(IDOK, IDYES...)
  632. int MsgBoxParam(
  633. HWND hwndParent,
  634. int MsgId,
  635. int CaptionId,
  636. DWORD Type,
  637. ...
  638. )
  639. {
  640. TCHAR szMsg[MAX_PATH * 4], szCaption[MAX_PATH];;
  641. LPCTSTR pCaption;
  642. va_list parg;
  643. int Result;
  644. // if no MsgId is given, it is for no memory error;
  645. if (MsgId)
  646. {
  647. va_start(parg, Type);
  648. // load the msg string to szCaption(temp). The text may contain
  649. // format information
  650. if (!::LoadString(g_hInstance, MsgId, szCaption, ARRAYLEN(szCaption)))
  651. {
  652. goto NoMemory;
  653. }
  654. //finish up format string
  655. wvsprintf(szMsg, szCaption, parg);
  656. // if caption id is given, load it.
  657. if (CaptionId)
  658. {
  659. if (!::LoadString(g_hInstance, CaptionId, szCaption, ARRAYLEN(szCaption)))
  660. {
  661. goto NoMemory;
  662. }
  663. pCaption = szCaption;
  664. }
  665. else
  666. {
  667. pCaption = g_strDevMgr;
  668. }
  669. if (!(Result = MessageBox(hwndParent, szMsg, pCaption, Type)))
  670. {
  671. goto NoMemory;
  672. }
  673. return Result;
  674. }
  675. NoMemory:
  676. g_MemoryException.ReportError(hwndParent);
  677. return 0;
  678. }
  679. // This function creates and displays a message box for the given
  680. // win32 error(or last error)
  681. // INPUT:
  682. // hwndParent -- the parent window for the will-be-created message box
  683. // CaptionId -- optional string id for caption
  684. // Type -- message styles(MB_xxxx)
  685. // Error -- Error code. If the value is ERROR_SUCCESS,
  686. // GetLastError() will be called to retreive the
  687. // real error code.
  688. // OUTPUT:
  689. // the value return from MessageBox
  690. //
  691. int
  692. MsxBoxWinError(
  693. HWND hwndParent,
  694. int CaptionId,
  695. DWORD Type,
  696. DWORD Error
  697. )
  698. {
  699. if (ERROR_SUCCESS == Error)
  700. {
  701. Error = GetLastError();
  702. }
  703. // nonsense to report success!
  704. ASSERT(ERROR_SUCCESS != Error);
  705. TCHAR szMsg[MAX_PATH];
  706. TCHAR szCaption[MAX_PATH];
  707. LPCTSTR Caption;
  708. if (CaptionId && ::LoadString(g_hInstance, CaptionId, szCaption, ARRAYLEN(szCaption)))
  709. {
  710. Caption = szCaption;
  711. }
  712. else
  713. {
  714. Caption = g_strDevMgr;
  715. }
  716. FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
  717. NULL, Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  718. szMsg, ARRAYLEN(szMsg), NULL);
  719. return MessageBox(hwndParent, szMsg, Caption, Type);
  720. }
  721. // This functin prompts for restart.
  722. // INPUT:
  723. // hwndParent -- the window handle to be used as the parent window
  724. // to the restart dialog
  725. // RestartFlags -- flags(RESTART/REBOOT/POWERRECYCLE)
  726. // ResId -- designated string resource id. If 0, default will
  727. // be used.
  728. // OUTPUT:
  729. // ID returned from the MessageBox. IDYES if the user said Yes to the restart
  730. // dialog and IDNO if they said NO.
  731. INT
  732. PromptForRestart(
  733. HWND hwndParent,
  734. DWORD RestartFlags,
  735. int ResId
  736. )
  737. {
  738. INT id = 0;
  739. if (RestartFlags & (DI_NEEDRESTART | DI_NEEDREBOOT))
  740. {
  741. DWORD ExitWinCode;
  742. try
  743. {
  744. String str;
  745. if (RestartFlags & DI_NEEDRESTART)
  746. {
  747. if (!ResId)
  748. {
  749. ResId = IDS_DEVCHANGE_RESTART;
  750. }
  751. str.LoadString(g_hInstance, ResId);
  752. ExitWinCode = EWX_REBOOT;
  753. }
  754. else if (RestartFlags & DI_NEEDREBOOT)
  755. {
  756. if (!ResId && RestartFlags & DI_NEEDPOWERCYCLE)
  757. {
  758. String str2;
  759. str.LoadString(g_hInstance, IDS_POWERCYC1);
  760. str2.LoadString(g_hInstance, IDS_POWERCYC2);
  761. str += str2;
  762. ExitWinCode = EWX_SHUTDOWN;
  763. }
  764. else
  765. {
  766. if (!ResId)
  767. {
  768. ResId = IDS_DEVCHANGE_RESTART;
  769. }
  770. str.LoadString(g_hInstance, ResId);
  771. ExitWinCode = EWX_REBOOT;
  772. }
  773. }
  774. id = RestartDialogEx(hwndParent,
  775. str,
  776. ExitWinCode,
  777. REASON_PLANNED_FLAG | REASON_HWINSTALL
  778. );
  779. }
  780. catch(CMemoryException* e)
  781. {
  782. e->Delete();
  783. MsgBoxParam(hwndParent, 0, 0, 0);
  784. }
  785. }
  786. return id;
  787. }
  788. BOOL
  789. LoadEnumPropPage32(
  790. LPCTSTR RegString,
  791. HMODULE* pDll,
  792. FARPROC* pProcAddress
  793. )
  794. {
  795. // verify parameters
  796. if (!RegString || _T('\0') == RegString[0] || !pDll || !pProcAddress)
  797. {
  798. SetLastError(ERROR_INVALID_PARAMETER);
  799. return FALSE;
  800. }
  801. // make a copy of the string because we have to party on it
  802. TCHAR* psz = new TCHAR[lstrlen(RegString) + 1];
  803. if (!psz)
  804. {
  805. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  806. return FALSE;
  807. }
  808. lstrcpy(psz, RegString);
  809. LPTSTR DllName;
  810. LPTSTR DllNameEnd;
  811. LPTSTR FunctionName;
  812. LPTSTR FunctionNameEnd;
  813. LPTSTR p;
  814. p = psz;
  815. SetLastError(ERROR_SUCCESS);
  816. // the format of the string is "dllname, dllentryname"
  817. p = SkipBlankChars(p);
  818. if (_T('\0') != *p)
  819. {
  820. // looking for dllname which could be enclosed
  821. // inside double quote chars.
  822. // NOTE: not double quote chars inside double quoted string is allowed.
  823. if (_T('\"') == *p)
  824. {
  825. DllName = ++p;
  826. while (_T('\"') != *p && _T('\0') != *p)
  827. p++;
  828. DllNameEnd = p;
  829. if (_T('\"') == *p)
  830. p++;
  831. }
  832. else
  833. {
  834. DllName = p;
  835. while (!IsBlankChar(*p) && _T(',') != *p)
  836. p++;
  837. DllNameEnd = p;
  838. }
  839. // looking for ','
  840. p = SkipBlankChars(p);
  841. if (_T('\0') != *p && _T(',') == *p)
  842. {
  843. p = SkipBlankChars(p + 1);
  844. if (_T('\0') != *p)
  845. {
  846. FunctionName = p++;
  847. while (!IsBlankChar(*p) && _T('\0') != *p)
  848. p++;
  849. FunctionNameEnd = p;
  850. }
  851. }
  852. }
  853. if (DllName && FunctionName)
  854. {
  855. *DllNameEnd = _T('\0');
  856. *FunctionNameEnd = _T('\0');
  857. *pDll = LoadLibrary(DllName);
  858. if (*pDll)
  859. {
  860. #ifdef UNICODE
  861. // convert Wide char to ANSI which is GetProcAddress expected.
  862. // We do not append a 'A" or a "W' here.
  863. CHAR FuncNameA[256];
  864. int LenA = WideCharToMultiByte(CP_ACP, 0,
  865. FunctionName,
  866. wcslen(FunctionName) + 1,
  867. FuncNameA,
  868. sizeof(FuncNameA),
  869. NULL, NULL);
  870. *pProcAddress = GetProcAddress(*pDll, FuncNameA);
  871. #else
  872. *pProcAddress = GetProcAddress(*pDll, FunctionName);
  873. #endif
  874. }
  875. }
  876. delete [] psz;
  877. if (!*pProcAddress && *pDll)
  878. FreeLibrary(*pDll);
  879. return (*pDll && *pProcAddress);
  880. }
  881. BOOL
  882. AddPropPageCallback(
  883. HPROPSHEETPAGE hPage,
  884. LPARAM lParam
  885. )
  886. {
  887. CPropSheetData* ppsData = (CPropSheetData*)lParam;
  888. ASSERT(ppsData);
  889. return ppsData->InsertPage(hPage);
  890. }
  891. PCTSTR
  892. MyGetFileTitle(
  893. IN PCTSTR FilePath
  894. )
  895. /*++
  896. Routine Description:
  897. This routine returns a pointer to the first character in the
  898. filename part of the supplied path. If only a filename was given,
  899. then this will be a pointer to the first character in the string
  900. (i.e., the same as what was passed in).
  901. To find the filename part, the routine returns the last component of
  902. the string, beginning with the character immediately following the
  903. last '\', '/' or ':'. (NB NT treats '/' as equivalent to '\' )
  904. Arguments:
  905. FilePath - Supplies the file path from which to retrieve the filename
  906. portion.
  907. Return Value:
  908. A pointer to the beginning of the filename portion of the path.
  909. --*/
  910. {
  911. PCTSTR LastComponent = FilePath;
  912. TCHAR CurChar;
  913. while(CurChar = *FilePath) {
  914. FilePath = CharNext(FilePath);
  915. if((CurChar == TEXT('\\')) || (CurChar == TEXT('/')) || (CurChar == TEXT(':'))) {
  916. LastComponent = FilePath;
  917. }
  918. }
  919. return LastComponent;
  920. }
  921. BOOL
  922. AddToolTips(
  923. HWND hDlg,
  924. UINT id,
  925. LPCTSTR pszText,
  926. HWND *phwnd
  927. )
  928. {
  929. if (*phwnd == NULL)
  930. {
  931. *phwnd = CreateWindow(TOOLTIPS_CLASS,
  932. TEXT(""),
  933. WS_POPUP | TTS_NOPREFIX,
  934. CW_USEDEFAULT,
  935. CW_USEDEFAULT,
  936. CW_USEDEFAULT,
  937. CW_USEDEFAULT,
  938. hDlg,
  939. NULL,
  940. g_hInstance,
  941. NULL);
  942. if (*phwnd)
  943. {
  944. TOOLINFO ti;
  945. ti.cbSize = sizeof(ti);
  946. ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  947. ti.hwnd = hDlg;
  948. ti.uId = (UINT_PTR)GetDlgItem(hDlg, id);
  949. ti.lpszText = (LPTSTR)pszText; // const -> non const
  950. ti.hinst = g_hInstance;
  951. SendMessage(*phwnd, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
  952. }
  953. }
  954. return (*phwnd) ? TRUE : FALSE;
  955. }
  956. BOOL
  957. EnablePrivilege(
  958. IN PCTSTR PrivilegeName,
  959. IN BOOL Enable
  960. )
  961. /*++
  962. Routine Description:
  963. Enable or disable a given named privilege.
  964. Arguments:
  965. PrivilegeName - supplies the name of a system privilege.
  966. Enable - flag indicating whether to enable or disable the privilege.
  967. Return Value:
  968. Boolean value indicating whether the operation was successful.
  969. --*/
  970. {
  971. HANDLE Token;
  972. BOOL b;
  973. TOKEN_PRIVILEGES NewPrivileges;
  974. LUID Luid;
  975. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
  976. return(FALSE);
  977. }
  978. if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  979. CloseHandle(Token);
  980. return(FALSE);
  981. }
  982. NewPrivileges.PrivilegeCount = 1;
  983. NewPrivileges.Privileges[0].Luid = Luid;
  984. NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  985. b = AdjustTokenPrivileges(
  986. Token,
  987. FALSE,
  988. &NewPrivileges,
  989. 0,
  990. NULL,
  991. NULL
  992. );
  993. CloseHandle(Token);
  994. return(b);
  995. }
  996. void Int64ToStr(LONGLONG n, LPTSTR lpBuffer)
  997. {
  998. TCHAR szTemp[40];
  999. LONGLONG iChr = 0;
  1000. do {
  1001. szTemp[iChr++] = TEXT('0') + (TCHAR)(n % 10);
  1002. n = n / 10;
  1003. } while (n != 0);
  1004. do {
  1005. iChr--;
  1006. *lpBuffer++ = szTemp[iChr];
  1007. } while (iChr != 0);
  1008. *lpBuffer++ = '\0';
  1009. }
  1010. //
  1011. // Obtain NLS info about how numbers should be grouped.
  1012. //
  1013. // The annoying thing is that LOCALE_SGROUPING and NUMBERFORMAT
  1014. // have different ways of specifying number grouping.
  1015. //
  1016. // LOCALE NUMBERFMT Sample Country
  1017. //
  1018. // 3;0 3 1,234,567 United States
  1019. // 3;2;0 32 12,34,567 India
  1020. // 3 30 1234,567 ??
  1021. //
  1022. // Not my idea. That's the way it works.
  1023. //
  1024. UINT GetNLSGrouping(void)
  1025. {
  1026. TCHAR szGrouping[32];
  1027. // If no locale info, then assume Western style thousands
  1028. if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szGrouping, ARRAYLEN(szGrouping)))
  1029. return 3;
  1030. UINT grouping = 0;
  1031. LPTSTR psz = szGrouping;
  1032. for (;;)
  1033. {
  1034. if (*psz == '0') break; // zero - stop
  1035. else if ((UINT)(*psz - '0') < 10) // digit - accumulate it
  1036. grouping = grouping * 10 + (UINT)(*psz - '0');
  1037. else if (*psz) // punctuation - ignore it
  1038. { }
  1039. else // end of string, no "0" found
  1040. {
  1041. grouping = grouping * 10; // put zero on end (see examples)
  1042. break; // and finished
  1043. }
  1044. psz++;
  1045. }
  1046. return grouping;
  1047. }
  1048. STDAPI_(LPTSTR)
  1049. AddCommas64(
  1050. LONGLONG n,
  1051. LPTSTR pszResult,
  1052. UINT cchResult
  1053. )
  1054. {
  1055. TCHAR szTemp[MAX_COMMA_NUMBER_SIZE];
  1056. TCHAR szSep[5];
  1057. NUMBERFMT nfmt;
  1058. nfmt.NumDigits=0;
  1059. nfmt.LeadingZero=0;
  1060. nfmt.Grouping = GetNLSGrouping();
  1061. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYLEN(szSep));
  1062. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  1063. nfmt.NegativeOrder= 0;
  1064. Int64ToStr(n, szTemp);
  1065. if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, cchResult) == 0)
  1066. StrCpyN(pszResult, szTemp, cchResult);
  1067. return pszResult;
  1068. }