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.

658 lines
28 KiB

  1. #include "mslocusr.h"
  2. #include "msluglob.h"
  3. #include "resource.h"
  4. /* InstallLogonDialog - check if there is a primary logon provider already on
  5. * the system, and if not, install MSLOCUSR as a net provider and make it the
  6. * primary logon. Returns TRUE if the NP was installed.
  7. *
  8. * This chunk of hideous registry code exists because NETDI.DLL (the win95
  9. * network setup engine) (a) has no programmatic interface, it just assumes
  10. * it's being driven by NETCPL.CPL; (b) is 16-bit code, so even if it had
  11. * a programmatic interface, we'd have to thunk; and (c) if everything's
  12. * not consistent in his database of what network components are installed
  13. * and which are bound to which, then the next time the user brings up the
  14. * network CPL, any components which don't make sense just get silently
  15. * deinstalled.
  16. *
  17. * The set of registry keys and values which need to be added, changed, or
  18. * updated was gleaned from a registry diff done after using the real network
  19. * CPL to install this logon provider from an INF. A similar registry diff
  20. * and similar code could be created to programmatically install a transport.
  21. * Don't ask me to do it for you, though...
  22. *
  23. * Note that in case of registry errors, we just bail out. It would require
  24. * a huge amount of extra code to keep track of everything that had been done
  25. * up to that point and undo it. The worst that happens if we do strange
  26. * things to the net component database is that NETDI will deinstall our
  27. * component the next time the user brings up the network control panel. It
  28. * shouldn't actually cause any crashes or anything like that.
  29. */
  30. BOOL InstallLogonDialog(void)
  31. {
  32. HKEY hkey; /* used for various work */
  33. LONG err;
  34. TCHAR szBuf[MAX_PATH];
  35. DWORD dwType;
  36. DWORD cbData;
  37. DWORD dwTemp;
  38. DWORD dwDisp;
  39. NLS_STR nlsNPName(MAX_RES_STR_LEN);
  40. if (nlsNPName.LoadString(IDS_NP_NAME) != ERROR_SUCCESS)
  41. return FALSE;
  42. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon", 0,
  43. KEY_QUERY_VALUE | KEY_SET_VALUE, &hkey);
  44. if (err != ERROR_SUCCESS)
  45. return FALSE; /* big problems if we can't get this guy */
  46. /* Get the PrimaryProvider value, which is the name of the net provider
  47. * that's handling the main logon dialog. If it's there and not blank,
  48. * then presumably the user's on a LAN or something, so we don't want
  49. * to replace the logon dialog.
  50. */
  51. cbData = sizeof(szBuf);
  52. err = RegQueryValueEx(hkey, "PrimaryProvider", NULL, &dwType,
  53. (LPBYTE)szBuf, &cbData);
  54. if (err == ERROR_SUCCESS && szBuf[0] != '\0') {
  55. RegCloseKey(hkey);
  56. return FALSE;
  57. }
  58. /* Make us the primary logon provider, as far as MPR and the logon code
  59. * are concerned.
  60. */
  61. err = RegSetValueEx(hkey, "PrimaryProvider", 0, REG_SZ,
  62. (LPBYTE)nlsNPName.QueryPch(), nlsNPName.strlen()+1);
  63. RegCloseKey(hkey);
  64. if (err != ERROR_SUCCESS)
  65. return FALSE;
  66. /* Under HKLM\SW\MS\W\CV\Network\Real Mode Net, preferredredir=null string,
  67. * since we will now be the primary network in all respects. NETDI needs
  68. * this to avoid getting confused.
  69. */
  70. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Network\\Real Mode Net",
  71. 0, KEY_QUERY_VALUE, &hkey);
  72. if (err == ERROR_SUCCESS) {
  73. err = RegSetValueEx(hkey, "preferredredir", 0, REG_SZ, (LPBYTE)TEXT(""), sizeof(TCHAR));
  74. RegCloseKey(hkey);
  75. }
  76. /* Add new keys under HKLM\System\CurrentControlSet which will actually
  77. * make MPR load our DLL as a net provider.
  78. */
  79. HKEY hkeyFamilyClient;
  80. err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\NPSTUB\\NetworkProvider",
  81. 0, "", REG_OPTION_NON_VOLATILE,
  82. KEY_SET_VALUE,
  83. NULL, &hkeyFamilyClient, &dwDisp);
  84. if (err == ERROR_SUCCESS) {
  85. RegSetValueEx(hkeyFamilyClient, "Name", 0, REG_SZ,
  86. (LPBYTE)nlsNPName.QueryPch(), nlsNPName.strlen()+1);
  87. RegSetValueEx(hkeyFamilyClient, "ProviderPath", 0, REG_SZ,
  88. (LPBYTE)TEXT("ienpstub.dll"), 11 * sizeof(TCHAR));
  89. RegSetValueEx(hkeyFamilyClient, "RealDLL", 0, REG_SZ,
  90. (LPBYTE)TEXT("mslocusr.dll"), 13 * sizeof(TCHAR));
  91. RegSetValueEx(hkeyFamilyClient, "Description", 0, REG_SZ,
  92. (LPBYTE)nlsNPName.QueryPch(), nlsNPName.strlen()+1);
  93. dwTemp = WNNC_NET_MSNET;
  94. RegSetValueEx(hkeyFamilyClient, "NetID", 0, REG_DWORD,
  95. (LPBYTE)&dwTemp, sizeof(dwTemp));
  96. dwTemp = 0x40000000;
  97. RegSetValueEx(hkeyFamilyClient, "CallOrder", 0, REG_DWORD,
  98. (LPBYTE)&dwTemp, sizeof(dwTemp));
  99. RegCloseKey(hkeyFamilyClient);
  100. }
  101. err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
  102. 0, "", REG_OPTION_NON_VOLATILE,
  103. KEY_SET_VALUE,
  104. NULL, &hkeyFamilyClient, &dwDisp);
  105. if (err == ERROR_SUCCESS) {
  106. cbData = sizeof(szBuf);
  107. if (RegQueryValueEx(hkeyFamilyClient, "NPSTUB", NULL, &dwType,
  108. (LPBYTE)szBuf, &cbData) == ERROR_SUCCESS) {
  109. /* Our provider is already installed! Better not do anything
  110. * more than just making it default, which we've already done.
  111. */
  112. RegCloseKey(hkeyFamilyClient);
  113. return FALSE;
  114. }
  115. RegSetValueEx(hkeyFamilyClient, "NPSTUB", 0, REG_SZ,
  116. (LPBYTE)TEXT(""), sizeof(TCHAR));
  117. RegCloseKey(hkeyFamilyClient);
  118. }
  119. /* We've now installed our NP in the registry, and to see it appear we
  120. * need a reboot. So from here on, if we bail out, we return TRUE.
  121. */
  122. /* First big chunk of network component database management. Under
  123. * HKLM\System\CurrentControlSet\Services\Class\NetClient there is a
  124. * four-digit numeric subkey (e.g., "0000") for each network client.
  125. * One of them will be the default network client as far as NETDI's
  126. * database is concerned; this is indicated by the existence of the
  127. * "Ndi\Default" subkey under the number key. If we find one of those
  128. * guys, we save away the DeviceID value from the Ndi subkey so we can
  129. * tweak some configuration flags later in another part of the database.
  130. *
  131. * While enumerating the keys, we keep track of the highest number we've
  132. * seen so far. When we're done, we add 1 to that and use that as the
  133. * subkey name for our client. The number is kept separate from the
  134. * RegEnumKey index because the numbers are not necessarily packed (nor
  135. * will RegEnumKey necessarily return them in numeric order!).
  136. */
  137. HKEY hkeyNetClient;
  138. err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class\\NetClient",
  139. 0, "", REG_OPTION_NON_VOLATILE,
  140. KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
  141. NULL, &hkeyNetClient, &dwDisp);
  142. if (err != ERROR_SUCCESS)
  143. return TRUE;
  144. UINT nFamilyNum;
  145. TCHAR szFamilyNumString[5]; /* four digits plus null */
  146. TCHAR szDefaultDeviceID[MAX_PATH] = "";
  147. if (dwDisp == REG_OPENED_EXISTING_KEY) {
  148. NLS_STR nlsSubKey(20); /* enough for four digits, plus some just in case */
  149. DWORD iSubKey = 0;
  150. UINT maxSubKey = 0;
  151. for (;;) {
  152. err = RegEnumKey(hkeyNetClient, iSubKey, nlsSubKey.Party(), nlsSubKey.QueryAllocSize());
  153. nlsSubKey.DonePartying();
  154. if (err != ERROR_SUCCESS)
  155. break;
  156. NLS_STR nls2(nlsSubKey.strlen() + 12);
  157. if (nls2.QueryError() == ERROR_SUCCESS) {
  158. nls2 = nlsSubKey;
  159. nls2.strcat("\\Ndi\\Default");
  160. cbData = sizeof(szBuf);
  161. err = RegQueryValue(hkeyNetClient, nls2.QueryPch(), szBuf, (PLONG)&cbData);
  162. if (err == ERROR_SUCCESS) {
  163. if (!lstrcmpi(szBuf, "True")) {
  164. HKEY hkeyNdi;
  165. NLS_STR nls3(nlsSubKey.strlen() + 5);
  166. if (nls3.QueryError() == ERROR_SUCCESS) {
  167. nls3 = nlsSubKey;
  168. nls3.strcat("\\Ndi");
  169. err = RegOpenKeyEx(hkeyNetClient, nls3.QueryPch(), 0, KEY_QUERY_VALUE, &hkeyNdi);
  170. if (err == ERROR_SUCCESS) {
  171. cbData = sizeof(szDefaultDeviceID);
  172. RegQueryValueEx(hkeyNdi, "DeviceID", NULL, &dwType,
  173. (LPBYTE)szDefaultDeviceID, &cbData);
  174. RegCloseKey(hkeyNdi);
  175. }
  176. }
  177. }
  178. RegDeleteKey(hkeyNetClient, nls2.QueryPch());
  179. }
  180. }
  181. UINT nSubKey = nlsSubKey.atoi();
  182. if (nSubKey > maxSubKey)
  183. maxSubKey = nSubKey;
  184. iSubKey++;
  185. }
  186. nFamilyNum = maxSubKey+1;
  187. }
  188. else
  189. nFamilyNum = 0;
  190. wsprintf(szFamilyNumString, "%04d", nFamilyNum);
  191. err = RegCreateKeyEx(hkeyNetClient, szFamilyNumString,
  192. 0, "", REG_OPTION_NON_VOLATILE,
  193. KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
  194. NULL, &hkeyFamilyClient, &dwDisp);
  195. if (err == ERROR_SUCCESS) {
  196. RegSetValueEx(hkeyFamilyClient, "DriverDesc", 0, REG_SZ,
  197. (LPBYTE)nlsNPName.QueryPch(), nlsNPName.strlen()+1);
  198. RegSetValueEx(hkeyFamilyClient, "InfPath", 0, REG_SZ,
  199. (LPBYTE)TEXT("NETFAM.INF"), 11 * sizeof(TCHAR));
  200. RegSetValueEx(hkeyFamilyClient, "DriverDate", 0, REG_SZ,
  201. (LPBYTE)TEXT(" 5-21-1997"), 11 * sizeof(TCHAR));
  202. err = RegCreateKeyEx(hkeyFamilyClient, "Ndi",
  203. 0, "", REG_OPTION_NON_VOLATILE,
  204. KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
  205. NULL, &hkey, &dwDisp);
  206. if (err == ERROR_SUCCESS) {
  207. RegSetValueEx(hkey, "DeviceID", 0, REG_SZ,
  208. (LPBYTE)TEXT("FAMILY"), 7 * sizeof(TCHAR));
  209. RegSetValueEx(hkey, "NetworkProvider", 0, REG_SZ,
  210. (LPBYTE)nlsNPName.QueryPch(), nlsNPName.strlen()+1);
  211. RegSetValueEx(hkey, "InstallInf", 0, REG_SZ,
  212. (LPBYTE)TEXT(""), sizeof(TCHAR));
  213. RegSetValueEx(hkey, "InfSection", 0, REG_SZ,
  214. (LPBYTE)TEXT("FAMILY.ndi"), 11 * sizeof(TCHAR));
  215. {
  216. NLS_STR nlsHelpText(MAX_RES_STR_LEN);
  217. if (nlsHelpText.LoadString(IDS_NETFAM_HELP_TEXT) == ERROR_SUCCESS) {
  218. RegSetValueEx(hkey, "HelpText", 0, REG_SZ,
  219. (LPBYTE)nlsHelpText.QueryPch(), nlsHelpText.strlen() + 1);
  220. }
  221. }
  222. HKEY hkeyInterfaces;
  223. err = RegCreateKeyEx(hkey, "Interfaces",
  224. 0, "", REG_OPTION_NON_VOLATILE,
  225. KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
  226. NULL, &hkeyInterfaces, &dwDisp);
  227. if (err == ERROR_SUCCESS) {
  228. RegSetValueEx(hkeyInterfaces, "DefLower", 0, REG_SZ,
  229. (LPBYTE)TEXT("netbios,ipxDHost"), 13 * sizeof(TCHAR));
  230. RegSetValueEx(hkeyInterfaces, "LowerRange", 0, REG_SZ,
  231. (LPBYTE)TEXT("netbios,ipxDHost"), 13 * sizeof(TCHAR));
  232. RegSetValueEx(hkeyInterfaces, "Lower", 0, REG_SZ,
  233. (LPBYTE)TEXT("netbios,ipxDHost"), 13 * sizeof(TCHAR));
  234. RegSetValueEx(hkeyInterfaces, "Upper", 0, REG_SZ,
  235. (LPBYTE)TEXT(""), sizeof(TCHAR));
  236. RegCloseKey(hkeyInterfaces);
  237. }
  238. if (err == ERROR_SUCCESS)
  239. err = RegSetValue(hkey, "Install", REG_SZ, "FAMILY.Install", 14);
  240. if (err == ERROR_SUCCESS)
  241. err = RegSetValue(hkey, "Remove", REG_SZ, "FAMILY.Remove", 13);
  242. if (err == ERROR_SUCCESS)
  243. err = RegSetValue(hkey, "Default", REG_SZ, "True", 5);
  244. RegCloseKey(hkey);
  245. }
  246. RegCloseKey(hkeyFamilyClient);
  247. }
  248. RegCloseKey(hkeyNetClient);
  249. if (err != ERROR_SUCCESS)
  250. return TRUE;
  251. /* Now the other half of the database, under HKLM\Enum\Network. This has
  252. * a subkey (named by DeviceID, as seen above) for each network component.
  253. * Under each such subkey, there's a numbered subkey for each instance.
  254. * We have three tasks here: First of all, for each instance of the client
  255. * that used to be the default, we have to mask out bit 0x00000010 from
  256. * the ConfigFlags value, to make it no longer the default client. Then
  257. * we have to create a new branch for our own client, which mainly points
  258. * back to the other section of the database which we just finished with.
  259. * Finally, we must find MSTCP and add a binding between it and our client,
  260. * because NETDI assumes that a client that's not bound to any transports
  261. * must be messed up, so it deletes it.
  262. */
  263. HKEY hkeyEnum;
  264. err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Enum\\Network",
  265. 0, "", REG_OPTION_NON_VOLATILE,
  266. KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
  267. NULL, &hkeyEnum, &dwDisp);
  268. if (err != ERROR_SUCCESS)
  269. return TRUE;
  270. /* Un-default the default client. */
  271. if (szDefaultDeviceID[0] != '\0') {
  272. HKEY hkeyDefaultDevice;
  273. err = RegOpenKeyEx(hkeyEnum, szDefaultDeviceID, 0,
  274. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
  275. &hkeyDefaultDevice);
  276. if (err == ERROR_SUCCESS) {
  277. NLS_STR nlsSubKey(20); /* enough for four digits, plus some just in case */
  278. DWORD iSubKey = 0;
  279. for (;;) {
  280. err = RegEnumKey(hkeyDefaultDevice, iSubKey, nlsSubKey.Party(), nlsSubKey.QueryAllocSize());
  281. nlsSubKey.DonePartying();
  282. if (err != ERROR_SUCCESS)
  283. break;
  284. HKEY hkeyInstance;
  285. err = RegOpenKeyEx(hkeyDefaultDevice, nlsSubKey.QueryPch(),
  286. 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyInstance);
  287. if (err == ERROR_SUCCESS) {
  288. DWORD dwConfigFlags;
  289. cbData = sizeof(dwConfigFlags);
  290. err = RegQueryValueEx(hkeyInstance, "ConfigFlags", NULL,
  291. &dwType, (LPBYTE)&dwConfigFlags,
  292. &cbData);
  293. if (err == ERROR_SUCCESS &&
  294. (dwType == REG_DWORD || dwType == REG_BINARY) &&
  295. (dwConfigFlags & 0x10)) {
  296. dwConfigFlags &= ~0x10;
  297. RegSetValueEx(hkeyInstance, "ConfigFlags", 0, dwType,
  298. (LPBYTE)&dwConfigFlags, cbData);
  299. }
  300. RegCloseKey(hkeyInstance);
  301. }
  302. iSubKey++;
  303. }
  304. RegCloseKey(hkeyDefaultDevice);
  305. }
  306. }
  307. /* Now create a new branch for our client. */
  308. err = RegCreateKeyEx(hkeyEnum, "FAMILY\\0000",
  309. 0, "", REG_OPTION_NON_VOLATILE,
  310. KEY_SET_VALUE,
  311. NULL, &hkeyFamilyClient, &dwDisp);
  312. if (err == ERROR_SUCCESS) {
  313. RegSetValueEx(hkeyFamilyClient, "Class", 0, REG_SZ,
  314. (LPBYTE)TEXT("NetClient"), 10 * sizeof(TCHAR));
  315. lstrcpy(szBuf, "NetClient\\");
  316. lstrcat(szBuf, szFamilyNumString);
  317. RegSetValueEx(hkeyFamilyClient, "Driver", 0, REG_SZ, (LPBYTE)szBuf, lstrlen(szBuf)+1);
  318. RegSetValueEx(hkeyFamilyClient, "MasterCopy", 0, REG_SZ,
  319. (LPBYTE)TEXT("Enum\\Network\\FAMILY\\0000"), 25 * sizeof(TCHAR));
  320. RegSetValueEx(hkeyFamilyClient, "DeviceDesc", 0, REG_SZ,
  321. (LPBYTE)nlsNPName.QueryPch(), nlsNPName.strlen()+1);
  322. RegSetValueEx(hkeyFamilyClient, "CompatibleIDs", 0, REG_SZ,
  323. (LPBYTE)TEXT("FAMILY"), 7 * sizeof(TCHAR));
  324. RegSetValueEx(hkeyFamilyClient, "Mfg", 0, REG_SZ,
  325. (LPBYTE)TEXT("Microsoft"), 10 * sizeof(TCHAR));
  326. dwTemp = 0x00000010;
  327. RegSetValueEx(hkeyFamilyClient, "ConfigFlags", 0, REG_BINARY,
  328. (LPBYTE)&dwTemp, sizeof(dwTemp));
  329. /* A "Bindings" subkey needs to exist here, with no values in it
  330. * (since our "client" isn't bound to any higher level components
  331. * like servers).
  332. */
  333. err = RegCreateKeyEx(hkeyFamilyClient, "Bindings",
  334. 0, "", REG_OPTION_NON_VOLATILE,
  335. KEY_SET_VALUE,
  336. NULL, &hkey, &dwDisp);
  337. if (err == ERROR_SUCCESS)
  338. RegCloseKey(hkey);
  339. RegCloseKey(hkeyFamilyClient);
  340. }
  341. /* Get MSTCP's enum key, get the first instance, and from it we can find
  342. * the "master" instance. We can then add a binding to ourselves there.
  343. * Can't just assume "0000" as the first one, unfortunately.
  344. */
  345. err = RegOpenKeyEx(hkeyEnum, "MSTCP", 0,
  346. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
  347. &hkey);
  348. if (err == ERROR_SUCCESS) {
  349. NLS_STR nlsSubKey(20); /* enough for four digits, plus some just in case */
  350. DWORD iSubKey = 0;
  351. for (;;) {
  352. err = RegEnumKey(hkey, iSubKey, nlsSubKey.Party(), nlsSubKey.QueryAllocSize());
  353. nlsSubKey.DonePartying();
  354. if (err != ERROR_SUCCESS)
  355. break;
  356. HKEY hkeyInstance;
  357. err = RegOpenKeyEx(hkey, nlsSubKey.QueryPch(),
  358. 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyInstance);
  359. if (err == ERROR_SUCCESS) {
  360. cbData = sizeof(szBuf);
  361. err = RegQueryValueEx(hkeyInstance, "MasterCopy", NULL,
  362. &dwType, (LPBYTE)szBuf,
  363. &cbData);
  364. RegCloseKey(hkeyInstance);
  365. /* The MasterCopy value is actually a path to a registry key
  366. * from HKEY_LOCAL_MACHINE. We want to deal with its Bindings
  367. * subkey.
  368. */
  369. if (err == ERROR_SUCCESS) {
  370. HKEY hkeyBindings;
  371. lstrcat(szBuf, "\\Bindings");
  372. err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szBuf,
  373. 0, "", REG_OPTION_NON_VOLATILE,
  374. KEY_SET_VALUE,
  375. NULL, &hkeyBindings, &dwDisp);
  376. if (err == ERROR_SUCCESS) {
  377. RegSetValueEx(hkeyBindings, "FAMILY\\0000", 0, REG_SZ,
  378. (LPBYTE)TEXT(""), sizeof(TCHAR));
  379. RegCloseKey(hkeyBindings);
  380. }
  381. break; /* abandon enum loop */
  382. }
  383. iSubKey++;
  384. }
  385. }
  386. RegCloseKey(hkey);
  387. }
  388. RegCloseKey(hkeyEnum);
  389. return TRUE;
  390. }
  391. /*
  392. Purpose: Recursively delete the key, including all child values
  393. and keys. Mimics what RegDeleteKey does in Win95.
  394. Snarfed from shlwapi so we don't end up loading him at
  395. boot time.
  396. Returns:
  397. Cond: --
  398. */
  399. DWORD
  400. DeleteKeyRecursively(
  401. IN HKEY hkey,
  402. IN LPCSTR pszSubKey)
  403. {
  404. DWORD dwRet;
  405. HKEY hkSubKey;
  406. // Open the subkey so we can enumerate any children
  407. dwRet = RegOpenKeyEx(hkey, pszSubKey, 0, KEY_ALL_ACCESS, &hkSubKey);
  408. if (ERROR_SUCCESS == dwRet)
  409. {
  410. DWORD dwIndex;
  411. CHAR szSubKeyName[MAX_PATH + 1];
  412. DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName);
  413. CHAR szClass[MAX_PATH];
  414. DWORD cbClass = ARRAYSIZE(szClass);
  415. // I can't just call RegEnumKey with an ever-increasing index, because
  416. // I'm deleting the subkeys as I go, which alters the indices of the
  417. // remaining subkeys in an implementation-dependent way. In order to
  418. // be safe, I have to count backwards while deleting the subkeys.
  419. // Find out how many subkeys there are
  420. dwRet = RegQueryInfoKey(hkSubKey,
  421. szClass,
  422. &cbClass,
  423. NULL,
  424. &dwIndex, // The # of subkeys -- all we need
  425. NULL,
  426. NULL,
  427. NULL,
  428. NULL,
  429. NULL,
  430. NULL,
  431. NULL);
  432. if (NO_ERROR == dwRet)
  433. {
  434. // dwIndex is now the count of subkeys, but it needs to be
  435. // zero-based for RegEnumKey, so I'll pre-decrement, rather
  436. // than post-decrement.
  437. while (ERROR_SUCCESS == RegEnumKey(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName))
  438. {
  439. DeleteKeyRecursively(hkSubKey, szSubKeyName);
  440. }
  441. }
  442. RegCloseKey(hkSubKey);
  443. dwRet = RegDeleteKey(hkey, pszSubKey);
  444. }
  445. return dwRet;
  446. }
  447. void DeinstallLogonDialog(void)
  448. {
  449. RegDeleteKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\NPSTUB\\NetworkProvider");
  450. RegDeleteKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\NPSTUB");
  451. HKEY hkey;
  452. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
  453. 0, KEY_WRITE, &hkey) == ERROR_SUCCESS) {
  454. RegDeleteValue(hkey, "NPSTUB");
  455. RegCloseKey(hkey);
  456. }
  457. char szBuf[MAX_PATH];
  458. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon",
  459. 0, KEY_WRITE, &hkey) == ERROR_SUCCESS) {
  460. DWORD cbData = sizeof(szBuf);
  461. DWORD dwType;
  462. LONG err = RegQueryValueEx(hkey, "PrimaryProvider", NULL, &dwType,
  463. (LPBYTE)szBuf, &cbData);
  464. if (err == ERROR_SUCCESS && szBuf[0] != '\0') {
  465. NLS_STR nlsNPName(MAX_RES_STR_LEN);
  466. if (nlsNPName.LoadString(IDS_NP_NAME) == ERROR_SUCCESS) {
  467. if (!::strcmpf(nlsNPName.QueryPch(), szBuf)) {
  468. RegDeleteValue(hkey, "PrimaryProvider");
  469. }
  470. }
  471. }
  472. RegCloseKey(hkey);
  473. }
  474. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Enum\\Network\\FAMILY", 0,
  475. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WRITE,
  476. &hkey) == ERROR_SUCCESS) {
  477. UINT i=0;
  478. /* For each instance of us under the Enum branch, fetch the
  479. * corresponding key name under the other half of the database
  480. * and delete it.
  481. */
  482. for (;;) {
  483. DWORD err = RegEnumKey(hkey, i, szBuf, sizeof(szBuf));
  484. if (err != ERROR_SUCCESS)
  485. break;
  486. HKEY hkeyInstance;
  487. err = RegOpenKeyEx(hkey, szBuf,
  488. 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyInstance);
  489. if (err == ERROR_SUCCESS) {
  490. strcpyf(szBuf, "System\\CurrentControlSet\\Services\\Class\\");
  491. DWORD dwType;
  492. DWORD cbData = sizeof(szBuf) - 40; /* - length of above string */
  493. if (RegQueryValueEx(hkeyInstance, "Driver", NULL, &dwType,
  494. (LPBYTE)szBuf + 40, &cbData) == ERROR_SUCCESS) {
  495. /* szBuf now equals the other branch we need to kill */
  496. DeleteKeyRecursively(HKEY_LOCAL_MACHINE, szBuf);
  497. }
  498. RegCloseKey(hkeyInstance);
  499. }
  500. i++;
  501. }
  502. RegCloseKey(hkey);
  503. DeleteKeyRecursively(HKEY_LOCAL_MACHINE, "Enum\\Network\\FAMILY");
  504. }
  505. /* Now clean up bindings to our client, otherwise PNP will try to install
  506. * us as a new (unknown) device. This involves enumerating components
  507. * under HKLM\Enum\Network; for each one, enumerate the instances; for
  508. * each instance's Bindings key, enumerate the values, and delete all
  509. * values that begin with FAMILY\.
  510. */
  511. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Enum\\Network", 0,
  512. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WRITE,
  513. &hkey) == ERROR_SUCCESS) {
  514. UINT iComponent = 0;
  515. for (;;) {
  516. DWORD err = RegEnumKey(hkey, iComponent, szBuf, sizeof(szBuf));
  517. if (err != ERROR_SUCCESS)
  518. break;
  519. HKEY hkeyComponent;
  520. err = RegOpenKeyEx(hkey, szBuf,
  521. 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkeyComponent);
  522. if (err == ERROR_SUCCESS) {
  523. /* Opened a component's key. Enumerate its instances, opening
  524. * each one's Bindings subkey.
  525. */
  526. TCHAR szInstance[16]; /* actually only needs to be "nnnn\Bindings" plus null char */
  527. UINT iInstance = 0;
  528. for (;;) {
  529. err = RegEnumKey(hkeyComponent, iInstance, szInstance, sizeof(szInstance));
  530. if (err != ERROR_SUCCESS)
  531. break;
  532. if (strlenf(szInstance)*sizeof(TCHAR) <= sizeof(szInstance) - sizeof("\\Bindings"))
  533. strcatf(szInstance, "\\Bindings");
  534. HKEY hkeyInstance;
  535. err = RegOpenKeyEx(hkeyComponent, szInstance,
  536. 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyInstance);
  537. if (err == ERROR_SUCCESS) {
  538. /* Opened a Bindings subkey. For each value under this
  539. * key, the value name indicates the instance being
  540. * bound to, and the value data is empty. So we can
  541. * enum values, ignoring the value data and type and
  542. * just concentrating on the name.
  543. */
  544. TCHAR szValueName[64]; /* usually "COMPONENT\nnnn" */
  545. UINT iValue = 0;
  546. for (;;) {
  547. DWORD cchValue = ARRAYSIZE(szValueName);
  548. err = RegEnumValue(hkeyInstance, iValue, szValueName,
  549. &cchValue, NULL, NULL, NULL, NULL);
  550. if (err != ERROR_SUCCESS)
  551. break;
  552. /* If this is a binding to our client, delete the
  553. * binding and reset (deleting values while enuming
  554. * can be unpredictable).
  555. */
  556. if (!strnicmpf(szValueName, "FAMILY\\", 7)) {
  557. RegDeleteValue(hkeyInstance, szValueName);
  558. iValue = 0;
  559. continue;
  560. }
  561. iValue++;
  562. }
  563. RegCloseKey(hkeyInstance);
  564. }
  565. iInstance++;
  566. }
  567. RegCloseKey(hkeyComponent);
  568. }
  569. iComponent++;
  570. }
  571. RegCloseKey(hkey);
  572. }
  573. }