Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

794 lines
22 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. ASSERT(pszBinding != NULL);
  149. CHAR szRegKey[MAX_PATH];
  150. static const CHAR szEnumString[] = "Enum\\Network\\";
  151. static const CHAR szBindingsString[] = "\\Bindings";
  152. int cRemaining = sizeof(szRegKey) - (sizeof(szEnumString) + sizeof(szBindingsString));
  153. if (lstrlen(pszBinding) >= cRemaining)
  154. return; // Bail out
  155. lstrcpy(szRegKey, szEnumString);
  156. lstrcat(szRegKey, pszBinding);
  157. int cchMainEnumKey = lstrlen(szRegKey);
  158. lstrcat(szRegKey, szBindingsString);
  159. // Enumerate and delete all binding keys referred to by current binding key
  160. CRegistry reg;
  161. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS)) // e.g. "Enum\Network\MSTCP\0000\Bindings"
  162. {
  163. for (;;) // Loop until we've deleted all the subkeys
  164. {
  165. CHAR szValueName[60];
  166. DWORD cbValueName = _countof(szValueName);
  167. if (ERROR_SUCCESS != RegEnumValue(reg.m_hKey, 0, szValueName, &cbValueName, NULL, NULL, NULL, NULL))
  168. break;
  169. // Remove the client or service
  170. RemoveBindingFromParent(reg.m_hKey, szValueName);
  171. }
  172. }
  173. // Open the main node, and get values we'll need later
  174. TCHAR szMasterCopy[60];
  175. CHAR szClassKey[40];
  176. szMasterCopy[0] = '\0';
  177. szRegKey[cchMainEnumKey] = '\0';
  178. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ)) // e.g. "Enum\Network\MSTCP\0000"
  179. return; // it's already been deleted
  180. reg.QueryStringValue("MasterCopy", szMasterCopy, _countof(szMasterCopy));
  181. reg.QueryStringValue("Driver", szClassKey, _countof(szClassKey)); // e.g. "NetClient\0000"
  182. // Remove this binding's node from the registry (and its sub-keys)
  183. LPSTR pchSubKey = FindFileTitle(szRegKey);
  184. *(pchSubKey-1) = '\0';
  185. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS)) // e.g. "Enum\Network\MSTCP"
  186. {
  187. // Main purpose of this function: delete the requested binding key
  188. RegDeleteKeyAndSubKeys(reg.m_hKey, pchSubKey);
  189. // Was this a "MasterCopy" binding?
  190. static const int cchEnumNet = _countof("Enum\\Network\\") - 1;
  191. BOOL bMasterCopy = (0 == lstrcmpi(szMasterCopy + cchEnumNet, pszBinding));
  192. // Check for siblings which might be referencing the same class key
  193. BOOL bClassKeyReferenced = FALSE;
  194. CHAR szAlternateMaster[60];
  195. szAlternateMaster[0] = '\0';
  196. for (DWORD iSibling = 0; ; iSibling++)
  197. {
  198. CHAR szSiblingKey[60];
  199. DWORD cbSiblingKey = _countof(szSiblingKey);
  200. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iSibling, szSiblingKey, &cbSiblingKey, NULL, NULL, NULL, NULL))
  201. break;
  202. CRegistry regSibling;
  203. if (regSibling.OpenKey(reg.m_hKey, szSiblingKey, KEY_ALL_ACCESS))
  204. {
  205. CHAR szSiblingDriver[60];
  206. if (regSibling.QueryStringValue("Driver", szSiblingDriver, _countof(szSiblingDriver)))
  207. {
  208. if (0 == lstrcmpi(szSiblingDriver, szClassKey))
  209. {
  210. bClassKeyReferenced = TRUE;
  211. if (!bMasterCopy)
  212. break;
  213. // Check if this sib's mastercopy points to the key being deleted
  214. if (bMasterCopy)
  215. {
  216. CHAR szSibMaster[60];
  217. if (regSibling.QueryStringValue("MasterCopy", szSibMaster, _countof(szSibMaster))
  218. && !lstrcmpi(szSibMaster, szMasterCopy))
  219. {
  220. if (szAlternateMaster[0] == '\0') // first match, make it the new master
  221. {
  222. wsprintf(szAlternateMaster, "%s\\%s", szRegKey, szSiblingKey);
  223. }
  224. regSibling.SetStringValue("MasterCopy", szAlternateMaster);
  225. }
  226. }
  227. }
  228. }
  229. }
  230. }
  231. if (!bClassKeyReferenced)
  232. {
  233. // No more references to the class key, so delete it
  234. lstrcpy(szRegKey, "System\\CurrentControlSet\\Services\\Class\\");
  235. lstrcat(szRegKey, szClassKey);
  236. pchSubKey = FindFileTitle(szRegKey);
  237. *(pchSubKey-1) = '\0';
  238. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS))
  239. {
  240. RegDeleteKeyAndSubKeys(reg.m_hKey, pchSubKey);
  241. }
  242. }
  243. }
  244. }
  245. // RemoveBindingFromParent
  246. //
  247. // Given an open Bindings key, and a string representing one of the bindings
  248. // listed in it, this function deletes the value, then calls RemoveBinding()
  249. // to delete the binding and all of its cascading dependencies.
  250. //
  251. // History:
  252. //
  253. // 3/25/1999 KenSh Created
  254. // 4/30/1999 KenSh Got rid of unnecessary code to delete empty parent
  255. //
  256. VOID RemoveBindingFromParent(HKEY hkeyParentBindingsKey, LPCSTR pszBinding)
  257. {
  258. // Delete the binding from the Bindings key of the person bound to us
  259. VERIFY(ERROR_SUCCESS == RegDeleteValue(hkeyParentBindingsKey, pszBinding));
  260. RemoveBinding(pszBinding);
  261. }
  262. // pszClassKey is of the form "NetService\0000"
  263. BOOL WINAPI DoesClassKeyExist(LPCSTR pszClassKey)
  264. {
  265. CRegistry reg;
  266. if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class"))
  267. {
  268. if (reg.OpenSubKey(pszClassKey))
  269. {
  270. // REVIEW: could check for presence of certain entries
  271. return TRUE;
  272. }
  273. }
  274. return FALSE;
  275. }
  276. // pszClass = "NetService"
  277. // pszDevice = "VSERVER"
  278. // pszEnumSubKey = "0000"
  279. BOOL WINAPI IsValidNetEnumKey(LPCSTR pszClass, LPCSTR pszDevice, LPCSTR pszEnumSubKey)
  280. {
  281. CRegistry reg;
  282. TCHAR szRegKey[260];
  283. wsprintf(szRegKey, "Enum\\Network\\%s\\%s", pszDevice, pszEnumSubKey);
  284. BOOL bResult = FALSE;
  285. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ))
  286. goto done;
  287. TCHAR szBuf[100];
  288. // Check a few values
  289. if (!reg.QueryStringValue("Class", szBuf, _countof(szBuf)))
  290. goto done;
  291. if (0 != lstrcmpi(szBuf, pszClass))
  292. goto done;
  293. if (!reg.QueryStringValue("Driver", szBuf, _countof(szBuf)))
  294. goto done;
  295. if (!DoesClassKeyExist(szBuf))
  296. goto done;
  297. bResult = TRUE;
  298. done:
  299. return bResult;
  300. }
  301. // pszClass is of the form "NetService"
  302. // pszDevice is of the form "VSERVER"
  303. // pszBuf may be NULL if you don't need a copy of the string
  304. BOOL WINAPI FindValidNetEnumKey(LPCSTR pszClass, LPCSTR pszDevice, LPSTR pszBuf, int cchBuf)
  305. {
  306. CRegistry reg;
  307. TCHAR szRegKey[200];
  308. wsprintf(szRegKey, "Enum\\Network\\%s", pszDevice);
  309. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ))
  310. {
  311. DWORD dwIndex;
  312. TCHAR szSubKey[50];
  313. for (dwIndex = 0; ; dwIndex++)
  314. {
  315. DWORD cchSubKey = _countof(szSubKey);
  316. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  317. break;
  318. if (!IsValidNetEnumKey(pszClass, pszDevice, szSubKey))
  319. continue;
  320. // Found a valid entry; copy it to pszBuf and return TRUE
  321. //
  322. if (pszBuf != NULL)
  323. {
  324. ASSERT(cchBuf > lstrlen(szRegKey) + lstrlen(szSubKey) + 1);
  325. wsprintf(pszBuf, "%s\\%s", szRegKey, szSubKey);
  326. }
  327. return TRUE;
  328. }
  329. }
  330. return FALSE;
  331. }
  332. // pszClass = "NetService", etc.
  333. // pszDeviceID = "VSERVER", etc.
  334. // returns TRUE if anything was removed
  335. BOOL WINAPI RemoveBrokenNetItems(LPCSTR pszClass, LPCSTR pszDeviceID)
  336. {
  337. CRegistry reg;
  338. TCHAR szRegKey[200];
  339. BOOL bResult = FALSE;
  340. delete_enum_keys:
  341. //
  342. // Find and remove any broken Enum keys
  343. //
  344. wsprintf(szRegKey, "Enum\\Network\\%s", pszDeviceID);
  345. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey))
  346. {
  347. TCHAR szSubKey[50];
  348. DWORD dwIndex = 0;
  349. for (;;)
  350. {
  351. DWORD cchSubKey = _countof(szSubKey);
  352. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  353. break;
  354. if (!IsValidNetEnumKey(pszClass, pszDeviceID, szSubKey))
  355. {
  356. // Delete the key
  357. // REVIEW: should delete all references to the key
  358. RegDeleteKeyAndSubKeys(reg.m_hKey, szSubKey);
  359. bResult = TRUE;
  360. // Restart the search to ensure we find all broken items
  361. dwIndex = 0;
  362. continue;
  363. }
  364. dwIndex++;
  365. }
  366. }
  367. //
  368. // Find and remove any unreferenced Class keys
  369. //
  370. wsprintf(szRegKey, "System\\CurrentControlSet\\Services\\Class\\%s", pszClass);
  371. if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey))
  372. {
  373. TCHAR szSubKey[50];
  374. int cClassKeysRemoved = 0;
  375. DWORD dwIndex = 0;
  376. for (;;)
  377. {
  378. DWORD cchSubKey = _countof(szSubKey);
  379. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  380. break;
  381. wsprintf(szRegKey, "%s\\%s", pszClass, szSubKey);
  382. if (!IsNetClassKeyReferenced(szRegKey))
  383. {
  384. // Delete the key
  385. RegDeleteKeyAndSubKeys(reg.m_hKey, szSubKey);
  386. bResult = TRUE;
  387. cClassKeysRemoved++;
  388. // Restart the search to ensure we find all broken items
  389. dwIndex = 0;
  390. continue;
  391. }
  392. dwIndex++;
  393. }
  394. // If we removed any class keys, check the Enum keys again
  395. if (cClassKeysRemoved != 0)
  396. goto delete_enum_keys;
  397. }
  398. return bResult;
  399. }
  400. BOOL GetDeviceInterfaceList(LPCSTR pszClass, LPCSTR pszDeviceID, LPCSTR pszInterfaceType, LPSTR pszBuf, int cchBuf)
  401. {
  402. ASSERT(pszClass != NULL);
  403. CRegistry regClassRoot;
  404. CHAR szRegClassRoot[260];
  405. static const CHAR szClassString[] = "System\\CurrentControlSet\\Services\\Class\\";
  406. int cRemaining = sizeof(szRegClassRoot) - sizeof(szClassString);
  407. if (lstrlen(pszClass) >= cRemaining)
  408. return FALSE; // Bail out
  409. lstrcpy(szRegClassRoot, szClassString);
  410. lstrcat(szRegClassRoot, pszClass);
  411. if (regClassRoot.OpenKey(HKEY_LOCAL_MACHINE, szRegClassRoot, KEY_READ))
  412. {
  413. for (DWORD iAdapter = 0; ; iAdapter++)
  414. {
  415. CHAR szSubKey[15];
  416. DWORD cchSubKey = _countof(szSubKey) - 4; // -4 to allow "\\Ndi"
  417. if (ERROR_SUCCESS != RegEnumKeyEx(regClassRoot.m_hKey, iAdapter, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
  418. break;
  419. CRegistry regNdi;
  420. lstrcat(szSubKey, "\\Ndi");
  421. if (regNdi.OpenKey(regClassRoot.m_hKey, szSubKey, KEY_READ))
  422. {
  423. CHAR szCurDeviceID[200];
  424. if (regNdi.QueryStringValue("DeviceID", szCurDeviceID, _countof(szCurDeviceID)) &&
  425. 0 == lstrcmpi(szCurDeviceID, pszDeviceID))
  426. {
  427. BOOL bResult = FALSE;
  428. if (regNdi.OpenSubKey("Interfaces", KEY_READ))
  429. {
  430. bResult = regNdi.QueryStringValue(pszInterfaceType, pszBuf, cchBuf);
  431. }
  432. return bResult;
  433. }
  434. }
  435. }
  436. }
  437. return FALSE;
  438. }
  439. BOOL CheckMatchingInterface(LPCSTR pszList1, LPCSTR pszList2)
  440. {
  441. CHAR szInterface1[40];
  442. CHAR szInterface2[40];
  443. while (GetFirstToken(pszList1, ',', szInterface1, _countof(szInterface1)))
  444. {
  445. LPCSTR pszTemp2 = pszList2;
  446. while (GetFirstToken(pszTemp2, ',', szInterface2, _countof(szInterface2)))
  447. {
  448. if (0 == lstrcmpi(szInterface1, szInterface2))
  449. return TRUE;
  450. }
  451. }
  452. return FALSE;
  453. }
  454. BOOL GetDeviceLowerRange(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
  455. {
  456. return GetDeviceInterfaceList(pszClass, pszDeviceID, "LowerRange", pszBuf, cchBuf);
  457. }
  458. BOOL GetDeviceUpperRange(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
  459. {
  460. return GetDeviceInterfaceList(pszClass, pszDeviceID, "UpperRange", pszBuf, cchBuf);
  461. }
  462. // class is "Net", "NetTrans", "NetClient", or "NetService"
  463. HRESULT OpenNetClassKey(CRegistry& reg, LPCSTR pszClass, LPCSTR pszSubKey, REGSAM dwAccess)
  464. {
  465. ASSERT(pszClass != NULL);
  466. CHAR szRegKey[MAX_PATH];
  467. static const CHAR szClassString[] = "System\\CurrentControlSet\\Services\\Class\\";
  468. int cRemaining = sizeof(szRegKey) -
  469. (sizeof(szClassString) + ((pszSubKey)?(lstrlen(pszSubKey) + 1):(0)));
  470. if (lstrlen(pszClass) >= cRemaining)
  471. return NETCONN_INVALID_ARGUMENT; // Bail out
  472. lstrcpy(szRegKey, szClassString);
  473. lstrcat(szRegKey, pszClass);
  474. if (pszSubKey != NULL)
  475. {
  476. lstrcat(szRegKey, "\\");
  477. lstrcat(szRegKey, pszSubKey);
  478. }
  479. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, dwAccess))
  480. return NETCONN_UNKNOWN_ERROR;
  481. return NETCONN_SUCCESS;
  482. }
  483. VOID FindUnusedDeviceIdNumber(CRegistry& reg, LPSTR pszBuf, int cchBuf)
  484. {
  485. for (DWORD dwDeviceNumber = 0; ; dwDeviceNumber++)
  486. {
  487. CRegistry regTemp;
  488. wsprintf(pszBuf, "%04lu", dwDeviceNumber);
  489. if (!regTemp.OpenKey(reg.m_hKey, pszBuf, KEY_READ))
  490. break;
  491. }
  492. }
  493. // Given a network device ID, such as "MSTCP", creates a new instance
  494. // of it by copying an existing instance.
  495. // pszClass = "NetTrans"
  496. // pszDeviceID = "MSTCP"
  497. // pszBuf is filled with the new device binding ID, e.g. "MSTCP\0000"
  498. HRESULT FindAndCloneNetEnumKey(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
  499. {
  500. CRegistry reg;
  501. TCHAR szExistingEnumKey[260];
  502. if (!FindValidNetEnumKey(pszClass, pszDeviceID, szExistingEnumKey, _countof(szExistingEnumKey)))
  503. {
  504. ASSERT(FALSE);
  505. return NETCONN_UNKNOWN_ERROR; // the device is not installed properly!
  506. }
  507. TCHAR szRegKey[200];
  508. wsprintf(szRegKey, "Enum\\Network\\%s", pszDeviceID);
  509. if (!reg.CreateKey(HKEY_LOCAL_MACHINE, szRegKey))
  510. {
  511. ASSERT(FALSE);
  512. return NETCONN_UNKNOWN_ERROR;
  513. }
  514. // Find the next unused device ID number
  515. TCHAR szNewNumber[10];
  516. FindUnusedDeviceIdNumber(reg, szNewNumber, _countof(szNewNumber));
  517. // Make a copy of the key (recursive)
  518. LPCTSTR pszExistingNumber = FindFileTitle(szExistingEnumKey);
  519. if (!reg.CloneSubKey(pszExistingNumber, szNewNumber, TRUE))
  520. {
  521. ASSERT(FALSE);
  522. return NETCONN_UNKNOWN_ERROR;
  523. }
  524. wsprintf(pszBuf, "%s\\%s", pszDeviceID, szNewNumber);
  525. return NETCONN_SUCCESS;
  526. }
  527. // existing driver is of the form "NetTrans\0000"
  528. // new driver will be of the form "NetTrans\0001"
  529. HRESULT CloneNetClassKey(LPCSTR pszExistingDriver, LPSTR pszNewDriverBuf, int cchNewDriverBuf)
  530. {
  531. HRESULT hr;
  532. LPSTR pchSlash = strchr(pszExistingDriver, '\\');
  533. if (pchSlash == NULL)
  534. {
  535. ASSERT(FALSE);
  536. return NETCONN_UNKNOWN_ERROR;
  537. }
  538. // Extract just the class portion of the driver name, e.g. "NetTrans"
  539. CHAR szClass[30];
  540. int cchClass = (int)(pchSlash - pszExistingDriver);
  541. ASSERT(cchClass < _countof(szClass));
  542. lstrcpyn(szClass, pszExistingDriver, cchClass+1);
  543. CRegistry regClassKey;
  544. if (FAILED(hr = OpenNetClassKey(regClassKey, szClass, NULL, KEY_ALL_ACCESS)))
  545. return hr;
  546. // Find the next unused driver number
  547. CHAR szDriverNumber[5];
  548. FindUnusedDeviceIdNumber(regClassKey, szDriverNumber, _countof(szDriverNumber));
  549. // Make a copy of the key (recursive)
  550. if (!regClassKey.CloneSubKey(pchSlash+1, szDriverNumber, TRUE))
  551. {
  552. ASSERT(FALSE);
  553. return NETCONN_UNKNOWN_ERROR;
  554. }
  555. wsprintf(pszNewDriverBuf, "%s\\%s", szClass, szDriverNumber);
  556. // Remove the "default" subkey if we just copied it (can't have 2 defaults)
  557. if (regClassKey.OpenSubKey(szDriverNumber))
  558. {
  559. if (regClassKey.OpenSubKey("Ndi"))
  560. {
  561. RegDeleteKey(regClassKey.m_hKey, "Default");
  562. }
  563. }
  564. return NETCONN_SUCCESS;
  565. }
  566. // pszSubKey == "MSTCP", "VREDIR", "MSTCP\0000", etc.
  567. HRESULT OpenNetEnumKey(CRegistry& reg, LPCSTR pszSubKey, REGSAM dwAccess)
  568. {
  569. ASSERT(pszSubKey != NULL);
  570. CHAR szRegKey[MAX_PATH];
  571. static const CHAR szEnumString[] = "Enum\\Network\\";
  572. int cRemaining = sizeof(szRegKey) - sizeof(szEnumString);
  573. if (lstrlen(pszSubKey) >= cRemaining)
  574. return NETCONN_INVALID_ARGUMENT; // Bail out
  575. lstrcpy(szRegKey, szEnumString);
  576. lstrcat(szRegKey, pszSubKey);
  577. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, dwAccess))
  578. return NETCONN_UNKNOWN_ERROR;
  579. return NETCONN_SUCCESS;
  580. }
  581. // pszClass = "NetClient"
  582. // pszDeviceID = "NWREDIR"
  583. HRESULT DeleteClassKeyReferences(LPCSTR pszClass, LPCSTR pszDeviceID)
  584. {
  585. HRESULT hr = NETCONN_SUCCESS;
  586. // Delete the class key(s)
  587. CRegistry reg;
  588. if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class") &&
  589. reg.OpenSubKey(pszClass))
  590. {
  591. TCHAR szNumber[20];
  592. DWORD iClassItem = 0;
  593. for (;;)
  594. {
  595. DWORD cchNumber = _countof(szNumber);
  596. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iClassItem, szNumber, &cchNumber, NULL, NULL, NULL, NULL))
  597. break;
  598. CRegistry regNumber;
  599. if (regNumber.OpenKey(reg.m_hKey, szNumber))
  600. {
  601. CRegistry regNdi;
  602. if (regNdi.OpenKey(regNumber.m_hKey, "Ndi"))
  603. {
  604. TCHAR szDeviceID[50];
  605. if (regNdi.QueryStringValue("DeviceID", szDeviceID, _countof(szDeviceID)) &&
  606. !lstrcmpi(szDeviceID, pszDeviceID))
  607. {
  608. regNdi.CloseKey();
  609. regNumber.CloseKey();
  610. RegDeleteKeyAndSubKeys(reg.m_hKey, szNumber);
  611. hr = NETCONN_NEED_RESTART;
  612. // Restart the search
  613. iClassItem = 0;
  614. continue;
  615. }
  616. }
  617. }
  618. iClassItem++;
  619. }
  620. }
  621. return hr;
  622. }
  623. // pszClassKey is of the form "NetService\0000"
  624. BOOL IsNetClassKeyReferenced(LPCSTR pszClassKey)
  625. {
  626. CRegistry reg;
  627. CHAR szDeviceID[200];
  628. DWORD iKey;
  629. // Get the device ID
  630. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class", KEY_READ))
  631. goto done;
  632. if (!reg.OpenSubKey(pszClassKey, KEY_READ))
  633. goto done;
  634. if (!reg.OpenSubKey("Ndi", KEY_READ))
  635. goto done;
  636. if (!reg.QueryStringValue("DeviceID", szDeviceID, _countof(szDeviceID)))
  637. goto done;
  638. if (!reg.OpenKey(HKEY_LOCAL_MACHINE, "Enum\\Network", KEY_READ))
  639. goto done;
  640. if (!reg.OpenSubKey(szDeviceID, KEY_READ))
  641. goto done;
  642. for (iKey = 0; ; iKey++)
  643. {
  644. CHAR szSubKey[60];
  645. DWORD cbSubKey = _countof(szSubKey);
  646. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iKey, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL))
  647. break;
  648. CRegistry regSubKey;
  649. if (regSubKey.OpenKey(reg.m_hKey, szSubKey, KEY_READ))
  650. {
  651. CHAR szDriver[60];
  652. if (regSubKey.QueryStringValue("Driver", szDriver, _countof(szDriver)))
  653. {
  654. if (0 == lstrcmpi(szDriver, pszClassKey))
  655. return TRUE;
  656. }
  657. }
  658. }
  659. done:
  660. return FALSE;
  661. }
  662. // Given a binding of one of the two following forms
  663. // "MSTCP\0000"
  664. // "Enum\Network\MSTCP\0000"
  665. // and a device ID such as "MSTCP", returns TRUE if the binding is a binding
  666. // of the given device, or FALSE if not.
  667. BOOL WINAPI DoesBindingMatchDeviceID(LPCSTR pszBinding, LPCSTR pszDeviceID)
  668. {
  669. CHAR szTemp[40];
  670. LPCSTR pszBoundDevice = FindPartialPath(pszBinding, 1); // skip "Enum\..." if present
  671. lstrcpyn(szTemp, pszBoundDevice, _countof(szTemp));
  672. LPSTR pchSlash = strchr(szTemp, '\\');
  673. if (pchSlash != NULL)
  674. *pchSlash = '\0';
  675. return !lstrcmpi(szTemp, pszDeviceID);
  676. }