|
|
//
// 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) { ASSERT(pszBinding != NULL);
CHAR szRegKey[MAX_PATH]; static const CHAR szEnumString[] = "Enum\\Network\\"; static const CHAR szBindingsString[] = "\\Bindings"; int cRemaining = sizeof(szRegKey) - (sizeof(szEnumString) + sizeof(szBindingsString));
if (lstrlen(pszBinding) >= cRemaining) return; // Bail out
lstrcpy(szRegKey, szEnumString); lstrcat(szRegKey, pszBinding); int cchMainEnumKey = lstrlen(szRegKey); lstrcat(szRegKey, szBindingsString);
// 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) { ASSERT(pszClass != NULL);
CRegistry regClassRoot; CHAR szRegClassRoot[260]; static const CHAR szClassString[] = "System\\CurrentControlSet\\Services\\Class\\"; int cRemaining = sizeof(szRegClassRoot) - sizeof(szClassString);
if (lstrlen(pszClass) >= cRemaining) return FALSE; // Bail out
lstrcpy(szRegClassRoot, szClassString); 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]; static const CHAR szClassString[] = "System\\CurrentControlSet\\Services\\Class\\"; int cRemaining = sizeof(szRegKey) - (sizeof(szClassString) + ((pszSubKey)?(lstrlen(pszSubKey) + 1):(0)));
if (lstrlen(pszClass) >= cRemaining) return NETCONN_INVALID_ARGUMENT; // Bail out
lstrcpy(szRegKey, szClassString); 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) { ASSERT(pszSubKey != NULL);
CHAR szRegKey[MAX_PATH]; static const CHAR szEnumString[] = "Enum\\Network\\"; int cRemaining = sizeof(szRegKey) - sizeof(szEnumString);
if (lstrlen(pszSubKey) >= cRemaining) return NETCONN_INVALID_ARGUMENT; // Bail out
lstrcpy(szRegKey, szEnumString); 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); }
|