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.

766 lines
20 KiB

  1. //
  2. // Binding.cpp
  3. //
  4. // Shared code for enumerating and modifying network bindings, used for
  5. // protocols, clients, and services.
  6. //
  7. // History:
  8. //
  9. // 2/02/1999 KenSh Created for JetNet
  10. // 9/29/1999 KenSh Repurposed for Home Networking Wizard
  11. //
  12. #include "stdafx.h"
  13. #include "NetConn.h"
  14. #include "nconnwrap.h"
  15. #include "TheApp.h"
  16. // Given a string such as "MSTCP\0000" or "Network\MSTCP\0000", returns a
  17. // string such as "Enum\Network\MSTCP\0000".
  18. //
  19. // Input string will copied without modification if it starts with "Enum\".
  20. //
  21. void WINAPI FullEnumKeyFromBinding(LPCSTR pszBinding, LPSTR pszBuf, int cchBuf)
  22. {
  23. LPCSTR pszStatic = "";
  24. int cchStatic = 0;
  25. int cSlashes = CountChars(pszBinding, '\\');
  26. if (cSlashes == 1)
  27. {
  28. pszStatic = "Enum\\Network\\";
  29. cchStatic = _countof("Enum\\Network\\") - 1;
  30. }
  31. else if (cSlashes == 2)
  32. {
  33. pszStatic = "Enum\\";
  34. cchStatic = _countof("Enum\\") - 1;
  35. }
  36. int cchBinding = lstrlen(pszBinding);
  37. if (cchBuf < cchBinding + cchStatic + 1)
  38. {
  39. *pszBuf = '\0';
  40. }
  41. else
  42. {
  43. lstrcpy(pszBuf, pszStatic);
  44. lstrcpy(pszBuf + cchStatic, pszBinding);
  45. }
  46. }
  47. // Given a full or partial enum key, allocates and returns an array of string
  48. // pointers, one pointer for each binding.
  49. //
  50. // Examples of valid input:
  51. // "MSTCP\0000"
  52. // "Network\MSTCP\0000"
  53. // "Enum\Network\MSTCP\0000"
  54. // "Enum\PCI\VEN_10B7&DEV_9050&SUBSYS_00000000&REV_00\407000"
  55. //
  56. // Each output string is in the short format ("MSTCP\0000").
  57. //
  58. // pprgBindings may be NULL, in which case only the count is returned.
  59. //
  60. int WINAPI EnumNetBindings(LPCSTR pszParentBinding, LPSTR** pprgBindings)
  61. {
  62. TCHAR szFullParent[200];
  63. FullEnumKeyFromBinding(pszParentBinding, szFullParent, _countof(szFullParent));
  64. CRegistry reg;
  65. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szFullParent, KEY_READ))
  66. {
  67. if (reg.OpenSubKey("Bindings", KEY_READ))
  68. {
  69. DWORD cBindings;
  70. DWORD cbMaxValueNameLen;
  71. if (ERROR_SUCCESS == RegQueryInfoKey(reg.m_hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cBindings, &cbMaxValueNameLen, NULL, NULL, NULL))
  72. {
  73. if (pprgBindings == NULL)
  74. {
  75. return (int)cBindings;
  76. }
  77. else
  78. {
  79. int cEnum = 0;
  80. LPTSTR* prgBindings = (LPTSTR*)NetConnAlloc(cBindings * (cbMaxValueNameLen + 1 + sizeof(LPTSTR)));
  81. LPTSTR pch = (LPTSTR)(prgBindings + cBindings);
  82. for (DWORD iBinding = 0; iBinding < cBindings; iBinding++)
  83. {
  84. DWORD cchValueName = cbMaxValueNameLen+1;
  85. prgBindings[iBinding] = pch;
  86. if (ERROR_SUCCESS == RegEnumValue(reg.m_hKey, iBinding, pch, &cchValueName, NULL, NULL, NULL, NULL))
  87. {
  88. pch += (cchValueName + 1);
  89. cEnum += 1;
  90. }
  91. }
  92. *pprgBindings = prgBindings;
  93. return cEnum;
  94. }
  95. }
  96. }
  97. }
  98. if (pprgBindings != NULL)
  99. {
  100. *pprgBindings = NULL;
  101. }
  102. return 0;
  103. }
  104. // Same as EnumNetBindings, except it filters out bindings that don't
  105. // match the given device ID (e.g. "MSTCP").
  106. // pprgBindings may be NULL, in which case only the count is returned.
  107. int WINAPI EnumMatchingNetBindings(LPCSTR pszParentBinding, LPCSTR pszDeviceID, LPSTR** pprgBindings)
  108. {
  109. LPSTR* prgBindings;
  110. int cBindings = EnumNetBindings(pszParentBinding, &prgBindings);
  111. for (int iBinding = 0; iBinding < cBindings; iBinding++)
  112. {
  113. if (!DoesBindingMatchDeviceID(prgBindings[iBinding], pszDeviceID))
  114. {
  115. for (int iBinding2 = iBinding+1; iBinding2 < cBindings; iBinding2++)
  116. {
  117. prgBindings[iBinding2-1] = prgBindings[iBinding2];
  118. }
  119. cBindings--;
  120. iBinding--;
  121. }
  122. }
  123. if (cBindings == 0 || pprgBindings == NULL)
  124. {
  125. NetConnFree(prgBindings);
  126. prgBindings = NULL;
  127. }
  128. if (pprgBindings != NULL)
  129. {
  130. *pprgBindings = prgBindings;
  131. }
  132. return cBindings;
  133. }
  134. // RemoveBinding
  135. //
  136. // Removes a specific instance of a protocol, client, or service from the registry.
  137. // Any cascading dependencies are removed as well.
  138. //
  139. // pszNetEnumKey - partial Enum key of the binding to be removed, e.g. "MSTCP\0000"
  140. // or "VSERVER\0000". Assumed to live under HKLM\Enum\Network.
  141. //
  142. // History:
  143. //
  144. // 3/25/1999 KenSh Created
  145. //
  146. VOID RemoveBinding(LPCSTR pszBinding)
  147. {
  148. CHAR szRegKey[MAX_PATH];
  149. lstrcpy(szRegKey, "Enum\\Network\\");
  150. lstrcat(szRegKey, pszBinding);
  151. int cchMainEnumKey = lstrlen(szRegKey);
  152. lstrcat(szRegKey, "\\Bindings");
  153. // Enumerate and delete all binding keys referred to by current binding key
  154. CRegistry reg;
  155. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS)) // e.g. "Enum\Network\MSTCP\0000\Bindings"
  156. {
  157. for (;;) // Loop until we've deleted all the subkeys
  158. {
  159. CHAR szValueName[60];
  160. DWORD cbValueName = _countof(szValueName);
  161. if (ERROR_SUCCESS != RegEnumValue(reg.m_hKey, 0, szValueName, &cbValueName, NULL, NULL, NULL, NULL))
  162. break;
  163. // Remove the client or service
  164. RemoveBindingFromParent(reg.m_hKey, szValueName);
  165. }
  166. }
  167. // Open the main node, and get values we'll need later
  168. TCHAR szMasterCopy[60];
  169. CHAR szClassKey[40];
  170. szMasterCopy[0] = '\0';
  171. szRegKey[cchMainEnumKey] = '\0';
  172. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ)) // e.g. "Enum\Network\MSTCP\0000"
  173. return; // it's already been deleted
  174. reg.QueryStringValue("MasterCopy", szMasterCopy, _countof(szMasterCopy));
  175. reg.QueryStringValue("Driver", szClassKey, _countof(szClassKey)); // e.g. "NetClient\0000"
  176. // Remove this binding's node from the registry (and its sub-keys)
  177. LPSTR pchSubKey = FindFileTitle(szRegKey);
  178. *(pchSubKey-1) = '\0';
  179. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS)) // e.g. "Enum\Network\MSTCP"
  180. {
  181. // Main purpose of this function: delete the requested binding key
  182. RegDeleteKeyAndSubKeys(reg.m_hKey, pchSubKey);
  183. // Was this a "MasterCopy" binding?
  184. static const int cchEnumNet = _countof("Enum\\Network\\") - 1;
  185. BOOL bMasterCopy = (0 == lstrcmpi(szMasterCopy + cchEnumNet, pszBinding));
  186. // Check for siblings which might be referencing the same class key
  187. BOOL bClassKeyReferenced = FALSE;
  188. CHAR szAlternateMaster[60];
  189. szAlternateMaster[0] = '\0';
  190. for (DWORD iSibling = 0; ; iSibling++)
  191. {
  192. CHAR szSiblingKey[60];
  193. DWORD cbSiblingKey = _countof(szSiblingKey);
  194. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iSibling, szSiblingKey, &cbSiblingKey, NULL, NULL, NULL, NULL))
  195. break;
  196. CRegistry regSibling;
  197. if (regSibling.OpenKey(reg.m_hKey, szSiblingKey, KEY_ALL_ACCESS))
  198. {
  199. CHAR szSiblingDriver[60];
  200. if (regSibling.QueryStringValue("Driver", szSiblingDriver, _countof(szSiblingDriver)))
  201. {
  202. if (0 == lstrcmpi(szSiblingDriver, szClassKey))
  203. {
  204. bClassKeyReferenced = TRUE;
  205. if (!bMasterCopy)
  206. break;
  207. // Check if this sib's mastercopy points to the key being deleted
  208. if (bMasterCopy)
  209. {
  210. CHAR szSibMaster[60];
  211. if (regSibling.QueryStringValue("MasterCopy", szSibMaster, _countof(szSibMaster))
  212. && !lstrcmpi(szSibMaster, szMasterCopy))
  213. {
  214. if (szAlternateMaster[0] == '\0') // first match, make it the new master
  215. {
  216. wsprintf(szAlternateMaster, "%s\\%s", szRegKey, szSiblingKey);
  217. }
  218. regSibling.SetStringValue("MasterCopy", szAlternateMaster);
  219. }
  220. }
  221. }
  222. }
  223. }
  224. }
  225. if (!bClassKeyReferenced)
  226. {
  227. // No more references to the class key, so delete it
  228. lstrcpy(szRegKey, "System\\CurrentControlSet\\Services\\Class\\");
  229. lstrcat(szRegKey, szClassKey);
  230. pchSubKey = FindFileTitle(szRegKey);
  231. *(pchSubKey-1) = '\0';
  232. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS))
  233. {
  234. RegDeleteKeyAndSubKeys(reg.m_hKey, pchSubKey);
  235. }
  236. }
  237. }
  238. }
  239. // RemoveBindingFromParent
  240. //
  241. // Given an open Bindings key, and a string representing one of the bindings
  242. // listed in it, this function deletes the value, then calls RemoveBinding()
  243. // to delete the binding and all of its cascading dependencies.
  244. //
  245. // History:
  246. //
  247. // 3/25/1999 KenSh Created
  248. // 4/30/1999 KenSh Got rid of unnecessary code to delete empty parent
  249. //
  250. VOID RemoveBindingFromParent(HKEY hkeyParentBindingsKey, LPCSTR pszBinding)
  251. {
  252. // Delete the binding from the Bindings key of the person bound to us
  253. VERIFY(ERROR_SUCCESS == RegDeleteValue(hkeyParentBindingsKey, pszBinding));
  254. RemoveBinding(pszBinding);
  255. }
  256. // pszClassKey is of the form "NetService\0000"
  257. BOOL WINAPI DoesClassKeyExist(LPCSTR pszClassKey)
  258. {
  259. CRegistry reg;
  260. if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class"))
  261. {
  262. if (reg.OpenSubKey(pszClassKey))
  263. {
  264. // REVIEW: could check for presence of certain entries
  265. return TRUE;
  266. }
  267. }
  268. return FALSE;
  269. }
  270. // pszClass = "NetService"
  271. // pszDevice = "VSERVER"
  272. // pszEnumSubKey = "0000"
  273. BOOL WINAPI IsValidNetEnumKey(LPCSTR pszClass, LPCSTR pszDevice, LPCSTR pszEnumSubKey)
  274. {
  275. CRegistry reg;
  276. TCHAR szRegKey[260];
  277. wsprintf(szRegKey, "Enum\\Network\\%s\\%s", pszDevice, pszEnumSubKey);
  278. BOOL bResult = FALSE;
  279. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ))
  280. goto done;
  281. TCHAR szBuf[100];
  282. // Check a few values
  283. if (!reg.QueryStringValue("Class", szBuf, _countof(szBuf)))
  284. goto done;
  285. if (0 != lstrcmpi(szBuf, pszClass))
  286. goto done;
  287. if (!reg.QueryStringValue("Driver", szBuf, _countof(szBuf)))
  288. goto done;
  289. if (!DoesClassKeyExist(szBuf))
  290. goto done;
  291. bResult = TRUE;
  292. done:
  293. return bResult;
  294. }
  295. // pszClass is of the form "NetService"
  296. // pszDevice is of the form "VSERVER"
  297. // pszBuf may be NULL if you don't need a copy of the string
  298. BOOL WINAPI FindValidNetEnumKey(LPCSTR pszClass, LPCSTR pszDevice, LPSTR pszBuf, int cchBuf)
  299. {
  300. CRegistry reg;
  301. TCHAR szRegKey[200];
  302. wsprintf(szRegKey, "Enum\\Network\\%s", pszDevice);
  303. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ))
  304. {
  305. DWORD dwIndex;
  306. TCHAR szSubKey[50];
  307. for (dwIndex = 0; ; dwIndex++)
  308. {
  309. DWORD cchSubKey = _countof(szSubKey);
  310. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  311. break;
  312. if (!IsValidNetEnumKey(pszClass, pszDevice, szSubKey))
  313. continue;
  314. // Found a valid entry; copy it to pszBuf and return TRUE
  315. //
  316. if (pszBuf != NULL)
  317. {
  318. ASSERT(cchBuf > lstrlen(szRegKey) + lstrlen(szSubKey) + 1);
  319. wsprintf(pszBuf, "%s\\%s", szRegKey, szSubKey);
  320. }
  321. return TRUE;
  322. }
  323. }
  324. return FALSE;
  325. }
  326. // pszClass = "NetService", etc.
  327. // pszDeviceID = "VSERVER", etc.
  328. // returns TRUE if anything was removed
  329. BOOL WINAPI RemoveBrokenNetItems(LPCSTR pszClass, LPCSTR pszDeviceID)
  330. {
  331. CRegistry reg;
  332. TCHAR szRegKey[200];
  333. BOOL bResult = FALSE;
  334. delete_enum_keys:
  335. //
  336. // Find and remove any broken Enum keys
  337. //
  338. wsprintf(szRegKey, "Enum\\Network\\%s", pszDeviceID);
  339. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey))
  340. {
  341. TCHAR szSubKey[50];
  342. DWORD dwIndex = 0;
  343. for (;;)
  344. {
  345. DWORD cchSubKey = _countof(szSubKey);
  346. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  347. break;
  348. if (!IsValidNetEnumKey(pszClass, pszDeviceID, szSubKey))
  349. {
  350. // Delete the key
  351. // REVIEW: should delete all references to the key
  352. RegDeleteKeyAndSubKeys(reg.m_hKey, szSubKey);
  353. bResult = TRUE;
  354. // Restart the search to ensure we find all broken items
  355. dwIndex = 0;
  356. continue;
  357. }
  358. dwIndex++;
  359. }
  360. }
  361. //
  362. // Find and remove any unreferenced Class keys
  363. //
  364. wsprintf(szRegKey, "System\\CurrentControlSet\\Services\\Class\\%s", pszClass);
  365. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey))
  366. {
  367. TCHAR szSubKey[50];
  368. int cClassKeysRemoved = 0;
  369. DWORD dwIndex = 0;
  370. for (;;)
  371. {
  372. DWORD cchSubKey = _countof(szSubKey);
  373. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  374. break;
  375. wsprintf(szRegKey, "%s\\%s", pszClass, szSubKey);
  376. if (!IsNetClassKeyReferenced(szRegKey))
  377. {
  378. // Delete the key
  379. RegDeleteKeyAndSubKeys(reg.m_hKey, szSubKey);
  380. bResult = TRUE;
  381. cClassKeysRemoved++;
  382. // Restart the search to ensure we find all broken items
  383. dwIndex = 0;
  384. continue;
  385. }
  386. dwIndex++;
  387. }
  388. // If we removed any class keys, check the Enum keys again
  389. if (cClassKeysRemoved != 0)
  390. goto delete_enum_keys;
  391. }
  392. return bResult;
  393. }
  394. BOOL GetDeviceInterfaceList(LPCSTR pszClass, LPCSTR pszDeviceID, LPCSTR pszInterfaceType, LPSTR pszBuf, int cchBuf)
  395. {
  396. CRegistry regClassRoot;
  397. CHAR szRegClassRoot[260];
  398. lstrcpy(szRegClassRoot, "System\\CurrentControlSet\\Services\\Class\\");
  399. lstrcat(szRegClassRoot, pszClass);
  400. if (regClassRoot.OpenKey(HKEY_LOCAL_MACHINE, szRegClassRoot, KEY_READ))
  401. {
  402. for (DWORD iAdapter = 0; ; iAdapter++)
  403. {
  404. CHAR szSubKey[15];
  405. DWORD cchSubKey = _countof(szSubKey) - 4; // -4 to allow "\\Ndi"
  406. if (ERROR_SUCCESS != RegEnumKeyEx(regClassRoot.m_hKey, iAdapter, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  407. break;
  408. CRegistry regNdi;
  409. lstrcat(szSubKey, "\\Ndi");
  410. if (regNdi.OpenKey(regClassRoot.m_hKey, szSubKey, KEY_READ))
  411. {
  412. CHAR szCurDeviceID[200];
  413. if (regNdi.QueryStringValue("DeviceID", szCurDeviceID, _countof(szCurDeviceID)) &&
  414. 0 == lstrcmpi(szCurDeviceID, pszDeviceID))
  415. {
  416. BOOL bResult = FALSE;
  417. if (regNdi.OpenSubKey("Interfaces", KEY_READ))
  418. {
  419. bResult = regNdi.QueryStringValue(pszInterfaceType, pszBuf, cchBuf);
  420. }
  421. return bResult;
  422. }
  423. }
  424. }
  425. }
  426. return FALSE;
  427. }
  428. BOOL CheckMatchingInterface(LPCSTR pszList1, LPCSTR pszList2)
  429. {
  430. CHAR szInterface1[40];
  431. CHAR szInterface2[40];
  432. while (GetFirstToken(pszList1, ',', szInterface1, _countof(szInterface1)))
  433. {
  434. LPCSTR pszTemp2 = pszList2;
  435. while (GetFirstToken(pszTemp2, ',', szInterface2, _countof(szInterface2)))
  436. {
  437. if (0 == lstrcmpi(szInterface1, szInterface2))
  438. return TRUE;
  439. }
  440. }
  441. return FALSE;
  442. }
  443. BOOL GetDeviceLowerRange(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
  444. {
  445. return GetDeviceInterfaceList(pszClass, pszDeviceID, "LowerRange", pszBuf, cchBuf);
  446. }
  447. BOOL GetDeviceUpperRange(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
  448. {
  449. return GetDeviceInterfaceList(pszClass, pszDeviceID, "UpperRange", pszBuf, cchBuf);
  450. }
  451. // class is "Net", "NetTrans", "NetClient", or "NetService"
  452. HRESULT OpenNetClassKey(CRegistry& reg, LPCSTR pszClass, LPCSTR pszSubKey, REGSAM dwAccess)
  453. {
  454. ASSERT(pszClass != NULL);
  455. CHAR szRegKey[MAX_PATH];
  456. lstrcpy(szRegKey, "System\\CurrentControlSet\\Services\\Class\\");
  457. lstrcat(szRegKey, pszClass);
  458. if (pszSubKey != NULL)
  459. {
  460. lstrcat(szRegKey, "\\");
  461. lstrcat(szRegKey, pszSubKey);
  462. }
  463. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, dwAccess))
  464. return NETCONN_UNKNOWN_ERROR;
  465. return NETCONN_SUCCESS;
  466. }
  467. VOID FindUnusedDeviceIdNumber(CRegistry& reg, LPSTR pszBuf, int cchBuf)
  468. {
  469. for (DWORD dwDeviceNumber = 0; ; dwDeviceNumber++)
  470. {
  471. CRegistry regTemp;
  472. wsprintf(pszBuf, "%04lu", dwDeviceNumber);
  473. if (!regTemp.OpenKey(reg.m_hKey, pszBuf, KEY_READ))
  474. break;
  475. }
  476. }
  477. // Given a network device ID, such as "MSTCP", creates a new instance
  478. // of it by copying an existing instance.
  479. // pszClass = "NetTrans"
  480. // pszDeviceID = "MSTCP"
  481. // pszBuf is filled with the new device binding ID, e.g. "MSTCP\0000"
  482. HRESULT FindAndCloneNetEnumKey(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
  483. {
  484. CRegistry reg;
  485. TCHAR szExistingEnumKey[260];
  486. if (!FindValidNetEnumKey(pszClass, pszDeviceID, szExistingEnumKey, _countof(szExistingEnumKey)))
  487. {
  488. ASSERT(FALSE);
  489. return NETCONN_UNKNOWN_ERROR; // the device is not installed properly!
  490. }
  491. TCHAR szRegKey[200];
  492. wsprintf(szRegKey, "Enum\\Network\\%s", pszDeviceID);
  493. if (!reg.CreateKey(HKEY_LOCAL_MACHINE, szRegKey))
  494. {
  495. ASSERT(FALSE);
  496. return NETCONN_UNKNOWN_ERROR;
  497. }
  498. // Find the next unused device ID number
  499. TCHAR szNewNumber[10];
  500. FindUnusedDeviceIdNumber(reg, szNewNumber, _countof(szNewNumber));
  501. // Make a copy of the key (recursive)
  502. LPCTSTR pszExistingNumber = FindFileTitle(szExistingEnumKey);
  503. if (!reg.CloneSubKey(pszExistingNumber, szNewNumber, TRUE))
  504. {
  505. ASSERT(FALSE);
  506. return NETCONN_UNKNOWN_ERROR;
  507. }
  508. wsprintf(pszBuf, "%s\\%s", pszDeviceID, szNewNumber);
  509. return NETCONN_SUCCESS;
  510. }
  511. // existing driver is of the form "NetTrans\0000"
  512. // new driver will be of the form "NetTrans\0001"
  513. HRESULT CloneNetClassKey(LPCSTR pszExistingDriver, LPSTR pszNewDriverBuf, int cchNewDriverBuf)
  514. {
  515. HRESULT hr;
  516. LPSTR pchSlash = strchr(pszExistingDriver, '\\');
  517. if (pchSlash == NULL)
  518. {
  519. ASSERT(FALSE);
  520. return NETCONN_UNKNOWN_ERROR;
  521. }
  522. // Extract just the class portion of the driver name, e.g. "NetTrans"
  523. CHAR szClass[30];
  524. int cchClass = (int)(pchSlash - pszExistingDriver);
  525. ASSERT(cchClass < _countof(szClass));
  526. lstrcpyn(szClass, pszExistingDriver, cchClass+1);
  527. CRegistry regClassKey;
  528. if (FAILED(hr = OpenNetClassKey(regClassKey, szClass, NULL, KEY_ALL_ACCESS)))
  529. return hr;
  530. // Find the next unused driver number
  531. CHAR szDriverNumber[5];
  532. FindUnusedDeviceIdNumber(regClassKey, szDriverNumber, _countof(szDriverNumber));
  533. // Make a copy of the key (recursive)
  534. if (!regClassKey.CloneSubKey(pchSlash+1, szDriverNumber, TRUE))
  535. {
  536. ASSERT(FALSE);
  537. return NETCONN_UNKNOWN_ERROR;
  538. }
  539. wsprintf(pszNewDriverBuf, "%s\\%s", szClass, szDriverNumber);
  540. // Remove the "default" subkey if we just copied it (can't have 2 defaults)
  541. if (regClassKey.OpenSubKey(szDriverNumber))
  542. {
  543. if (regClassKey.OpenSubKey("Ndi"))
  544. {
  545. RegDeleteKey(regClassKey.m_hKey, "Default");
  546. }
  547. }
  548. return NETCONN_SUCCESS;
  549. }
  550. // pszSubKey == "MSTCP", "VREDIR", "MSTCP\0000", etc.
  551. HRESULT OpenNetEnumKey(CRegistry& reg, LPCSTR pszSubKey, REGSAM dwAccess)
  552. {
  553. CHAR szRegKey[MAX_PATH];
  554. lstrcpy(szRegKey, "Enum\\Network\\");
  555. lstrcat(szRegKey, pszSubKey);
  556. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, dwAccess))
  557. return NETCONN_UNKNOWN_ERROR;
  558. return NETCONN_SUCCESS;
  559. }
  560. // pszClass = "NetClient"
  561. // pszDeviceID = "NWREDIR"
  562. HRESULT DeleteClassKeyReferences(LPCSTR pszClass, LPCSTR pszDeviceID)
  563. {
  564. HRESULT hr = NETCONN_SUCCESS;
  565. // Delete the class key(s)
  566. CRegistry reg;
  567. if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class") &&
  568. reg.OpenSubKey(pszClass))
  569. {
  570. TCHAR szNumber[20];
  571. DWORD iClassItem = 0;
  572. for (;;)
  573. {
  574. DWORD cchNumber = _countof(szNumber);
  575. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iClassItem, szNumber, &cchNumber, NULL, NULL, NULL, NULL))
  576. break;
  577. CRegistry regNumber;
  578. if (regNumber.OpenKey(reg.m_hKey, szNumber))
  579. {
  580. CRegistry regNdi;
  581. if (regNdi.OpenKey(regNumber.m_hKey, "Ndi"))
  582. {
  583. TCHAR szDeviceID[50];
  584. if (regNdi.QueryStringValue("DeviceID", szDeviceID, _countof(szDeviceID)) &&
  585. !lstrcmpi(szDeviceID, pszDeviceID))
  586. {
  587. regNdi.CloseKey();
  588. regNumber.CloseKey();
  589. RegDeleteKeyAndSubKeys(reg.m_hKey, szNumber);
  590. hr = NETCONN_NEED_RESTART;
  591. // Restart the search
  592. iClassItem = 0;
  593. continue;
  594. }
  595. }
  596. }
  597. iClassItem++;
  598. }
  599. }
  600. return hr;
  601. }
  602. // pszClassKey is of the form "NetService\0000"
  603. BOOL IsNetClassKeyReferenced(LPCSTR pszClassKey)
  604. {
  605. CRegistry reg;
  606. CHAR szDeviceID[200];
  607. DWORD iKey;
  608. // Get the device ID
  609. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class", KEY_READ))
  610. goto done;
  611. if (!reg.OpenSubKey(pszClassKey, KEY_READ))
  612. goto done;
  613. if (!reg.OpenSubKey("Ndi", KEY_READ))
  614. goto done;
  615. if (!reg.QueryStringValue("DeviceID", szDeviceID, _countof(szDeviceID)))
  616. goto done;
  617. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, "Enum\\Network", KEY_READ))
  618. goto done;
  619. if (!reg.OpenSubKey(szDeviceID, KEY_READ))
  620. goto done;
  621. for (iKey = 0; ; iKey++)
  622. {
  623. CHAR szSubKey[60];
  624. DWORD cbSubKey = _countof(szSubKey);
  625. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iKey, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL))
  626. break;
  627. CRegistry regSubKey;
  628. if (regSubKey.OpenKey(reg.m_hKey, szSubKey, KEY_READ))
  629. {
  630. CHAR szDriver[60];
  631. if (regSubKey.QueryStringValue("Driver", szDriver, _countof(szDriver)))
  632. {
  633. if (0 == lstrcmpi(szDriver, pszClassKey))
  634. return TRUE;
  635. }
  636. }
  637. }
  638. done:
  639. return FALSE;
  640. }
  641. // Given a binding of one of the two following forms
  642. // "MSTCP\0000"
  643. // "Enum\Network\MSTCP\0000"
  644. // and a device ID such as "MSTCP", returns TRUE if the binding is a binding
  645. // of the given device, or FALSE if not.
  646. BOOL WINAPI DoesBindingMatchDeviceID(LPCSTR pszBinding, LPCSTR pszDeviceID)
  647. {
  648. CHAR szTemp[40];
  649. LPCSTR pszBoundDevice = FindPartialPath(pszBinding, 1); // skip "Enum\..." if present
  650. lstrcpyn(szTemp, pszBoundDevice, _countof(szTemp));
  651. LPSTR pchSlash = strchr(szTemp, '\\');
  652. if (pchSlash != NULL)
  653. *pchSlash = '\0';
  654. return !lstrcmpi(szTemp, pszDeviceID);
  655. }