|
|
/****************************************************************************
* * registry.c * * Copyright (c) 1992-1994 Microsoft Corporation * * This file contains functions to maintain registry entries for * kernel drivers installed via the drivers control panel applet. * * Note that the ONLY state maintained between calls here is whatever * state the registry and its handles maintain. * * The registry entries are structured as follows : * (see also winreg.h, winnt.h) * * HKEY_LOCAL_MACHINE * SYSTEM * CurrentControlSet * Services * DriverNode (eg sndblst) * Type = SERVICE_KERNEL_DRIVER (eg) * Group = "Base" * ErrorControl = SERVICE_ERROR_NORMAL * Start = SERVICE_SYSTEM_START | * SERVICE_DEMAND_START | * SERVICE_DISABLED * ... * Tag = A unique number ??? * * Parameters * Device0 * Interrupt = * Port = * DMAChannel = * * The Driver node is set up by the services manager when we call * CreateService but we have to insert the device data ourselves. * * * * The registry entries are shared between : * * The system loader (which uses the Services entry) * The kernel driver (which reads from the Device entry) * This component called from the drivers control panel applet * The service control manager * The Setup utility * * Security access * --------------- * * The driver determines whether it can perform configuration and * installation by whether it can get read and write access to the * service control manager. This is required to manipulate the kernel * driver database. * * Services controller * ------------------- * * The services controller is used because this is the only way we * are allowed to load and unload kernel drivers. Only the services * controller can call LoadDriver and UnloadDriver and not get 'access * denied'. * * Note also that we can't keep the services controller handle open * at the same time as the registry handle because then we can't get * write access (actually we only need KEY_CREATE_SUB_KEY access) to * our device parameters subkey. * ***************************************************************************/
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <winsvc.h>
#include <soundcfg.h>
#include "registry.h"
/***************************************************************************
* * Constants for accessing the registry * ***************************************************************************/
/*
* Path to service node key */
#define STR_SERVICES_NODE TEXT("SYSTEM\\CurrentControlSet\\Services\\")
/*
* Node sub-key for device parameters */
#define STR_DEVICE_DATA PARMS_SUBKEY
/*
* Name of Base group where sound drivers normally go */
#define STR_BASE_GROUP TEXT("Base")
/*
* Name of driver group for synthesizers * - we use our own name here to make sure * we are loaded after things like the PAS driver. (Base is a * known group and drivers in it are always loaded before unknown * groups like this one). */
#define STR_SYNTH_GROUP TEXT("Synthesizer Drivers")
/*
* Name of service */
#define STR_DRIVER TEXT("\\Driver\\")
/*
* Path to kernel drivers directory from system directory */
#define STR_DRIVERS_DIR TEXT("\\SystemRoot\\System32\\drivers\\")
/*
* Extension for drivers */
#define STR_SYS_EXT TEXT(".SYS")
BOOL DrvSaveParametersKey(PREG_ACCESS RegAccess) { TCHAR TempFilePath[MAX_PATH]; HKEY ParametersKey;
if (GetTempPath(MAX_PATH, TempFilePath) > MAX_PATH) { return FALSE; }
if (GetTempFileName(TempFilePath, TEXT("DRV"), 0, RegAccess->TempKeySaveFileName) == 0) { return FALSE; }
ParametersKey = DrvOpenRegKey(RegAccess->DriverName, NULL);
if (ParametersKey == NULL) { RegAccess->TempKeySaveFileName[0] = '\0'; return FALSE; }
if (ERROR_SUCCESS != RegSaveKey(ParametersKey, RegAccess->TempKeySaveFileName, NULL)) { RegCloseKey(ParametersKey); RegAccess->TempKeySaveFileName[0] = '\0'; return FALSE; }
RegCloseKey(ParametersKey);
return TRUE; }
BOOL DrvRestoreParametersKey(PREG_ACCESS RegAccess) { BOOL Rc; HKEY ParametersKey;
ParametersKey = DrvOpenRegKey(RegAccess->DriverName, NULL);
Rc = ParametersKey != NULL && ERROR_SUCCESS == RegRestoreKey(ParametersKey, RegAccess->TempKeySaveFileName, 0);
RegCloseKey(ParametersKey); DeleteFile(RegAccess->TempKeySaveFileName);
RegAccess->TempKeySaveFileName[0] = '\0';
return Rc; }
HKEY DrvOpenRegKey(LPCTSTR DriverName, LPCTSTR Path) { TCHAR RegistryPath[MAX_PATH]; HKEY NodeHandle;
//
// Create the path to our node
//
lstrcpy(RegistryPath, STR_SERVICES_NODE); lstrcat(RegistryPath, DriverName); lstrcat(RegistryPath, TEXT("\\")); lstrcat(RegistryPath, PARMS_SUBKEY); if (Path != NULL && lstrlen(Path) != 0) { lstrcat(RegistryPath, TEXT("\\")); lstrcat(RegistryPath, Path); }
//
// See if we can get a registry handle to our device data
//
if (RegCreateKey(HKEY_LOCAL_MACHINE, RegistryPath, &NodeHandle) != ERROR_SUCCESS) { return NULL; } else { return NodeHandle; } }
HKEY DrvCreateDeviceKey(LPCTSTR DriverName) { UINT i; HKEY hKey;
for (i = 0; ; i++) {
hKey = DrvOpenDeviceKey(DriverName, i);
if (hKey == NULL) { TCHAR DeviceKeyName[MAX_PATH];
wsprintf(DeviceKeyName, TEXT("Device%d"), i);
return DrvOpenRegKey(DriverName, DeviceKeyName); } else { RegCloseKey(hKey); } } }
HKEY DrvOpenDeviceKey(LPCTSTR DriverName, UINT n) { TCHAR DeviceKeyName[MAX_PATH]; HKEY hKeyParameters; HKEY hKeyReturn; DWORD SubKeySize;
SubKeySize = MAX_PATH;
hKeyParameters = DrvOpenRegKey(DriverName, NULL);
if (hKeyParameters == NULL) { return NULL; }
hKeyReturn = NULL;
if (ERROR_SUCCESS == RegEnumKeyEx(hKeyParameters, n, DeviceKeyName, &SubKeySize, NULL, NULL, NULL, NULL)) { RegOpenKey(hKeyParameters, DeviceKeyName, &hKeyReturn); }
RegCloseKey(hKeyParameters);
return hKeyReturn; }
SC_HANDLE DrvOpenService(PREG_ACCESS RegAccess) { SC_HANDLE Handle; Handle = OpenService(RegAccess->ServiceManagerHandle, RegAccess->DriverName, SERVICE_ALL_ACCESS);
#if 0
if (Handle == NULL) { char buf[100]; sprintf(buf, "OpenService failed code %d\n", GetLastError()); OutputDebugStringA(buf); } #endif
return Handle; }
void DrvCloseService(PREG_ACCESS RegAccess, SC_HANDLE ServiceHandle) { CloseServiceHandle(ServiceHandle); }
/***************************************************************************
* * Function : * DrvCreateServicesNode * * Parameters : * DriverNodeName The name of the service node. Same as the * name of the driver which must be * DriverNodeName.sys for the system to find it. * * DriverType Type of driver - see registry.h * * ServiceNodeKey Pointer to where to put returned handle * * Return code : * * Standard error code (see winerror.h) * * Description : * * Create the service node key * * The class name of the registry node is "" * ***************************************************************************/
BOOL DrvCreateServicesNode(LPTSTR DriverName, SOUND_KERNEL_MODE_DRIVER_TYPE DriverType, PREG_ACCESS RegAccess, BOOL Create) { SERVICE_STATUS ServiceStatus; SC_HANDLE ServiceHandle; // Handle to our driver 'service'
RegAccess->DriverName = DriverName;
//
// See if we can open the registry
//
if (RegAccess->ServiceManagerHandle == NULL) { RegAccess->ServiceManagerHandle = OpenSCManager( NULL, // This machine
NULL, // The active database
SC_MANAGER_ALL_ACCESS); // We want to create and change
if (RegAccess->ServiceManagerHandle == NULL) { return FALSE; } }
//
// Open our particular service
//
ServiceHandle = DrvOpenService(RegAccess);
//
// See if that worked
//
if (ServiceHandle == NULL && GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { if (Create) { SC_LOCK ServicesDatabaseLock; TCHAR ServiceName[MAX_PATH]; TCHAR BinaryPath[MAX_PATH];
lstrcpy(BinaryPath, STR_DRIVERS_DIR); lstrcat(BinaryPath, DriverName); lstrcat(BinaryPath, STR_SYS_EXT);
lstrcpy(ServiceName, STR_DRIVER); lstrcat(ServiceName, DriverName);
/*
* Lock the service controller database to avoid deadlocks * we have to loop because we can't wait */
for (ServicesDatabaseLock = NULL; (ServicesDatabaseLock = LockServiceDatabase(RegAccess->ServiceManagerHandle)) == NULL; Sleep(100)) { }
/*
* Create the service */
ServiceHandle = CreateService( RegAccess->ServiceManagerHandle, DriverName, // Service name
NULL, // ???
SERVICE_ALL_ACCESS, // Full access
SERVICE_KERNEL_DRIVER, // Kernel driver
SERVICE_DEMAND_START, // Start at sys start
SERVICE_ERROR_NORMAL, // Not a disaster if fails
BinaryPath, // Default path
DriverType == SoundDriverTypeSynth ? STR_SYNTH_GROUP : // Driver group
STR_BASE_GROUP, NULL, // do not want TAG information
TEXT("\0"), // No dependencies
NULL, // ServiceName, // Driver object - optional
NULL); // No password
UnlockServiceDatabase(ServicesDatabaseLock); #if DBG
if (ServiceHandle == NULL) { TCHAR buf[100]; wsprintf(buf, TEXT("CreateService failed code %d\n"), GetLastError()); OutputDebugString(buf); } #endif
} }
//
// Check at least that it's a device driver
//
if (ServiceHandle != NULL) { if (!QueryServiceStatus( ServiceHandle, &ServiceStatus) || ServiceStatus.dwServiceType != SERVICE_KERNEL_DRIVER) {
//
// Doesn't look like ours
//
CloseServiceHandle(RegAccess->ServiceManagerHandle); RegAccess->ServiceManagerHandle = NULL; DrvCloseService(RegAccess, ServiceHandle); return FALSE; }
}
if (ServiceHandle == NULL) { //
// Leave the SC manager handle open. We use the presence of this
// handle to test whether the driver can be configured (ie whether we
// have the access rights to get into the SC manager).
//
return FALSE; } else { //
// We can't keep this handle open (even though we'd like to) because
// we need write access to the registry node created so that
// we can add device parameters
//
DrvCloseService(RegAccess, ServiceHandle); return TRUE; } }
/***************************************************************************
* * Function : * DrvCloseServicesNode * * Parameters : * ServiceNodeKey * * Return code : * * Standard error code (see winerror.h) * * Description : * * Close our handle * ***************************************************************************/
VOID DrvCloseServiceManager( PREG_ACCESS RegAccess) { if (RegAccess->ServiceManagerHandle != NULL) { CloseServiceHandle(RegAccess->ServiceManagerHandle); RegAccess->ServiceManagerHandle = NULL; }
if (RegAccess->TempKeySaveFileName[0] != '\0') { DeleteFile(RegAccess->TempKeySaveFileName); } }
/***************************************************************************
* * Function : * DrvDeleteServicesNode * * Parameters : * DeviceName * * Return code : * * TRUE = success, FALSE = failed * * Description : * * Delete our node using the handle proviced * ***************************************************************************/
BOOL DrvDeleteServicesNode( PREG_ACCESS RegAccess) { BOOL Success; SC_LOCK ServicesDatabaseLock; SC_HANDLE ServiceHandle;
/*
** Delete the service node and free tha handle ** (Note the service cannot be deleted until all handles are closed) */
ServiceHandle = DrvOpenService(RegAccess);
if (ServiceHandle == NULL) { LONG Error; Error = GetLastError(); if (Error == ERROR_SERVICE_DOES_NOT_EXIST) { /*
** It's already gone ! */ return TRUE; } else { return FALSE; // It was there but something went wrong
} }
/*
* Lock the service controller database to avoid deadlocks * we have to loop because we can't wait */
for (ServicesDatabaseLock = NULL; (ServicesDatabaseLock = LockServiceDatabase(RegAccess->ServiceManagerHandle)) == NULL; Sleep(100)) { }
Success = DeleteService(ServiceHandle);
UnlockServiceDatabase(ServicesDatabaseLock);
DrvCloseService(RegAccess, ServiceHandle);
return Success; }
/***************************************************************************
* * Function : * DrvNumberOfDevices * * Parameters : * ServiceNodeKey Handle to the device services node key * NumberOfDevices DWORD value to set to number of subkeys * * Return code : * * Standard error code (see winerror.h) * * Description : * Find out how many device keys we have * ***************************************************************************/ LONG DrvNumberOfDevices( PREG_ACCESS RegAccess, LPDWORD NumberOfDevices) { HKEY ParmsKey; LONG ReturnCode; DWORD Junk; DWORD cchClassName; TCHAR ClassName[100]; DWORD cbJunk = 0; FILETIME FileTime;
*NumberOfDevices = 0; ParmsKey = DrvOpenRegKey(RegAccess->DriverName, NULL);
if (ParmsKey == NULL) { return ERROR_FILE_NOT_FOUND; }
cchClassName = 100; ReturnCode = RegQueryInfoKey( ParmsKey, ClassName, &cchClassName, NULL, NumberOfDevices, &Junk, &Junk, &Junk, &Junk, &Junk, &Junk, &FileTime);
RegCloseKey(ParmsKey);
return ReturnCode;
}
/***************************************************************************
* * Function : * DrvSetDeviceParameter * * Parameters : * ServiceNodeKey Handle to the device services node key * ValueName Name of value to set * Value DWORD value to set * * Return code : * * Standard error code (see winerror.h) * * Description : * * Add the value to the device parameters section under the * services node. * This section is created if it does not already exist. * ***************************************************************************/
LONG DrvSetDeviceIdParameter( PREG_ACCESS RegAccess, UINT DeviceNumber, LPTSTR ValueName, DWORD Value) { HKEY ParmsKey; LONG ReturnCode;
//
// ALWAYS create a key 0 - that way old drivers work
//
if (DeviceNumber == 0) { ParmsKey = DrvOpenRegKey(RegAccess->DriverName, TEXT("Device0")); } else { ParmsKey = DrvOpenDeviceKey(RegAccess->DriverName, DeviceNumber); }
if (ParmsKey == NULL) { return ERROR_FILE_NOT_FOUND; }
//
// Write the value
//
ReturnCode = RegSetValueEx(ParmsKey, // Registry handle
ValueName, // Name of item
0, // Reserved 0
REG_DWORD, // Data type
(LPBYTE)&Value, // The value
sizeof(Value)); // Data length
//
// Free the handles we created
//
RegCloseKey(ParmsKey);
return ReturnCode; }
/***************************************************************************
* * Function : * DrvQueryDeviceIdParameter * * Parameters : * ServiceNodeKey Handle to the device services node key * ValueName Name of value to query * pValue Returned value * * Return code : * * Standard error code (see winerror.h) * * Description : * * Add the value to the device parameters section under the * services node. * This section is created if it does not already exist. * ***************************************************************************/
LONG DrvQueryDeviceIdParameter( PREG_ACCESS RegAccess, UINT DeviceNumber, LPTSTR ValueName, PDWORD pValue) { HKEY ParmsKey; LONG ReturnCode; DWORD Index; DWORD Type; DWORD Value; DWORD ValueLength;
ParmsKey = DrvOpenDeviceKey(RegAccess->DriverName, DeviceNumber);
if (ParmsKey == NULL) { return ERROR_FILE_NOT_FOUND; }
ValueLength = sizeof(Value);
ReturnCode = RegQueryValueEx(ParmsKey, ValueName, NULL, &Type, (LPBYTE)&Value, &ValueLength);
RegCloseKey(ParmsKey);
if (ReturnCode == ERROR_SUCCESS) {
if (Type == REG_DWORD) { *pValue = Value; } else { ReturnCode = ERROR_FILE_NOT_FOUND; } }
return ReturnCode; }
/***************************************************************************
* * Function : * DrvLoadKernelDriver * * Parameters : * Drivername Name of driver to load * * Return code : * * TRUE if successful, otherwise FALSE * * Description : * * Call StartService to load the driver. This assumes the services * name is the driver name * ***************************************************************************/
BOOL DrvLoadKernelDriver( PREG_ACCESS RegAccess) { SC_HANDLE ServiceHandle; BOOL Success; ServiceHandle = DrvOpenService(RegAccess);
if (ServiceHandle == NULL) { return FALSE; }
/*
* StartService causes the system to try to load the kernel driver */
Success = StartService(ServiceHandle, 0, NULL);
/*
* If this was successful we can change the start type to system * start */
if (Success) { Success = ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, SERVICE_SYSTEM_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } DrvCloseService(RegAccess, ServiceHandle); return Success; }
/***************************************************************************
* * Function : * DrvUnLoadKernelDriver * * Parameters : * RegAccess Access variables to registry and Service control * manager * * Return code : * * TRUE if successful, otherwise FALSE * * Description : * * Call ControlService to unload the driver. This assumes the services * name is the driver name * ***************************************************************************/
BOOL DrvUnloadKernelDriver( PREG_ACCESS RegAccess) { SERVICE_STATUS ServiceStatus; SC_HANDLE ServiceHandle; BOOL Success;
ServiceHandle = DrvOpenService(RegAccess); if (ServiceHandle == NULL) { return GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST; }
/*
* Set it not to load at system start until we've reconfigured */
Success = ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (Success) { /*
* Don't try to unload if it's not loaded */
if (DrvIsDriverLoaded(RegAccess)) {
/*
* Note that the driver object name will not be found if * the driver is not loaded. However, the services manager may * get in first and decide that the driver file does not exist. */
Success = ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
}
}
DrvCloseService(RegAccess, ServiceHandle); return Success; }
/***************************************************************************
* * Function : * * DrvIsDriverLoaded * * Parameters : * * RegAccess Access variables to registry and Service control * manager * * Return code : * * TRUE if successful, otherwise FALSE * * Description : * * See if a service by our name is started. * Note - this assumes that we think our service is installed * ***************************************************************************/ BOOL DrvIsDriverLoaded( PREG_ACCESS RegAccess) { SERVICE_STATUS ServiceStatus; SC_HANDLE ServiceHandle; BOOL Success; ServiceHandle = DrvOpenService(RegAccess); if (ServiceHandle == NULL) { return FALSE; }
if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) { DrvCloseService(RegAccess, ServiceHandle); return FALSE; }
Success = ServiceStatus.dwServiceType == SERVICE_KERNEL_DRIVER && (ServiceStatus.dwCurrentState == SERVICE_RUNNING || ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING);
DrvCloseService(RegAccess, ServiceHandle); return Success; }
/***************************************************************************
* * Function : * * DrvConfigureDriver * * Parameters : * * RegAccess Access variables to registry and Service control * manager * * DriverName Name of the driver * * DriverType Type of driver (see registry.h) * * SetParms Callback to set the registry parameters * * Context Context value for callback * * Return code : * * TRUE if successful, otherwise FALSE * * Description : * * Performs the necessary operations to (re) configure a driver : * * 1. If the driver is already installed : * * Unload it if necessary * * Set its start type to Demand until we know we're safe * (This is so the system won't load a bad config if we crash) * * 2. If the driver is not installed create its service entry in the * registry. * * 3. Run the callback to set up the driver's parameters * * 4. Load the driver * * 5. If the load returns success set the start type to System start * ***************************************************************************/
BOOL DrvConfigureDriver( PREG_ACCESS RegAccess, LPTSTR DriverName, SOUND_KERNEL_MODE_DRIVER_TYPE DriverType, BOOL (* SetParms )(PVOID), PVOID Context) { return
/*
* If there isn't a services node create one - this is done first * because this is how the driver name gets into the REG_ACCESS * structure */
DrvCreateServicesNode( DriverName, DriverType, RegAccess, TRUE)
&&
/*
* Unload driver if it's loaded */
DrvUnloadKernelDriver(RegAccess)
&&
/*
* Run the callback */
(SetParms == NULL || (*SetParms)(Context))
&&
/*
* Try reloading the driver */
DrvLoadKernelDriver(RegAccess)
;
}
/***************************************************************************
* * Function : * * DrvRemoveDriver * * Parameters : * * RegAccess Access variables to registry and Service control * manager * * Return code : * * DRVCNF_CANCEL - Error occurred * * DRVCNF_OK - Registry entry delete but driver wasn't loaded * * DRVCNF_RESTART - Driver unloaded and registry entry deleted * * Description : * * Unload the driver and remove its service control entry * ***************************************************************************/
LRESULT DrvRemoveDriver( PREG_ACCESS RegAccess) { BOOL Loaded;
Loaded = DrvIsDriverLoaded(RegAccess);
if (Loaded) { DrvUnloadKernelDriver(RegAccess); } if (DrvDeleteServicesNode(RegAccess)) { return Loaded ? DRVCNF_RESTART : DRVCNF_OK; } else { return DRVCNF_CANCEL; } }
/***************************************************************************
* * Function : * * DrvSetMapperName * * Parameters : * * Mapping Name Name of mapping from midimap.cfg to use * * Return code : * * None - may or may not work * * Description : * * Tell the midi mapper which map to use * ***************************************************************************/
VOID DrvSetMapperName(LPTSTR SetupName) { HKEY hKey;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Midimap"), 0L, KEY_WRITE, &hKey)) {
RegSetValueEx( hKey, TEXT("Mapping Name"), 0L, REG_SZ, (LPBYTE)SetupName, sizeof(TCHAR) * (1 + lstrlen(SetupName)));
RegCloseKey(hKey); }
return; }
|