767 lines
20 KiB
C++
767 lines
20 KiB
C++
|
//
|
||
|
// Binding.cpp
|
||
|
//
|
||
|
// Shared code for enumerating and modifying network bindings, used for
|
||
|
// protocols, clients, and services.
|
||
|
//
|
||
|
// History:
|
||
|
//
|
||
|
// 2/02/1999 KenSh Created for JetNet
|
||
|
// 9/29/1999 KenSh Repurposed for Home Networking Wizard
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "NetConn.h"
|
||
|
#include "nconnwrap.h"
|
||
|
#include "TheApp.h"
|
||
|
|
||
|
|
||
|
// Given a string such as "MSTCP\0000" or "Network\MSTCP\0000", returns a
|
||
|
// string such as "Enum\Network\MSTCP\0000".
|
||
|
//
|
||
|
// Input string will copied without modification if it starts with "Enum\".
|
||
|
//
|
||
|
void WINAPI FullEnumKeyFromBinding(LPCSTR pszBinding, LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
LPCSTR pszStatic = "";
|
||
|
int cchStatic = 0;
|
||
|
|
||
|
int cSlashes = CountChars(pszBinding, '\\');
|
||
|
if (cSlashes == 1)
|
||
|
{
|
||
|
pszStatic = "Enum\\Network\\";
|
||
|
cchStatic = _countof("Enum\\Network\\") - 1;
|
||
|
}
|
||
|
else if (cSlashes == 2)
|
||
|
{
|
||
|
pszStatic = "Enum\\";
|
||
|
cchStatic = _countof("Enum\\") - 1;
|
||
|
}
|
||
|
|
||
|
int cchBinding = lstrlen(pszBinding);
|
||
|
if (cchBuf < cchBinding + cchStatic + 1)
|
||
|
{
|
||
|
*pszBuf = '\0';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lstrcpy(pszBuf, pszStatic);
|
||
|
lstrcpy(pszBuf + cchStatic, pszBinding);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Given a full or partial enum key, allocates and returns an array of string
|
||
|
// pointers, one pointer for each binding.
|
||
|
//
|
||
|
// Examples of valid input:
|
||
|
// "MSTCP\0000"
|
||
|
// "Network\MSTCP\0000"
|
||
|
// "Enum\Network\MSTCP\0000"
|
||
|
// "Enum\PCI\VEN_10B7&DEV_9050&SUBSYS_00000000&REV_00\407000"
|
||
|
//
|
||
|
// Each output string is in the short format ("MSTCP\0000").
|
||
|
//
|
||
|
// pprgBindings may be NULL, in which case only the count is returned.
|
||
|
//
|
||
|
int WINAPI EnumNetBindings(LPCSTR pszParentBinding, LPSTR** pprgBindings)
|
||
|
{
|
||
|
TCHAR szFullParent[200];
|
||
|
FullEnumKeyFromBinding(pszParentBinding, szFullParent, _countof(szFullParent));
|
||
|
|
||
|
CRegistry reg;
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, szFullParent, KEY_READ))
|
||
|
{
|
||
|
if (reg.OpenSubKey("Bindings", KEY_READ))
|
||
|
{
|
||
|
DWORD cBindings;
|
||
|
DWORD cbMaxValueNameLen;
|
||
|
if (ERROR_SUCCESS == RegQueryInfoKey(reg.m_hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cBindings, &cbMaxValueNameLen, NULL, NULL, NULL))
|
||
|
{
|
||
|
if (pprgBindings == NULL)
|
||
|
{
|
||
|
return (int)cBindings;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int cEnum = 0;
|
||
|
|
||
|
LPTSTR* prgBindings = (LPTSTR*)NetConnAlloc(cBindings * (cbMaxValueNameLen + 1 + sizeof(LPTSTR)));
|
||
|
LPTSTR pch = (LPTSTR)(prgBindings + cBindings);
|
||
|
for (DWORD iBinding = 0; iBinding < cBindings; iBinding++)
|
||
|
{
|
||
|
DWORD cchValueName = cbMaxValueNameLen+1;
|
||
|
prgBindings[iBinding] = pch;
|
||
|
if (ERROR_SUCCESS == RegEnumValue(reg.m_hKey, iBinding, pch, &cchValueName, NULL, NULL, NULL, NULL))
|
||
|
{
|
||
|
pch += (cchValueName + 1);
|
||
|
cEnum += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pprgBindings = prgBindings;
|
||
|
return cEnum;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pprgBindings != NULL)
|
||
|
{
|
||
|
*pprgBindings = NULL;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Same as EnumNetBindings, except it filters out bindings that don't
|
||
|
// match the given device ID (e.g. "MSTCP").
|
||
|
// pprgBindings may be NULL, in which case only the count is returned.
|
||
|
int WINAPI EnumMatchingNetBindings(LPCSTR pszParentBinding, LPCSTR pszDeviceID, LPSTR** pprgBindings)
|
||
|
{
|
||
|
LPSTR* prgBindings;
|
||
|
int cBindings = EnumNetBindings(pszParentBinding, &prgBindings);
|
||
|
for (int iBinding = 0; iBinding < cBindings; iBinding++)
|
||
|
{
|
||
|
if (!DoesBindingMatchDeviceID(prgBindings[iBinding], pszDeviceID))
|
||
|
{
|
||
|
for (int iBinding2 = iBinding+1; iBinding2 < cBindings; iBinding2++)
|
||
|
{
|
||
|
prgBindings[iBinding2-1] = prgBindings[iBinding2];
|
||
|
}
|
||
|
cBindings--;
|
||
|
iBinding--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cBindings == 0 || pprgBindings == NULL)
|
||
|
{
|
||
|
NetConnFree(prgBindings);
|
||
|
prgBindings = NULL;
|
||
|
}
|
||
|
|
||
|
if (pprgBindings != NULL)
|
||
|
{
|
||
|
*pprgBindings = prgBindings;
|
||
|
}
|
||
|
|
||
|
return cBindings;
|
||
|
}
|
||
|
|
||
|
|
||
|
// RemoveBinding
|
||
|
//
|
||
|
// Removes a specific instance of a protocol, client, or service from the registry.
|
||
|
// Any cascading dependencies are removed as well.
|
||
|
//
|
||
|
// pszNetEnumKey - partial Enum key of the binding to be removed, e.g. "MSTCP\0000"
|
||
|
// or "VSERVER\0000". Assumed to live under HKLM\Enum\Network.
|
||
|
//
|
||
|
// History:
|
||
|
//
|
||
|
// 3/25/1999 KenSh Created
|
||
|
//
|
||
|
VOID RemoveBinding(LPCSTR pszBinding)
|
||
|
{
|
||
|
CHAR szRegKey[MAX_PATH];
|
||
|
lstrcpy(szRegKey, "Enum\\Network\\");
|
||
|
lstrcat(szRegKey, pszBinding);
|
||
|
int cchMainEnumKey = lstrlen(szRegKey);
|
||
|
lstrcat(szRegKey, "\\Bindings");
|
||
|
|
||
|
// Enumerate and delete all binding keys referred to by current binding key
|
||
|
CRegistry reg;
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS)) // e.g. "Enum\Network\MSTCP\0000\Bindings"
|
||
|
{
|
||
|
for (;;) // Loop until we've deleted all the subkeys
|
||
|
{
|
||
|
CHAR szValueName[60];
|
||
|
DWORD cbValueName = _countof(szValueName);
|
||
|
if (ERROR_SUCCESS != RegEnumValue(reg.m_hKey, 0, szValueName, &cbValueName, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
// Remove the client or service
|
||
|
RemoveBindingFromParent(reg.m_hKey, szValueName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Open the main node, and get values we'll need later
|
||
|
TCHAR szMasterCopy[60];
|
||
|
CHAR szClassKey[40];
|
||
|
szMasterCopy[0] = '\0';
|
||
|
szRegKey[cchMainEnumKey] = '\0';
|
||
|
if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ)) // e.g. "Enum\Network\MSTCP\0000"
|
||
|
return; // it's already been deleted
|
||
|
|
||
|
reg.QueryStringValue("MasterCopy", szMasterCopy, _countof(szMasterCopy));
|
||
|
reg.QueryStringValue("Driver", szClassKey, _countof(szClassKey)); // e.g. "NetClient\0000"
|
||
|
|
||
|
// Remove this binding's node from the registry (and its sub-keys)
|
||
|
LPSTR pchSubKey = FindFileTitle(szRegKey);
|
||
|
*(pchSubKey-1) = '\0';
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS)) // e.g. "Enum\Network\MSTCP"
|
||
|
{
|
||
|
// Main purpose of this function: delete the requested binding key
|
||
|
RegDeleteKeyAndSubKeys(reg.m_hKey, pchSubKey);
|
||
|
|
||
|
// Was this a "MasterCopy" binding?
|
||
|
static const int cchEnumNet = _countof("Enum\\Network\\") - 1;
|
||
|
BOOL bMasterCopy = (0 == lstrcmpi(szMasterCopy + cchEnumNet, pszBinding));
|
||
|
|
||
|
// Check for siblings which might be referencing the same class key
|
||
|
BOOL bClassKeyReferenced = FALSE;
|
||
|
CHAR szAlternateMaster[60];
|
||
|
szAlternateMaster[0] = '\0';
|
||
|
for (DWORD iSibling = 0; ; iSibling++)
|
||
|
{
|
||
|
CHAR szSiblingKey[60];
|
||
|
DWORD cbSiblingKey = _countof(szSiblingKey);
|
||
|
if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iSibling, szSiblingKey, &cbSiblingKey, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
CRegistry regSibling;
|
||
|
if (regSibling.OpenKey(reg.m_hKey, szSiblingKey, KEY_ALL_ACCESS))
|
||
|
{
|
||
|
CHAR szSiblingDriver[60];
|
||
|
if (regSibling.QueryStringValue("Driver", szSiblingDriver, _countof(szSiblingDriver)))
|
||
|
{
|
||
|
if (0 == lstrcmpi(szSiblingDriver, szClassKey))
|
||
|
{
|
||
|
bClassKeyReferenced = TRUE;
|
||
|
|
||
|
if (!bMasterCopy)
|
||
|
break;
|
||
|
|
||
|
// Check if this sib's mastercopy points to the key being deleted
|
||
|
if (bMasterCopy)
|
||
|
{
|
||
|
CHAR szSibMaster[60];
|
||
|
if (regSibling.QueryStringValue("MasterCopy", szSibMaster, _countof(szSibMaster))
|
||
|
&& !lstrcmpi(szSibMaster, szMasterCopy))
|
||
|
{
|
||
|
if (szAlternateMaster[0] == '\0') // first match, make it the new master
|
||
|
{
|
||
|
wsprintf(szAlternateMaster, "%s\\%s", szRegKey, szSiblingKey);
|
||
|
}
|
||
|
|
||
|
regSibling.SetStringValue("MasterCopy", szAlternateMaster);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bClassKeyReferenced)
|
||
|
{
|
||
|
// No more references to the class key, so delete it
|
||
|
lstrcpy(szRegKey, "System\\CurrentControlSet\\Services\\Class\\");
|
||
|
lstrcat(szRegKey, szClassKey);
|
||
|
pchSubKey = FindFileTitle(szRegKey);
|
||
|
*(pchSubKey-1) = '\0';
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS))
|
||
|
{
|
||
|
RegDeleteKeyAndSubKeys(reg.m_hKey, pchSubKey);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// RemoveBindingFromParent
|
||
|
//
|
||
|
// Given an open Bindings key, and a string representing one of the bindings
|
||
|
// listed in it, this function deletes the value, then calls RemoveBinding()
|
||
|
// to delete the binding and all of its cascading dependencies.
|
||
|
//
|
||
|
// History:
|
||
|
//
|
||
|
// 3/25/1999 KenSh Created
|
||
|
// 4/30/1999 KenSh Got rid of unnecessary code to delete empty parent
|
||
|
//
|
||
|
VOID RemoveBindingFromParent(HKEY hkeyParentBindingsKey, LPCSTR pszBinding)
|
||
|
{
|
||
|
// Delete the binding from the Bindings key of the person bound to us
|
||
|
VERIFY(ERROR_SUCCESS == RegDeleteValue(hkeyParentBindingsKey, pszBinding));
|
||
|
RemoveBinding(pszBinding);
|
||
|
}
|
||
|
|
||
|
// pszClassKey is of the form "NetService\0000"
|
||
|
BOOL WINAPI DoesClassKeyExist(LPCSTR pszClassKey)
|
||
|
{
|
||
|
CRegistry reg;
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class"))
|
||
|
{
|
||
|
if (reg.OpenSubKey(pszClassKey))
|
||
|
{
|
||
|
// REVIEW: could check for presence of certain entries
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// pszClass = "NetService"
|
||
|
// pszDevice = "VSERVER"
|
||
|
// pszEnumSubKey = "0000"
|
||
|
BOOL WINAPI IsValidNetEnumKey(LPCSTR pszClass, LPCSTR pszDevice, LPCSTR pszEnumSubKey)
|
||
|
{
|
||
|
CRegistry reg;
|
||
|
TCHAR szRegKey[260];
|
||
|
wsprintf(szRegKey, "Enum\\Network\\%s\\%s", pszDevice, pszEnumSubKey);
|
||
|
|
||
|
BOOL bResult = FALSE;
|
||
|
|
||
|
if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ))
|
||
|
goto done;
|
||
|
|
||
|
TCHAR szBuf[100];
|
||
|
|
||
|
// Check a few values
|
||
|
if (!reg.QueryStringValue("Class", szBuf, _countof(szBuf)))
|
||
|
goto done;
|
||
|
if (0 != lstrcmpi(szBuf, pszClass))
|
||
|
goto done;
|
||
|
if (!reg.QueryStringValue("Driver", szBuf, _countof(szBuf)))
|
||
|
goto done;
|
||
|
if (!DoesClassKeyExist(szBuf))
|
||
|
goto done;
|
||
|
|
||
|
bResult = TRUE;
|
||
|
|
||
|
done:
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
// pszClass is of the form "NetService"
|
||
|
// pszDevice is of the form "VSERVER"
|
||
|
// pszBuf may be NULL if you don't need a copy of the string
|
||
|
BOOL WINAPI FindValidNetEnumKey(LPCSTR pszClass, LPCSTR pszDevice, LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
CRegistry reg;
|
||
|
TCHAR szRegKey[200];
|
||
|
wsprintf(szRegKey, "Enum\\Network\\%s", pszDevice);
|
||
|
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_READ))
|
||
|
{
|
||
|
DWORD dwIndex;
|
||
|
TCHAR szSubKey[50];
|
||
|
|
||
|
for (dwIndex = 0; ; dwIndex++)
|
||
|
{
|
||
|
DWORD cchSubKey = _countof(szSubKey);
|
||
|
if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
if (!IsValidNetEnumKey(pszClass, pszDevice, szSubKey))
|
||
|
continue;
|
||
|
|
||
|
// Found a valid entry; copy it to pszBuf and return TRUE
|
||
|
//
|
||
|
if (pszBuf != NULL)
|
||
|
{
|
||
|
ASSERT(cchBuf > lstrlen(szRegKey) + lstrlen(szSubKey) + 1);
|
||
|
wsprintf(pszBuf, "%s\\%s", szRegKey, szSubKey);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// pszClass = "NetService", etc.
|
||
|
// pszDeviceID = "VSERVER", etc.
|
||
|
// returns TRUE if anything was removed
|
||
|
BOOL WINAPI RemoveBrokenNetItems(LPCSTR pszClass, LPCSTR pszDeviceID)
|
||
|
{
|
||
|
CRegistry reg;
|
||
|
TCHAR szRegKey[200];
|
||
|
BOOL bResult = FALSE;
|
||
|
|
||
|
delete_enum_keys:
|
||
|
//
|
||
|
// Find and remove any broken Enum keys
|
||
|
//
|
||
|
wsprintf(szRegKey, "Enum\\Network\\%s", pszDeviceID);
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey))
|
||
|
{
|
||
|
TCHAR szSubKey[50];
|
||
|
|
||
|
DWORD dwIndex = 0;
|
||
|
for (;;)
|
||
|
{
|
||
|
DWORD cchSubKey = _countof(szSubKey);
|
||
|
if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
if (!IsValidNetEnumKey(pszClass, pszDeviceID, szSubKey))
|
||
|
{
|
||
|
// Delete the key
|
||
|
// REVIEW: should delete all references to the key
|
||
|
RegDeleteKeyAndSubKeys(reg.m_hKey, szSubKey);
|
||
|
bResult = TRUE;
|
||
|
|
||
|
// Restart the search to ensure we find all broken items
|
||
|
dwIndex = 0;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
dwIndex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find and remove any unreferenced Class keys
|
||
|
//
|
||
|
wsprintf(szRegKey, "System\\CurrentControlSet\\Services\\Class\\%s", pszClass);
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey))
|
||
|
{
|
||
|
TCHAR szSubKey[50];
|
||
|
int cClassKeysRemoved = 0;
|
||
|
|
||
|
DWORD dwIndex = 0;
|
||
|
for (;;)
|
||
|
{
|
||
|
DWORD cchSubKey = _countof(szSubKey);
|
||
|
if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
wsprintf(szRegKey, "%s\\%s", pszClass, szSubKey);
|
||
|
if (!IsNetClassKeyReferenced(szRegKey))
|
||
|
{
|
||
|
// Delete the key
|
||
|
RegDeleteKeyAndSubKeys(reg.m_hKey, szSubKey);
|
||
|
bResult = TRUE;
|
||
|
cClassKeysRemoved++;
|
||
|
|
||
|
// Restart the search to ensure we find all broken items
|
||
|
dwIndex = 0;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
dwIndex++;
|
||
|
}
|
||
|
|
||
|
// If we removed any class keys, check the Enum keys again
|
||
|
if (cClassKeysRemoved != 0)
|
||
|
goto delete_enum_keys;
|
||
|
}
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
BOOL GetDeviceInterfaceList(LPCSTR pszClass, LPCSTR pszDeviceID, LPCSTR pszInterfaceType, LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
CRegistry regClassRoot;
|
||
|
CHAR szRegClassRoot[260];
|
||
|
lstrcpy(szRegClassRoot, "System\\CurrentControlSet\\Services\\Class\\");
|
||
|
lstrcat(szRegClassRoot, pszClass);
|
||
|
if (regClassRoot.OpenKey(HKEY_LOCAL_MACHINE, szRegClassRoot, KEY_READ))
|
||
|
{
|
||
|
for (DWORD iAdapter = 0; ; iAdapter++)
|
||
|
{
|
||
|
CHAR szSubKey[15];
|
||
|
DWORD cchSubKey = _countof(szSubKey) - 4; // -4 to allow "\\Ndi"
|
||
|
if (ERROR_SUCCESS != RegEnumKeyEx(regClassRoot.m_hKey, iAdapter, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
CRegistry regNdi;
|
||
|
lstrcat(szSubKey, "\\Ndi");
|
||
|
if (regNdi.OpenKey(regClassRoot.m_hKey, szSubKey, KEY_READ))
|
||
|
{
|
||
|
CHAR szCurDeviceID[200];
|
||
|
if (regNdi.QueryStringValue("DeviceID", szCurDeviceID, _countof(szCurDeviceID)) &&
|
||
|
0 == lstrcmpi(szCurDeviceID, pszDeviceID))
|
||
|
{
|
||
|
BOOL bResult = FALSE;
|
||
|
|
||
|
if (regNdi.OpenSubKey("Interfaces", KEY_READ))
|
||
|
{
|
||
|
bResult = regNdi.QueryStringValue(pszInterfaceType, pszBuf, cchBuf);
|
||
|
}
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CheckMatchingInterface(LPCSTR pszList1, LPCSTR pszList2)
|
||
|
{
|
||
|
CHAR szInterface1[40];
|
||
|
CHAR szInterface2[40];
|
||
|
|
||
|
while (GetFirstToken(pszList1, ',', szInterface1, _countof(szInterface1)))
|
||
|
{
|
||
|
LPCSTR pszTemp2 = pszList2;
|
||
|
while (GetFirstToken(pszTemp2, ',', szInterface2, _countof(szInterface2)))
|
||
|
{
|
||
|
if (0 == lstrcmpi(szInterface1, szInterface2))
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL GetDeviceLowerRange(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
return GetDeviceInterfaceList(pszClass, pszDeviceID, "LowerRange", pszBuf, cchBuf);
|
||
|
}
|
||
|
|
||
|
BOOL GetDeviceUpperRange(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
return GetDeviceInterfaceList(pszClass, pszDeviceID, "UpperRange", pszBuf, cchBuf);
|
||
|
}
|
||
|
|
||
|
// class is "Net", "NetTrans", "NetClient", or "NetService"
|
||
|
HRESULT OpenNetClassKey(CRegistry& reg, LPCSTR pszClass, LPCSTR pszSubKey, REGSAM dwAccess)
|
||
|
{
|
||
|
ASSERT(pszClass != NULL);
|
||
|
|
||
|
CHAR szRegKey[MAX_PATH];
|
||
|
lstrcpy(szRegKey, "System\\CurrentControlSet\\Services\\Class\\");
|
||
|
lstrcat(szRegKey, pszClass);
|
||
|
|
||
|
if (pszSubKey != NULL)
|
||
|
{
|
||
|
lstrcat(szRegKey, "\\");
|
||
|
lstrcat(szRegKey, pszSubKey);
|
||
|
}
|
||
|
|
||
|
if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, dwAccess))
|
||
|
return NETCONN_UNKNOWN_ERROR;
|
||
|
|
||
|
return NETCONN_SUCCESS;
|
||
|
}
|
||
|
|
||
|
VOID FindUnusedDeviceIdNumber(CRegistry& reg, LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
for (DWORD dwDeviceNumber = 0; ; dwDeviceNumber++)
|
||
|
{
|
||
|
CRegistry regTemp;
|
||
|
wsprintf(pszBuf, "%04lu", dwDeviceNumber);
|
||
|
if (!regTemp.OpenKey(reg.m_hKey, pszBuf, KEY_READ))
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Given a network device ID, such as "MSTCP", creates a new instance
|
||
|
// of it by copying an existing instance.
|
||
|
// pszClass = "NetTrans"
|
||
|
// pszDeviceID = "MSTCP"
|
||
|
// pszBuf is filled with the new device binding ID, e.g. "MSTCP\0000"
|
||
|
HRESULT FindAndCloneNetEnumKey(LPCSTR pszClass, LPCSTR pszDeviceID, LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
CRegistry reg;
|
||
|
|
||
|
TCHAR szExistingEnumKey[260];
|
||
|
if (!FindValidNetEnumKey(pszClass, pszDeviceID, szExistingEnumKey, _countof(szExistingEnumKey)))
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
return NETCONN_UNKNOWN_ERROR; // the device is not installed properly!
|
||
|
}
|
||
|
|
||
|
TCHAR szRegKey[200];
|
||
|
wsprintf(szRegKey, "Enum\\Network\\%s", pszDeviceID);
|
||
|
if (!reg.CreateKey(HKEY_LOCAL_MACHINE, szRegKey))
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
return NETCONN_UNKNOWN_ERROR;
|
||
|
}
|
||
|
|
||
|
// Find the next unused device ID number
|
||
|
TCHAR szNewNumber[10];
|
||
|
FindUnusedDeviceIdNumber(reg, szNewNumber, _countof(szNewNumber));
|
||
|
|
||
|
// Make a copy of the key (recursive)
|
||
|
LPCTSTR pszExistingNumber = FindFileTitle(szExistingEnumKey);
|
||
|
if (!reg.CloneSubKey(pszExistingNumber, szNewNumber, TRUE))
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
return NETCONN_UNKNOWN_ERROR;
|
||
|
}
|
||
|
|
||
|
wsprintf(pszBuf, "%s\\%s", pszDeviceID, szNewNumber);
|
||
|
return NETCONN_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// existing driver is of the form "NetTrans\0000"
|
||
|
// new driver will be of the form "NetTrans\0001"
|
||
|
HRESULT CloneNetClassKey(LPCSTR pszExistingDriver, LPSTR pszNewDriverBuf, int cchNewDriverBuf)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
LPSTR pchSlash = strchr(pszExistingDriver, '\\');
|
||
|
if (pchSlash == NULL)
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
return NETCONN_UNKNOWN_ERROR;
|
||
|
}
|
||
|
|
||
|
// Extract just the class portion of the driver name, e.g. "NetTrans"
|
||
|
CHAR szClass[30];
|
||
|
int cchClass = (int)(pchSlash - pszExistingDriver);
|
||
|
ASSERT(cchClass < _countof(szClass));
|
||
|
lstrcpyn(szClass, pszExistingDriver, cchClass+1);
|
||
|
|
||
|
CRegistry regClassKey;
|
||
|
if (FAILED(hr = OpenNetClassKey(regClassKey, szClass, NULL, KEY_ALL_ACCESS)))
|
||
|
return hr;
|
||
|
|
||
|
// Find the next unused driver number
|
||
|
CHAR szDriverNumber[5];
|
||
|
FindUnusedDeviceIdNumber(regClassKey, szDriverNumber, _countof(szDriverNumber));
|
||
|
|
||
|
// Make a copy of the key (recursive)
|
||
|
if (!regClassKey.CloneSubKey(pchSlash+1, szDriverNumber, TRUE))
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
return NETCONN_UNKNOWN_ERROR;
|
||
|
}
|
||
|
|
||
|
wsprintf(pszNewDriverBuf, "%s\\%s", szClass, szDriverNumber);
|
||
|
|
||
|
// Remove the "default" subkey if we just copied it (can't have 2 defaults)
|
||
|
if (regClassKey.OpenSubKey(szDriverNumber))
|
||
|
{
|
||
|
if (regClassKey.OpenSubKey("Ndi"))
|
||
|
{
|
||
|
RegDeleteKey(regClassKey.m_hKey, "Default");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NETCONN_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
// pszSubKey == "MSTCP", "VREDIR", "MSTCP\0000", etc.
|
||
|
HRESULT OpenNetEnumKey(CRegistry& reg, LPCSTR pszSubKey, REGSAM dwAccess)
|
||
|
{
|
||
|
CHAR szRegKey[MAX_PATH];
|
||
|
lstrcpy(szRegKey, "Enum\\Network\\");
|
||
|
lstrcat(szRegKey, pszSubKey);
|
||
|
|
||
|
if (!reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, dwAccess))
|
||
|
return NETCONN_UNKNOWN_ERROR;
|
||
|
|
||
|
return NETCONN_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// pszClass = "NetClient"
|
||
|
// pszDeviceID = "NWREDIR"
|
||
|
HRESULT DeleteClassKeyReferences(LPCSTR pszClass, LPCSTR pszDeviceID)
|
||
|
{
|
||
|
HRESULT hr = NETCONN_SUCCESS;
|
||
|
|
||
|
// Delete the class key(s)
|
||
|
CRegistry reg;
|
||
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class") &&
|
||
|
reg.OpenSubKey(pszClass))
|
||
|
{
|
||
|
TCHAR szNumber[20];
|
||
|
DWORD iClassItem = 0;
|
||
|
for (;;)
|
||
|
{
|
||
|
DWORD cchNumber = _countof(szNumber);
|
||
|
if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iClassItem, szNumber, &cchNumber, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
CRegistry regNumber;
|
||
|
if (regNumber.OpenKey(reg.m_hKey, szNumber))
|
||
|
{
|
||
|
CRegistry regNdi;
|
||
|
if (regNdi.OpenKey(regNumber.m_hKey, "Ndi"))
|
||
|
{
|
||
|
TCHAR szDeviceID[50];
|
||
|
if (regNdi.QueryStringValue("DeviceID", szDeviceID, _countof(szDeviceID)) &&
|
||
|
!lstrcmpi(szDeviceID, pszDeviceID))
|
||
|
{
|
||
|
regNdi.CloseKey();
|
||
|
regNumber.CloseKey();
|
||
|
RegDeleteKeyAndSubKeys(reg.m_hKey, szNumber);
|
||
|
hr = NETCONN_NEED_RESTART;
|
||
|
|
||
|
// Restart the search
|
||
|
iClassItem = 0;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iClassItem++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// pszClassKey is of the form "NetService\0000"
|
||
|
BOOL IsNetClassKeyReferenced(LPCSTR pszClassKey)
|
||
|
{
|
||
|
CRegistry reg;
|
||
|
CHAR szDeviceID[200];
|
||
|
DWORD iKey;
|
||
|
|
||
|
// Get the device ID
|
||
|
if (!reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class", KEY_READ))
|
||
|
goto done;
|
||
|
if (!reg.OpenSubKey(pszClassKey, KEY_READ))
|
||
|
goto done;
|
||
|
if (!reg.OpenSubKey("Ndi", KEY_READ))
|
||
|
goto done;
|
||
|
|
||
|
if (!reg.QueryStringValue("DeviceID", szDeviceID, _countof(szDeviceID)))
|
||
|
goto done;
|
||
|
|
||
|
if (!reg.OpenKey(HKEY_LOCAL_MACHINE, "Enum\\Network", KEY_READ))
|
||
|
goto done;
|
||
|
if (!reg.OpenSubKey(szDeviceID, KEY_READ))
|
||
|
goto done;
|
||
|
|
||
|
for (iKey = 0; ; iKey++)
|
||
|
{
|
||
|
CHAR szSubKey[60];
|
||
|
DWORD cbSubKey = _countof(szSubKey);
|
||
|
if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iKey, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL))
|
||
|
break;
|
||
|
|
||
|
CRegistry regSubKey;
|
||
|
if (regSubKey.OpenKey(reg.m_hKey, szSubKey, KEY_READ))
|
||
|
{
|
||
|
CHAR szDriver[60];
|
||
|
if (regSubKey.QueryStringValue("Driver", szDriver, _countof(szDriver)))
|
||
|
{
|
||
|
if (0 == lstrcmpi(szDriver, pszClassKey))
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Given a binding of one of the two following forms
|
||
|
// "MSTCP\0000"
|
||
|
// "Enum\Network\MSTCP\0000"
|
||
|
// and a device ID such as "MSTCP", returns TRUE if the binding is a binding
|
||
|
// of the given device, or FALSE if not.
|
||
|
BOOL WINAPI DoesBindingMatchDeviceID(LPCSTR pszBinding, LPCSTR pszDeviceID)
|
||
|
{
|
||
|
CHAR szTemp[40];
|
||
|
LPCSTR pszBoundDevice = FindPartialPath(pszBinding, 1); // skip "Enum\..." if present
|
||
|
lstrcpyn(szTemp, pszBoundDevice, _countof(szTemp));
|
||
|
LPSTR pchSlash = strchr(szTemp, '\\');
|
||
|
if (pchSlash != NULL)
|
||
|
*pchSlash = '\0';
|
||
|
return !lstrcmpi(szTemp, pszDeviceID);
|
||
|
}
|
||
|
|