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.
1445 lines
48 KiB
1445 lines
48 KiB
/* 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 <windows.h>
|
|
#include <mmsystem.h>
|
|
#include <winsvc.h>
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <cpl.h>
|
|
#include <cphelp.h>
|
|
#include <regstr.h>
|
|
|
|
#include "drivers.h"
|
|
#include "sulib.h"
|
|
#include "mmcpl.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))
|
|
{
|
|
wcsncpy(szRestartDrv, pIDriver->szDesc, ARRAYSIZE(szRestartDrv));
|
|
szRestartDrv[ARRAYSIZE(szRestartDrv)-1] = TEXT('\0'); // Make sure there is a NULL terminator
|
|
}
|
|
|
|
/*
|
|
* 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, SIZEOF(szTemp)) == ERROR_SUCCESS); 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) + 1];
|
|
}
|
|
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) + 1];
|
|
}
|
|
//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 && (hkDevReg!=INVALID_HANDLE_VALUE))
|
|
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
|