/* REMOVE.C ** ** Copyright (C) Microsoft, 1990, All Rights Reserved. ** ** Multimedia Control Panel Applet for removing ** device drivers. See the ispec doc DRIVERS.DOC for more information. ** ** History: ** ** Thu Oct 17 1991 -by- Sanjaya ** Created. Originally part of drivers.c */ #include #include #include #include #include #include #include #include #include #include "drivers.h" #include "sulib.h" BOOL SetValidAlias (LPTSTR, LPTSTR); static CONST TCHAR gszRunDLL32Path[] = TEXT("\"%s\\RUNDLL32.EXE\" \"%s\\MMSYS.CPL\",mmWOW64MediaClassInstallerA \"%s\"%d"); static CONST TCHAR gszAliasValue[] = TEXT("Alias"); static CONST TCHAR gszAliasWOW64Value[] = TEXT("AliasWOW64"); static CONST TCHAR gszWaveWOW64Value[] = TEXT("WOW64"); #ifdef DOBOOT BOOL FindBootDriver (TCHAR *); PSTR strstri (LPTSTR, LPTSTR); #endif // DOBOOT /* * RemoveService(szFile) * * Remove the service corresponding to the file szFile * * returns TRUE if successful, FALSE otherwise */ BOOL RemoveService(LPTSTR szFile) { SC_HANDLE SCManagerHandle; SC_HANDLE ServiceHandle; TCHAR ServiceName[MAX_PATH]; BOOL Status = FALSE; /* * Extract the service name from the file name */ { TCHAR drive[MAX_PATH], directory[MAX_PATH], ext[MAX_PATH]; lsplitpath(szFile, drive, directory, ServiceName, ext); } /* * First try and obtain a handle to the service controller */ SCManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (SCManagerHandle == NULL) { TCHAR szMesg[MAXSTR]; TCHAR szMesg2[MAXSTR]; LoadString(myInstance, IDS_INSUFFICIENT_PRIVILEGE, szMesg, sizeof(szMesg)/sizeof(TCHAR)); wsprintf(szMesg2, szMesg, szFile); MessageBox(hMesgBoxParent, szMesg2, szRemove, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); return FALSE; } ServiceHandle = OpenService(SCManagerHandle, ServiceName, SERVICE_ALL_ACCESS); if (ServiceHandle != NULL) { SERVICE_STATUS ServiceStatus; SC_LOCK ServicesDatabaseLock; /* * Stop the service if possible. */ ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus); /* * Delete the service. * We aren't detecting if we can just carry on. */ /* * Lock the service controller database to avoid deadlocks * we have to loop because we can't wait */ for (ServicesDatabaseLock = NULL; (ServicesDatabaseLock = LockServiceDatabase(SCManagerHandle)) == NULL; Sleep(100)) { } Status = DeleteService(ServiceHandle); UnlockServiceDatabase(ServicesDatabaseLock); CloseServiceHandle(ServiceHandle); } else { /* * It's possible there was no services entry so the driver * wasn't really installed after all. */ LONG Error = GetLastError(); if (Error == ERROR_FILE_NOT_FOUND || Error == ERROR_PATH_NOT_FOUND || Error == ERROR_SERVICE_DOES_NOT_EXIST) { Status = TRUE; } } CloseServiceHandle(SCManagerHandle); return Status; } /* ** PostRemove() ** ** Mark an installed driver for removal later AND remove the driver's entry ** in SYSTEM.INI to avoid conflicts when we add or remove later. */ LONG_PTR PostRemove(PIDRIVER pIDriver, BOOL bLookAtRelated) { TCHAR *keystr; TCHAR allkeystr[MAXSTR]; TCHAR szfile[MAX_PATH]; HANDLE hDriver; LONG_PTR Status = DRVCNF_CANCEL; LPTSTR pstr; GetPrivateProfileString(pIDriver->szSection, pIDriver->szAlias, pIDriver->szFile, pIDriver->szFile, MAX_PATH, szSysIni); /* * Remove parameters from file name */ if (pIDriver->szFile) { for ( pstr=pIDriver->szFile; *pstr && (*pstr!=COMMA) && (*pstr!=SPACE); pstr++ ) ; *pstr = TEXT('\0'); } if (bLookAtRelated && (!bRelated || pIDriver->bRelated)) wcscpy(szRestartDrv, pIDriver->szDesc); /* * If it's a kernel driver remove it from the config registry * and services controller */ if (pIDriver->KernelDriver) { Status = RemoveService(pIDriver->szFile) ? DRVCNF_RESTART : DRVCNF_CANCEL; if (Status == DRVCNF_CANCEL) { return DRVCNF_CANCEL; } } else { hDriver = OpenDriver(pIDriver->wszAlias, pIDriver->wszSection, 0L); if (hDriver) { /* * Removal can fail so don't mark as deleted in this case */ Status = SendDriverMessage(hDriver, DRV_REMOVE, 0L, 0L); CloseDriver(hDriver, 0L, 0L); if (Status == DRVCNF_CANCEL) { return DRVCNF_CANCEL; } } } // Remove the driver from the treeview, // but don't free its structure // RemoveIDriver (hAdvDlgTree, pIDriver, FALSE); if (bLookAtRelated) { TCHAR allkeystr[MAXSTR]; if (GetPrivateProfileString(szRelatedDesc, pIDriver->szAlias, allkeystr, allkeystr, sizeof(allkeystr) / sizeof(TCHAR), szControlIni)) { int i; TCHAR szTemp[MAXSTR]; for (i = 1; infParseField(allkeystr, i, szTemp);i++) { PIDRIVER pid; if ((pid = FindIDriverByName (szTemp)) != NULL) { if (PostRemove (pid, FALSE) == DRVCNF_RESTART) { Status = DRVCNF_RESTART; } } } } } // Remove the driver entry from SYSTEM.INI so you don't // conflict with other drivers. GetPrivateProfileString(pIDriver->szSection, NULL, NULL, allkeystr, sizeof(allkeystr) / sizeof(TCHAR), szSysIni); keystr = allkeystr; while (wcslen(keystr) > 0) { GetPrivateProfileString(pIDriver->szSection, keystr, NULL, szfile, sizeof(szfile) / sizeof(TCHAR), szSysIni); if (!FileNameCmp(pIDriver->szFile, szfile)) RemoveDriverEntry(keystr, pIDriver->szFile, pIDriver->szSection, bLookAtRelated); keystr = &keystr[wcslen(keystr) + sizeof(TCHAR)]; } return Status; } void RemoveDriverEntry (LPTSTR szKey, LPTSTR szFile, LPTSTR szSection, BOOL bLookAtRelated) { /* * Remove entry for loading driver */ WritePrivateProfileString(szSection, szKey, NULL, szSysIni); /* * Delete entry for parameters for this driver */ WriteProfileString(szFile, szKey, NULL); /* * Remove entry which says this is a user driver (as opposed to * a pre-installed one). */ WritePrivateProfileString(szUserDrivers, szKey, NULL, szControlIni); /* * Remove description */ WritePrivateProfileString(szDriversDesc, szFile, NULL, szControlIni); /* * Remove links to related drivers */ WritePrivateProfileString(szRelatedDesc, szKey, NULL, szControlIni); #ifdef DOBOOT FindBootDriver(szKey); #endif // DOBOOT if (bLookAtRelated) SetValidAlias(szKey, szSection); } /* * SetValidAlias() * * Check to see if the alias removed would create a hole in the device * numbering scheme. If so switch the last device number with the deleted one. */ BOOL SetValidAlias(LPTSTR pstrType, LPTSTR pstrSection) { TCHAR *keystr; static TCHAR allkeystr[MAXSTR]; static TCHAR szExKey[MAXSTR], szExFile[MAXSTR], szExDesc[MAXSTR]; BOOL bfound = FALSE, bExchange = FALSE; int val, maxval = 0, typelen, len; /* * Getting length of alias */ len = typelen = wcslen(pstrType); // If the last TCHAR on the type is a number don't consider it if (pstrType[typelen - 1] > TEXT('0') && pstrType[typelen - 1] <= TEXT('9')) typelen--; // Get all the aliases in the drivers section GetPrivateProfileString(pstrSection, NULL, NULL, allkeystr, sizeof(allkeystr) / sizeof(TCHAR), szSysIni); keystr = allkeystr; while (*keystr != TEXT('\0')) { // Compare the root of the aliases if (!_wcsnicmp(keystr, pstrType, typelen) && ((keystr[typelen] <= TEXT('9') && keystr[typelen] > TEXT('0')) || keystr[typelen] == TEXT('\0'))) { //We found a common alias bfound = TRUE; val = _wtoi(&keystr[typelen]); if (val > maxval) { maxval = val; wcscpy(szExKey, keystr); } } //Pointer to next alias keystr = &keystr[wcslen(keystr) + sizeof(TCHAR)]; } //If we found one if (bfound) { if (len == typelen) bExchange = TRUE; else if (_wtoi(&pstrType[typelen]) < maxval) bExchange = TRUE; // We need to exchange it with the one we found if (bExchange) { //Exchanging the one in the drivers section in system.ini GetPrivateProfileString(pstrSection, szExKey, NULL, szExFile, sizeof(szExFile) / sizeof(TCHAR), szSysIni); WritePrivateProfileString(pstrSection, szExKey, NULL, szSysIni); WritePrivateProfileString(pstrSection, pstrType, szExFile, szSysIni); #ifdef TRASHDRIVERDESC //Exchanging the one in the drivers description section of control.ini GetPrivateProfileString(szDriversDesc, szExKey, NULL, szExDesc, sizeof(szExFile) / sizeof(TCHAR), szControlIni); WritePrivateProfileString(szDriversDesc, szExKey, NULL, szControlIni); WritePrivateProfileString(szDriversDesc, pstrType, szExDesc, szControlIni); #endif //If any related drivers were present under old alias switch them GetPrivateProfileString(szRelatedDesc, szExKey, NULL, szExDesc, sizeof(szExFile) / sizeof(TCHAR), szControlIni); if (wcslen(szExDesc)) { WritePrivateProfileString(szRelatedDesc, szExKey, NULL, szControlIni); WritePrivateProfileString(szRelatedDesc, pstrType, szExDesc, szControlIni); } //If user installed driver under old alias switch them GetPrivateProfileString(szUserDrivers, szExKey, NULL, szExDesc, sizeof(szExFile) / sizeof(TCHAR), szControlIni); if (wcslen(szExDesc)) { WritePrivateProfileString(szUserDrivers, szExKey, NULL, szControlIni); WritePrivateProfileString(szUserDrivers, pstrType, szExDesc, szControlIni); } #ifdef DOBOOT if (FindBootDriver(szExKey)) { static TCHAR szTemp[MAXSTR]; GetPrivateProfileString(szBoot, szDrivers, szTemp, szTemp, sizeof(szTemp) / sizeof(TCHAR), szSysIni); strcat(szTemp, TEXT(" ")); strcat(szTemp, pstrType); WritePrivateProfileString(szBoot, szDrivers, szTemp, szSysIni); } #endif // DOBOOT } } return(bExchange); } int FileNameCmp(TCHAR far *pch1, TCHAR far *pch2) { LPTSTR pchEOS; while (*pch1 == TEXT(' ')) pch1++; // eat spaces while (*pch2 == TEXT(' ')) pch2++; // eat spaces for (pchEOS = pch1; *pchEOS && *pchEOS != TEXT(' '); pchEOS++); return _wcsnicmp(pch1, pch2, (size_t)(pchEOS - pch1)); } #ifdef DOBOOT PSTR strstri(LPTSTR pszStr, LPTSTR pszKey) { while (pszStr) if (!_strnicmp(pszStr, pszKey, lstrlen(pszKey))) return(pszStr); else pszStr++; return(NULL); } /* * FindBootDriver() * Checks to see if the driver alias is on the drivers line of the * boot section. If so the alias is removed from the line. */ BOOL FindBootDriver(TCHAR *szKey) { TCHAR *ptr; int wKeyLen = (int)wcslen(szKey); TCHAR *endkey; static TCHAR szDriverline[MAXSTR]; GetPrivateProfileString(TEXT("boot"), TEXT("drivers"), szDriverline, szDriverline, MAX_PATH, szSysIni); ptr = strstri(szDriverline, szKey); if (ptr) { if ((((ptr != szDriverline) && (*(ptr - 1) == TEXT(' ') )) || (ptr == szDriverline)) && (*(ptr + wKeyLen) == TEXT(' ') || *(ptr + wKeyLen) == NULL)) { endkey = ptr + wKeyLen; while (*endkey) *ptr++ = *endkey++; *ptr = NULL; WritePrivateProfileString(TEXT("boot"), TEXT("drivers"), szDriverline, szSysIni); return(TRUE); } } return(FALSE); } #endif // DOBOOT // Steal use of function in midi.c to delete a reg subtree. LONG SHRegDeleteKey(HKEY hKey, LPCTSTR lpSubKey); //**************************************************************************** // Function: mystrtok() // // Purpose: Returns a pointer to the next token in a string. // // Parameters: // SrcString String containing token(s) // Seps Set of delimiter characters // State Pointer to a char* to hold state info // Return Code: // Ptr to next token, or NULL if no tokens left // // Comments: // Fixes problem with standard strtok, which can't be called recursively. // //**************************************************************************** LPTSTR mystrtok(LPTSTR SrcString, LPCTSTR Seps, LPTSTR FAR *State) { LPTSTR ThisString; LPTSTR NextString; // If Seps is NULL, use default separators if (!Seps) { Seps = TEXT(" ,\t"); // space, comma, tab chars } if (SrcString) ThisString = SrcString; else ThisString = *State; // Find beginning of the current string ThisString = ThisString + wcsspn(ThisString,Seps); if (ThisString[0]==TEXT('\0')) return NULL; // Find the end of the current string NextString = ThisString + wcscspn(ThisString,Seps); if (NextString[0]!=TEXT('\0')) { *NextString++=TEXT('\0'); } *State = NextString; return ThisString; } BOOL RemoveDriver(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { BOOL bRet = FALSE; // Return value TCHAR szDriverKey[MAX_PATH]; // Value of Driver's key in Enum branch TCHAR *pszDrvInst; // Driver's instance, e.g. "0000", "0001", etc. HKEY hkDevReg = NULL; // Key to Driver portion of registry (e.g. classguid\0000) HKEY hkDrivers32 = NULL; // Key to Drivers32 portion of registry HKEY hkDrivers = NULL; // Key to classguid\0000\Drivers TCHAR szSubClasses[256]; // List of subclasses to process TCHAR *strtok_State; // strtok state TCHAR *pszClass; // Information about e.g. classguid\0000\Drivers\wave HKEY hkClass; DWORD idxR3DriverName; // Information about e.g. classguid\0000\Drivers\wave\foo.drv HKEY hkR3DriverName; TCHAR szR3DriverName[64]; TCHAR szAlias[64]; // Alias in Drivers32 (e.g. wave1) TCHAR szDriver[64]; // Name of driver DWORD cbLen; LPCTSTR szAliasStringToUse; // Pointer to the Alias value name to use BOOL bIsWOW64Process = FALSE;// TRUE if we're running under WOW64 // // If we're running in WOW64, we need to use a different Alias string so that // we don't overwrite the 64-bit alias string // if( IsWow64Process(GetCurrentProcess(), &bIsWOW64Process) && bIsWOW64Process ) { szAliasStringToUse = gszAliasWOW64Value; } else { szAliasStringToUse = gszAliasValue; } // Get the Drivers key value under the device's Enum branch, // e.g. something like "{4D36E96C-E325-11CE-BFC1-08002BE10318}\0000" SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DRIVER , NULL, (LPBYTE)szDriverKey, MAX_PATH, NULL); // Get everything after the last \ character pszDrvInst = wcsrchr(szDriverKey,TEXT('\\')); if (!pszDrvInst) { goto RemoveDrivers32_exit; } pszDrvInst++; // Now pszDrvInst points to a string with the Driver Instance, e.g. "0000" // Open the Drivers32 section of the registry if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32"), &hkDrivers32)) { goto RemoveDrivers32_exit; } // Open the Driver reg key hkDevReg = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); if (hkDevReg == INVALID_HANDLE_VALUE) { goto RemoveDrivers32_exit; } // Enumerate through supporter classes in the Drivers subkey if (RegOpenKey(hkDevReg, TEXT("Drivers"), &hkDrivers)) { goto RemoveDrivers32_exit; } // Read the SubClasses key to determine which subclasses to process cbLen=sizeof(szSubClasses); if (RegQueryValueEx(hkDrivers, TEXT("Subclasses"), NULL, NULL, (LPBYTE)szSubClasses, &cbLen)) { goto RemoveDrivers32_exit; } // Enumerate all the subclasses for ( pszClass = mystrtok(szSubClasses,NULL,&strtok_State); pszClass; pszClass = mystrtok(NULL,NULL,&strtok_State) ) { #ifdef _WIN64 // // Check for magic WaveWOW64 value if( 0 == _wcsnicmp( pszClass, gszWaveWOW64Value, wcslen(gszWaveWOW64Value) ) ) { // Thunk the installation to the 32-bit mmsys.cpl installer mmWOW64ThunkMediaClassInstaller(DIF_REMOVE, DeviceInfoSet, DeviceInfoData); continue; } #endif //_WIN64 // Open up each subclass if (RegOpenKey(hkDrivers, pszClass, &hkClass)) { continue; } // Under each class is a set of driver name subkeys. // For each driver (e.g. foo1.drv, foo2.drv, etc.) for (idxR3DriverName = 0; !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR)); idxR3DriverName++) { // Open the key to the driver name if (RegOpenKey(hkClass, szR3DriverName, &hkR3DriverName)) { continue; } // Get the value of Driver under the driver name key cbLen = sizeof(szDriver); if (!RegQueryValueEx(hkR3DriverName, TEXT("Driver"), NULL, NULL, (LPBYTE)szDriver, &cbLen)) { // Send the driver a DRV_REMOVE message to the driver HANDLE hDriver; hDriver = OpenDriver(szDriver, NULL, 0L); if (hDriver) { SendDriverMessage(hDriver, DRV_REMOVE, 0L, 0L); CloseDriver(hDriver, 0L, 0L); } } // Get the value of Alias under the driver name key cbLen = sizeof(szAlias); if (!RegQueryValueEx(hkR3DriverName, szAliasStringToUse, NULL, NULL, (LPBYTE)szAlias, &cbLen)) { // Delete the corresponding entry in Drivers32 RegDeleteValue(hkDrivers32,szAlias); } // Close the Driver Name key RegCloseKey(hkR3DriverName); } // Close the class key RegCloseKey(hkClass); } bRet = TRUE; RemoveDrivers32_exit: if (hkDrivers32) RegCloseKey(hkDrivers32); if (hkDevReg) RegCloseKey(hkDevReg); if (hkDrivers) RegCloseKey(hkDrivers); return bRet; } // The driver's private registry section is located in something like: // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96C-E325-11CE-BFC1-08002BE10318}\xxxx // where xxxx is the device instance (e.g. 0000, 0001, etc.) // These last four digits are used to index into the driver's MediaResources section. // For example, suppose a device has a driver instance // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96C-E325-11CE-BFC1-08002BE10318}\0001 // and under that entry there is a Drivers\wave\foo.drv, meaning that the foo.drv driver supports a wave // API. // In this case, there would be an entry in // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MediaResources\wave\foo.drv<0001> // // On removal, we need to delete that entry. BOOL RemoveMediaResources(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { BOOL bRet = FALSE; // Return value TCHAR szDriverKey[MAX_PATH]; // Value of Driver's key in Enum branch TCHAR *pszDrvInst; // Driver's instance, e.g. "0000", "0001", etc. HKEY hkDevReg = NULL; // Key to Driver portion of registry (e.g. classguid\0000) HKEY hkDrivers = NULL; // Key to classguid\0000\Drivers HKEY hkMR = NULL; // Handle to MediaResources section TCHAR szSubClasses[256]; // List of subclasses to process TCHAR *strtok_State; // strtok state TCHAR *pszClass; // Information about e.g. classguid\0000\Drivers\wave HKEY hkClass; DWORD idxR3DriverName; // Information about e.g. classguid\0000\Drivers\wave\foo.drv HKEY hkR3DriverName; TCHAR szR3DriverName[64]; TCHAR szDriver[64]; // Driver name (e.g. foo.drv) DWORD cbLen; // Size of szDriver TCHAR szDevNode[MAX_PATH+1]; // Path to driver's reg entry TCHAR szSoftwareKey[MAX_PATH+1]; // Value of SOFTWAREKEY // Open Media Resources section of registry if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_MEDIARESOURCES, &hkMR)) { goto RemoveMediaResources_exit; } // Get the Drivers key value under the device's Enum branch, // e.g. something like "{4D36E96C-E325-11CE-BFC1-08002BE10318}\0000" SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DRIVER , NULL, (LPBYTE)szDriverKey, MAX_PATH, NULL); // Get everything after the last \ character pszDrvInst = wcsrchr(szDriverKey,TEXT('\\')); if (!pszDrvInst) { goto RemoveMediaResources_exit; } pszDrvInst++; // Now pszDrvInst points to a string with the Driver Instance, e.g. "0000" // Get full path to driver key wsprintf(szDevNode, TEXT("%s\\%s"), REGSTR_PATH_CLASS_NT, (LPTSTR)szDriverKey); // Open the Driver reg key hkDevReg = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); if (hkDevReg == INVALID_HANDLE_VALUE) { goto RemoveMediaResources_exit; } // Enumerate through supporter classes in the Drivers subkey if (RegOpenKey(hkDevReg, TEXT("Drivers"), &hkDrivers)) { goto RemoveMediaResources_exit; } // Read the SubClasses key to determine which subclasses to process cbLen=sizeof(szSubClasses); if (RegQueryValueEx(hkDrivers, TEXT("Subclasses"), NULL, NULL, (LPBYTE)szSubClasses, &cbLen)) { goto RemoveMediaResources_exit; } // Enumerate all the subclasses for ( pszClass = mystrtok(szSubClasses,NULL,&strtok_State); pszClass; pszClass = mystrtok(NULL,NULL,&strtok_State) ) { if (RegOpenKey(hkDrivers, pszClass, &hkClass)) { continue; } // Under each class is a set of driver name subkeys. // For each driver (e.g. foo1.drv, foo2.drv, etc.) for (idxR3DriverName = 0; !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR)); idxR3DriverName++) { // Open the key to the driver name if (RegOpenKey(hkClass, szR3DriverName, &hkR3DriverName)) { continue; } // Get the value of Driver in under the driver name key cbLen = sizeof(szDriver); if (!RegQueryValueEx(hkR3DriverName, TEXT("Driver"), NULL, NULL, (LPBYTE)szDriver, &cbLen)) { TCHAR szR3Path[256]; // Create a path to the MediaResources entry to be deleted wsprintf(szR3Path, TEXT("%s\\%s\\%s<%s>"), REGSTR_PATH_MEDIARESOURCES, (LPTSTR)pszClass, (LPTSTR)szDriver, (LPTSTR)pszDrvInst); // Delete the key SHRegDeleteKey(HKEY_LOCAL_MACHINE, szR3Path); } // Close the Driver Name key RegCloseKey(hkR3DriverName); } // Close the class key in the devnode RegCloseKey(hkClass); // Backup mechanism, in case we missed something. // This shouldn't be necessary, but Win98 does it. // Open the class key in MediaResources if (RegOpenKey(hkMR, pszClass, &hkClass)) { continue; } // Count the number of subkeys under the class key // We're gonna do this backwards because we'll be deleting keys later for (idxR3DriverName = 0; !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR)); idxR3DriverName++) { ; } // For each driver subkey, working backwards. // Subkeys are e.g. msacm.iac2, msacm.imaadpcm, etc. for (idxR3DriverName--; ((int)idxR3DriverName >= 0) && !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR)); idxR3DriverName--) { // Open the driver key if (RegOpenKey(hkClass, szR3DriverName, &hkR3DriverName)) { continue; } // Query the value of "SOFTWAREKEY" szSoftwareKey[0]=TEXT('\0'); // Init to safe value in case call fails cbLen = sizeof(szSoftwareKey); RegQueryValueEx(hkR3DriverName, TEXT("SOFTWAREKEY"), NULL, NULL, (LPBYTE)szSoftwareKey, &cbLen); // Close now, since we might delete in next line RegCloseKey(hkR3DriverName); // If the value of "SOFTWAREKEY" matches the path to the devnode, delete the key if (!lstrcmpi(szSoftwareKey, szDevNode)) { SHRegDeleteKey(hkClass, szR3DriverName); } } // Close the class key in MediaResources RegCloseKey(hkClass); } bRet = TRUE; RemoveMediaResources_exit: if (hkDevReg) RegCloseKey(hkDevReg); if (hkDrivers) RegCloseKey(hkDrivers); if (hkMR) RegCloseKey(hkMR); return bRet; } // Clear out entries in the Driver's branch of the registry, e.g. in {4D36E96C-E325-11CE-BFC1-08002BE10318}\0000 BOOL RemoveDriverInfo(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { HKEY hkDevReg; // Key to Driver portion of registry (e.g. classguid\0000) // Remove entries in the driver's reg section hkDevReg = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); if (hkDevReg == INVALID_HANDLE_VALUE) { return FALSE; } // Delete any entries that might cause trouble RegDeleteValue(hkDevReg,REGSTR_VAL_DEVLOADER); RegDeleteValue(hkDevReg,REGSTR_VAL_DRIVER); RegDeleteValue(hkDevReg,REGSTR_VAL_ENUMPROPPAGES); RegDeleteValue(hkDevReg,TEXT("NTMPDriver")); RegDeleteValue(hkDevReg,TEXT("AssociatedFilters")); RegDeleteValue(hkDevReg,TEXT("FDMA")); RegDeleteValue(hkDevReg,TEXT("DriverType")); // Blow away the Drivers subtree SHRegDeleteKey(hkDevReg,TEXT("Drivers")); // For future use, allow a key under which everything gets blown away SHRegDeleteKey(hkDevReg,TEXT("UnretainedSettings")); RegCloseKey(hkDevReg); return TRUE; } // Clear out entries in the Device's Enum branch of the registry: BOOL RemoveDeviceInfo(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { // Remove the Driver key. It looks something like "Driver = {4D36E96C-E325-11CE-BFC1-08002BE10318}\0000" // !!NO don't remove driver key, or else on driver upgrade system loses track of node & creates a new one // SetupDiSetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DRIVER , NULL, 0); // Remove the Service key. // Make sure before doing anything else that there is no service property for // this device instance. This allows us to know whether we should clean up the // device instance if we boot and find that it's no longer present. SetupDiSetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, NULL, 0); return TRUE; } /* 5/14/98 andyraf for NT5 */ /* Media_RemoveDevice * * This function gets called on driver removal (DIF_REMOVE) and driver installation (DIF_INSTALL). * It cleans up all the registry entries associated with the driver. */ DWORD Media_RemoveDevice(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { #if 0 // Don't know how to do this on NT5 if ((diFunction == DIF_REMOVE) && (lpdi->Flags & DI_CLASSINSTALLPARAMS) && (((LPREMOVEDEVICE_PARAMS)lpdi->lpClassInstallParams)->dwFlags & DI_REMOVEDEVICE_CONFIGSPECIFIC)) { return ERROR_DI_DO_DEFAULT; } // Not needed on NT5?? CleanupDummySysIniDevs(); //remove the wave=*.drv and midi=*.drv dummy devices. #endif #if 0 // We'll allow people to remove these drivers for now if (IsSpecialDriver(DeviceInfoSet, DeviceInfoData)) { return NO_ERROR; } #endif // Send DRV_REMOVE to each driver and clean out Drivers32 section of registry RemoveDriver (DeviceInfoSet, DeviceInfoData); // Clean out MediaResources section of registry RemoveMediaResources(DeviceInfoSet, DeviceInfoData); // Clean out driver's classguid\instance section of registry RemoveDriverInfo (DeviceInfoSet, DeviceInfoData); // Clean out device's enum section of registry RemoveDeviceInfo (DeviceInfoSet, DeviceInfoData); return ERROR_DI_DO_DEFAULT; } #if 0 // Unused at present BOOL AddDrivers32(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { BOOL bRet = FALSE; // Return value TCHAR szDriverKey[MAX_PATH]; // Value of Driver's key in Enum branch TCHAR *pszDrvInst; // Driver's instance, e.g. "0000", "0001", etc. HKEY hkDevReg = NULL; // Key to Driver portion of registry (e.g. classguid\0000) HKEY hkDrivers32 = NULL; // Key to Drivers32 portion of registry HKEY hkDrivers = NULL; // Key to classguid\0000\Drivers HKEY hkDriversDesc = NULL; // Key to drivers.desc portion of registry TCHAR szSubClasses[256]; // List of subclasses to process TCHAR *strtok_State; // strtok state TCHAR *pszClass; // Information about e.g. classguid\0000\Drivers\wave HKEY hkClass; DWORD idxR3DriverName; // Information about e.g. classguid\0000\Drivers\wave\foo.drv HKEY hkR3DriverName; TCHAR szR3DriverName[64]; TCHAR szAlias[64]; // Alias in Drivers32 (e.g. wave1) TCHAR szDriver[64]; // Name of driver TCHAR szDescription[MAX_PATH]; DWORD cbLen; // Get the Drivers key value under the device's Enum branch, // e.g. something like "{4D36E96C-E325-11CE-BFC1-08002BE10318}\0000" SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DRIVER , NULL, (LPBYTE)szDriverKey, MAX_PATH, NULL); // Get everything after the last \ character pszDrvInst = strrchr(szDriverKey,TEXT('\\')); if (!pszDrvInst) { goto RemoveDrivers32_exit; } pszDrvInst++; // Now pszDrvInst points to a string with the Driver Instance, e.g. "0000" // Open the Drivers32 section of the registry if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32"), &hkDrivers32)) { goto RemoveDrivers32_exit; } // If we're adding a driver, need to open key to drivers.desc also if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\drivers.desc"), &hkDriversDesc)) { goto RemoveDrivers32_exit; } // Open the Driver reg key hkDevReg = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); if (hkDevReg == INVALID_HANDLE_VALUE) { goto RemoveDrivers32_exit; } // Enumerate through supporter classes in the Drivers subkey if (RegOpenKey(hkDevReg, TEXT("Drivers"), &hkDrivers)) { goto RemoveDrivers32_exit; } // Read the SubClasses key to determine which subclasses to process cbLen=sizeof(szSubClasses); if (RegQueryValueEx(hkDrivers, TEXT("Subclasses"), NULL, NULL, (LPBYTE)szSubClasses, &cbLen)) { goto RemoveDrivers32_exit; } // Enumerate all the subclasses for ( pszClass = mystrtok(szSubClasses,NULL,&strtok_State); pszClass; pszClass = mystrtok(NULL,NULL,&strtok_State) ) { // Open up each subclass if (RegOpenKey(hkDrivers, pszClass, &hkClass)) { continue; } // Under each class is a set of driver name subkeys. // For each driver (e.g. foo1.drv, foo2.drv, etc.) for (idxR3DriverName = 0; !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR)); idxR3DriverName++) { // Open the key to the driver name if (RegOpenKey(hkClass, szR3DriverName, &hkR3DriverName)) { continue; } // Get driver name cbLen = sizeof(szDriver); if (!RegQueryValueEx(hkR3DriverName, TEXT("Driver"), NULL, NULL, (LPBYTE)szDriver, &cbLen)) { // Create the alias wsprintf(szAlias,TEXT("%s.%s<%s>"),(LPTSTR)pszClass,(LPTSTR)szDriver,(LPTSTR)pszDrvInst); // Write into Drivers32 RegSetValueExA(hkDrivers32,szAlias,0,REG_SZ,(PBYTE)szDriver,(wcslen(szDriver)*sizeof(TCHAR)) + sizeof(TCHAR)); // Write alias back into driver's reg area RegSetValueExA(hkR3DriverName,TEXT("Alias"),0,REG_SZ,(PBYTE)szAlias,(wcslen(szAlias)*sizeof(TCHAR)) + sizeof(TCHAR)); } // Write out Description // Get driver description cbLen = sizeof(szDescription); if (!RegQueryValueEx(hkR3DriverName, TEXT("Description"), NULL, NULL, (LPBYTE)szDescription, &cbLen)) { RegSetValueExA(hkDriversDesc,szDriver,0,REG_SZ,(PBYTE)szDescription,(wcslen(szDescription)*sizeof(TCHAR)) + sizeof(TCHAR)); } // Close the Driver Name key RegCloseKey(hkR3DriverName); } // Close the class key RegCloseKey(hkClass); } bRet = TRUE; RemoveDrivers32_exit: if (hkDrivers32) RegCloseKey(hkDrivers32); if (hkDevReg) RegCloseKey(hkDevReg); if (hkDrivers) RegCloseKey(hkDrivers); if (hkDriversDesc) RegCloseKey(hkDriversDesc); return bRet; } #endif #if 0 // Unused at present // The driver's private registry section is located in something like: // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96C-E325-11CE-BFC1-08002BE10318}\xxxx // where xxxx is the device instance (e.g. 0000, 0001, etc.) // These last four digits are used to index into the driver's MediaResources section. // For example, suppose a device has a driver instance // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96C-E325-11CE-BFC1-08002BE10318}\0001 // and under that entry there is a Drivers\wave\foo.drv, meaning that the foo.drv driver supports a wave // API. // In this case, there would be an entry in // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MediaResources\wave\foo.drv<0001> // // On removal, we need to delete that entry. BOOL AddMediaResources(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { BOOL bRet = FALSE; // Return value TCHAR szDriverKey[MAX_PATH]; // Value of Driver's key in Enum branch TCHAR *pszDrvInst; // Driver's instance, e.g. "0000", "0001", etc. HKEY hkDevReg = NULL; // Key to Driver portion of registry (e.g. classguid\0000) HKEY hkDrivers = NULL; // Key to classguid\0000\Drivers HKEY hkMR = NULL; // Handle to MediaResources section TCHAR szSubClasses[256]; // List of subclasses to process TCHAR *strtok_State; // strtok state TCHAR *pszClass; // Information about e.g. classguid\0000\Drivers\wave HKEY hkClass; DWORD idxR3DriverName; // Information about e.g. classguid\0000\Drivers\wave\foo.drv HKEY hkR3DriverName; TCHAR szR3DriverName[64]; TCHAR szDriver[64]; // Driver name (e.g. foo.drv) DWORD cbLen; // Size of szDriver TCHAR szDevNode[MAX_PATH+1]; // Path to driver's reg entry TCHAR szSoftwareKey[MAX_PATH+1]; // Value of SOFTWAREKEY // Open Media Resources section of registry if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_MEDIARESOURCES, &hkMR)) { goto RemoveMediaResources_exit; } // Get the Drivers key value under the device's Enum branch, // e.g. something like "{4D36E96C-E325-11CE-BFC1-08002BE10318}\0000" SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DRIVER , NULL, (LPBYTE)szDriverKey, MAX_PATH, NULL); // Get everything after the last \ character pszDrvInst = strrchr(szDriverKey,TEXT('\\')); if (!pszDrvInst) { goto RemoveMediaResources_exit; } pszDrvInst++; // Now pszDrvInst points to a string with the Driver Instance, e.g. "0000" // Get full path to driver key wsprintf(szDevNode, TEXT("%s\\%s"), REGSTR_PATH_CLASS_NT, (LPTSTR)szDriverKey); // Open the Driver reg key hkDevReg = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); if (hkDevReg == INVALID_HANDLE_VALUE) { goto RemoveMediaResources_exit; } // Enumerate through supporter classes in the Drivers subkey if (RegOpenKey(hkDevReg, TEXT("Drivers"), &hkDrivers)) { goto RemoveMediaResources_exit; } // Read the SubClasses key to determine which subclasses to process cbLen=sizeof(szSubClasses); if (RegQueryValueEx(hkDrivers, TEXT("Subclasses"), NULL, NULL, (LPBYTE)szSubClasses, &cbLen)) { goto RemoveMediaResources_exit; } // Enumerate all the subclasses for ( pszClass = mystrtok(szSubClasses,NULL,&strtok_State); pszClass; pszClass = mystrtok(NULL,NULL,&strtok_State) ) { if (RegOpenKey(hkDrivers, pszClass, &hkClass)) { continue; } // Under each class is a set of driver name subkeys. // For each driver (e.g. foo1.drv, foo2.drv, etc.) for (idxR3DriverName = 0; !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR)); idxR3DriverName++) { // Open the key to the driver name if (RegOpenKey(hkClass, szR3DriverName, &hkR3DriverName)) { continue; } // Get the value of Driver in under the driver name key cbLen = sizeof(szDriver); if (!RegQueryValueEx(hkR3DriverName, TEXT("Driver"), NULL, NULL, (LPBYTE)szDriver, &cbLen)) { HKEY hkMRClass; HKEY hkMRDriver; TCHAR szMRDriver[256]; // Create the class key if it doesn't already exist if (!RegCreateKey(hkMR,pszClass,&hkMRClass)) { continue; } // Create the driver key if it doesn't already exist wsprintf(szMRDriver, TEXT("%s<%s>"), (LPTSTR)szDriver, (LPTSTR)pszDrvInst); if (!RegCreateKey(hkMRClass,szMRDriver,&hkMRDriver)) { RegCloseKey(hkMRClass); continue; } // Migrate the values from the driver into the MediaResources key // First write out driver name // FEATURE: Not implemented yet. RegCloseKey(hkMRClass); RegCloseKey(hkMRDriver); } // Close the Driver Name key RegCloseKey(hkR3DriverName); } // Close the class key in the devnode RegCloseKey(hkClass); } bRet = TRUE; RemoveMediaResources_exit: if (hkDevReg) RegCloseKey(hkDevReg); if (hkDrivers) RegCloseKey(hkDrivers); if (hkMR) RegCloseKey(hkMR); return bRet; } #endif #ifdef _WIN64 void mmWOW64ThunkMediaClassInstaller(DWORD dwInstallationFlag, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData) { DWORD dwInstanceIDSize = 0; DWORD dwWow64DirSize = 0; LPTSTR tcstrDeviceInstanceId = NULL; LPTSTR tcstrWow64Directory = NULL; LPTSTR tcstrRunDLL32Path = NULL; PROCESS_INFORMATION processInformation; STARTUPINFO startupInfo; // Get the device instance ID SetupDiGetDeviceInstanceId( DeviceInfoSet, DeviceInfoData, NULL, 0, &dwInstanceIDSize ); if( 0 == dwInstanceIDSize ) { // Unable to retrieve required size - return return; } tcstrDeviceInstanceId = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * dwInstanceIDSize); if( NULL == tcstrDeviceInstanceId || 0 == SetupDiGetDeviceInstanceId( DeviceInfoSet, DeviceInfoData, tcstrDeviceInstanceId, dwInstanceIDSize, NULL ) ) { // Unable to retrieve device instance ID - return LocalFree((HANDLE)tcstrDeviceInstanceId); return; } dwWow64DirSize = GetSystemWow64Directory( NULL, 0 ); if( 0 == dwWow64DirSize ) { // Unable to retrieve the Wow64Directory size - return LocalFree((HANDLE)tcstrDeviceInstanceId); return; } tcstrWow64Directory = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * dwWow64DirSize); if( NULL == tcstrWow64Directory || 0 == GetSystemWow64Directory( tcstrWow64Directory, dwWow64DirSize ) ) { // Unable to retrieve the Wow64Directory - return LocalFree((HANDLE)tcstrWow64Directory); LocalFree((HANDLE)tcstrDeviceInstanceId); return; } // The full path is the size of the format string, plus two times the length of the system path, // plus the length of the instance ID, plus 10 (maximum length of a DWORD) tcstrRunDLL32Path = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * (wcslen(gszRunDLL32Path) + dwWow64DirSize * 2 + dwInstanceIDSize + 10)); if( NULL == tcstrRunDLL32Path ) { // Unable to allocate RunDLL32 path - return LocalFree((HANDLE)tcstrWow64Directory); LocalFree((HANDLE)tcstrDeviceInstanceId); return; } // Create the command line wsprintf( tcstrRunDLL32Path, gszRunDLL32Path, tcstrWow64Directory, tcstrWow64Directory, tcstrDeviceInstanceId, dwInstallationFlag ); // Initialize the CreateProcess structures ZeroMemory( &processInformation, sizeof(PROCESS_INFORMATION) ); ZeroMemory( &startupInfo, sizeof(STARTUPINFO) ); startupInfo.cb = sizeof(STARTUPINFO); if( CreateProcess( NULL, tcstrRunDLL32Path, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInformation ) ) { // Wait for the process to end WaitForSingleObject( processInformation.hProcess, 5000 ); // Close process and thread handles. CloseHandle( processInformation.hProcess ); CloseHandle( processInformation.hThread ); } // Free up the strings we allocated LocalFree((HANDLE)tcstrRunDLL32Path); LocalFree((HANDLE)tcstrWow64Directory); LocalFree((HANDLE)tcstrDeviceInstanceId); } #endif //_WIN64