Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1484 lines
47 KiB

/*************************************************************************
*
* INSTALL.C
*
* Copyright (C) Microsoft, 1991, All Rights Reserved.
*
* History:
*
* Thu Oct 17 1991 -by- Sanjaya
* Created. Culled out of drivers.c
*
*************************************************************************/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <winsvc.h>
#include <memory.h>
#include <string.h>
#include <cpl.h>
#include <cphelp.h>
#include <stdlib.h>
#include "drivers.h"
#include "sulib.h"
BOOL GetValidAlias (PSTR, PSTR);
BOOL SelectInstalled (HWND, PIDRIVER, LPSTR, HDEVINFO, PSP_DEVINFO_DATA);
void InitDrvConfigInfo (LPDRVCONFIGINFO, PIDRIVER );
BOOL InstallDrivers (HWND, HWND, PSTR);
void RemoveAlreadyInstalled (PSTR, PSTR);
void CheckIniDrivers (PSTR, PSTR);
void RemoveDriverParams (LPSTR, LPSTR);
void InsertNewIDriverNodeInList(PIDRIVER *, PIDRIVER);
void DestroyIDriverNodeList(PIDRIVER, BOOL, BOOL);
/*
***************************************************************
* Global strings
***************************************************************
*/
CONST CHAR gszAnsiDriversSubkeyName[] = "Drivers";
CONST CHAR gszAnsiSubClassesValue[] = "SubClasses";
CONST CHAR gszAnsiDescriptionValue[] = "Description";
CONST CHAR gszAnsiDriverValue[] = "Driver";
CONST CHAR gszAnsiAliasValue[] = "Alias";
/**************************************************************************
*
* InstallDrivers()
*
* Install a driver and set of driver types.
*
* Parameters :
* hwnd - Window handle of the main drivers.cpl windows
* hwndAvail - Handle of the 'available drivers' dialog window
* pstrKey - Key name of the inf section item we are installing
*
* This routine calls itself recursively to install related drivers
* (as listed in the .inf file).
*
**************************************************************************/
BOOL InstallDrivers(HWND hWnd, HWND hWndAvail, PSTR pstrKey)
{
IDRIVER IDTemplate; // temporary for installing, removing, etc.
PIDRIVER pIDriver=NULL;
int n;
char szTypes[MAXSTR];
char szType[MAXSTR];
char szParams[MAXSTR];
szTypes[0] = '\0';
hMesgBoxParent = hWndAvail;
/*
* mmAddNewDriver needs a buffer for all types we've actually installed
* User critical errors will pop up a task modal
*/
IDTemplate.bRelated = FALSE;
IDTemplate.szRemove[0] = TEXT('\0');
/*
* Do the copying and extract the list of types (WAVE, MIDI, ...)
* and the other driver data
*/
if (!mmAddNewDriver(pstrKey, szTypes, &IDTemplate))
return FALSE;
szTypes[lstrlen(szTypes)-1] = '\0'; // Remove space left at end
RemoveAlreadyInstalled(IDTemplate.szFile, IDTemplate.szSection);
/*
* At this point we assume the drivers were actually copied.
* Now we need to add them to the installed list.
* For each driver type we create an IDRIVER and add to the listbox
*/
for (n = 1; infParseField(szTypes, n, szType); n++)
{
/*
* Find a valid alias for this device (eg Wave2). This is
* used as the key in the [MCI] or [drivers] section.
*/
if (GetValidAlias(szType, IDTemplate.szSection) == FALSE)
{
/*
* Exceeded the maximum, tell the user
*/
PSTR pstrMessage;
char szApp[MAXSTR];
char szMessage[MAXSTR];
LoadString(myInstance,
IDS_CONFIGURE_DRIVER,
szApp,
sizeof(szApp));
LoadString(myInstance,
IDS_TOO_MANY_DRIVERS,
szMessage,
sizeof(szMessage));
if (NULL !=
(pstrMessage =
(PSTR)LocalAlloc(LPTR,
sizeof(szMessage) + lstrlen(szType))))
{
wsprintf(pstrMessage, szMessage, (LPSTR)szType);
MessageBox(hWndAvail,
pstrMessage,
szApp,
MB_OK | MB_ICONEXCLAMATION|MB_TASKMODAL);
LocalFree((HANDLE)pstrMessage);
}
continue;
}
if ( (pIDriver = (PIDRIVER)LocalAlloc(LPTR, sizeof(IDRIVER))) != NULL)
{
/*
* Copy all fields
*/
memcpy(pIDriver, &IDTemplate, sizeof(IDRIVER));
strncpy(pIDriver->szAlias, szType, sizeof(pIDriver->szAlias));
pIDriver->szAlias[sizeof(pIDriver->szAlias) - 1] = '\0';
mbstowcs(pIDriver->wszAlias, pIDriver->szAlias, MAX_PATH);
/*
* Want only one instance of each driver to show up in the list
* of installed drivers. Thus for the remaining drivers just
* place an entry in the drivers section of system.ini
*/
if ( n > 1) {
if (strlen(szParams) != 0 && !pIDriver->KernelDriver) {
/*
* Write their parameters to a section bearing their
* file name with an alias reflecting their alias
*/
WriteProfileString(pIDriver->szFile,
pIDriver->szAlias,
szParams);
}
WritePrivateProfileString(pIDriver->szSection,
pIDriver->szAlias,
pIDriver->szFile,
szSysIni);
} else {
/*
* Reduce to just the driver name
*/
RemoveDriverParams(pIDriver->szFile, szParams);
mbstowcs(pIDriver->wszFile, pIDriver->szFile, MAX_PATH);
if (strlen(szParams) != 0 && !pIDriver->KernelDriver) {
/*
* Write their parameters to a section bearing their
* file name with an alias reflecting their alias
*/
WriteProfileString(pIDriver->szFile,
pIDriver->szAlias,
szParams);
}
WritePrivateProfileString(pIDriver->szSection,
pIDriver->szAlias,
pIDriver->szFile,
szSysIni);
/*
* Call the driver to see if it can be configured
* and configure it if it can be
*/
if (!SelectInstalled(hWndAvail, pIDriver, szParams, INVALID_HANDLE_VALUE, NULL))
{
/*
* Error talking to driver
*/
WritePrivateProfileString(pIDriver->szSection,
pIDriver->szAlias,
NULL,
szSysIni);
WriteProfileString(pIDriver->szFile,
pIDriver->szAlias,
NULL);
RemoveIDriver (hAdvDlgTree, pIDriver, TRUE);
return FALSE;
}
/*
* for displaying the driver desc. in the restart mesg
*/
if (!bRelated || pIDriver->bRelated) {
strcpy(szRestartDrv, pIDriver->szDesc);
}
/*
* We need to write out the driver description to the
* control.ini section [Userinstallable.drivers]
* so we can differentiate between user and system drivers
*
* This is tested by the function UserInstalled when
* the user tries to remove a driver and merely
* affects which message the user gets when being
* asked to confirm removal (non user-installed drivers
* are described as being necessary to the system).
*/
WritePrivateProfileString(szUserDrivers,
pIDriver->szAlias,
pIDriver->szFile,
szControlIni);
/*
* Update [related.desc] section of control.ini :
*
* ALIAS=driver name list
*
* When the driver whose alias is ALIAS is removed
* the drivers in the name list will also be removed.
* These were the drivers in the related drivers list
* when the driver is installed.
*/
WritePrivateProfileString(szRelatedDesc,
pIDriver->szAlias,
pIDriver->szRemove,
szControlIni);
/*
* Cache the description string in control.ini in the
* drivers description section.
*
* The key is the driver file name + extension.
*/
WritePrivateProfileString(szDriversDesc,
pIDriver->szFile,
pIDriver->szDesc,
szControlIni);
#ifdef DOBOOT // We don't do the boot section on NT
if (bInstallBootLine) {
szTemp[MAXSTR];
GetPrivateProfileString(szBoot,
szDrivers,
szTemp,
szTemp,
sizeof(szTemp),
szSysIni);
strcat(szTemp, " ");
strcat(szTemp, pIDriver->szAlias);
WritePrivateProfileString(szBoot,
szDrivers,
szTemp,
szSysIni);
bInstallBootLine = FALSE;
}
#endif // DOBOOT
}
}
else
return FALSE; //ERROR
}
/*
* If no types were added then fail
*/
if (pIDriver == NULL) {
return FALSE;
}
/*
* If there are related drivers listed in the .inf section to install
* then install them now by calling ourselves. Use IDTemplate which
* is where mmAddNewDriver put the data.
*/
if (IDTemplate.bRelated == TRUE) {
int i;
char szTemp[MAXSTR];
/*
* Tell file copying to abort rather than put up errors
*/
bCopyingRelated = TRUE;
for (i = 1; infParseField(IDTemplate.szRelated, i, szTemp);i++) {
InstallDrivers(hWnd, hWndAvail, szTemp);
}
}
return TRUE;
}
/************************************************************************
*
* SelectInstalled()
*
* Check if the driver can be configured and configure it if it can be.
*
* hwnd - Our window - parent for driver to make its config window
* pIDriver - info about the driver
* params - the drivers parameters from the .inf file.
* DeviceInfoSet - Optionally, specifies the set containing the PnP device
* being installed. Specify INVALID_HANDLE_VALUE is this
* parameter is not present.
* DeviceInfoData - Optionally, specifies the PnP device being installed
* (ignored if DeviceInfoSet is not specified).
*
* Returns FALSE if an error occurred, otherwise TRUE. GetLastError() may
* be called to determine the cause of the failure.
*
************************************************************************/
BOOL SelectInstalled(HWND hwnd, PIDRIVER pIDriver, LPSTR pszParams, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData)
{
DRVCONFIGINFO DrvConfigInfo;
HANDLE hDriver;
BOOL Success = FALSE;
DWORD dwTagId;
DWORD Err = ERROR_GEN_FAILURE; // pick a half-way reasonable default.
wsStartWait();
/*
* If it's a kernel driver call the services controller to
* install the driver (unless it's a PnP device, in which case
* SetupDiInstallDevice would've already handled any necessary
* service installation).
*/
if (pIDriver->KernelDriver) {
SC_HANDLE SCManagerHandle;
SC_HANDLE ServiceHandle;
char ServiceName[MAX_PATH];
char BinaryPath[MAX_PATH];
/*
* These drivers are not configurable
*/
pIDriver->fQueryable = 0;
/*
* If this is a PnP device, then there's nothing we need to do.
*/
if(DeviceInfoSet != INVALID_HANDLE_VALUE) {
wsEndWait();
return TRUE;
}
/*
* The services controller will create the registry node to
* which we can add the device parameters value
*/
strcpy(BinaryPath, "\\SystemRoot\\system32\\drivers\\");
strcat(BinaryPath, pIDriver->szFile);
/*
* First try and obtain a handle to the service controller
*/
SCManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (SCManagerHandle != NULL) {
SC_LOCK ServicesDatabaseLock;
/*
* 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)) {
}
{
char drive[MAX_PATH], directory[MAX_PATH], ext[MAX_PATH];
_splitpath(pIDriver->szFile, drive, directory, ServiceName, ext);
}
if(!(ServiceHandle = CreateService(SCManagerHandle,
ServiceName,
NULL,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
BinaryPath,
"Base",
&dwTagId,
"\0",
NULL,
NULL))) {
Err = GetLastError();
}
UnlockServiceDatabase(ServicesDatabaseLock);
if (ServiceHandle != NULL) {
/*
* Try to write the parameters to the registry if there
* are any
*/
if (strlen(pszParams)) {
HKEY ParmsKey;
char RegPath[MAX_PATH];
strcpy(RegPath, "\\SYSTEM\\CurrentControlSet\\Services\\");
strcat(RegPath, ServiceName);
strcat(RegPath, "\\Parameters");
Success = RegCreateKey(HKEY_LOCAL_MACHINE,
RegPath,
&ParmsKey) == ERROR_SUCCESS &&
RegSetValue(ParmsKey,
"",
REG_SZ,
pszParams,
strlen(pszParams)) == ERROR_SUCCESS &&
RegCloseKey(ParmsKey) == ERROR_SUCCESS;
if(!Success) {
Err = GetLastError();
}
} else {
Success = TRUE;
}
/*
* Service created so try and start it
*/
if (Success) {
/*
* We tell them to restart just in case
*/
bRestart = TRUE;
/*
* Load the kernel driver by starting the service.
* If this is successful it should be safe to let
* the system load the driver at system start so
* we change the start type.
*/
Success =
StartService(ServiceHandle, 0, NULL) &&
ChangeServiceConfig(ServiceHandle,
SERVICE_NO_CHANGE,
SERVICE_SYSTEM_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
if (!Success) {
char szMesg[MAXSTR];
char szMesg2[MAXSTR];
char szTitle[50];
Err = GetLastError();
/*
* Uninstall driver if we couldn't load it
*/
for (ServicesDatabaseLock = NULL;
(ServicesDatabaseLock =
LockServiceDatabase(SCManagerHandle))
== NULL;
Sleep(100)) {
}
DeleteService(ServiceHandle);
UnlockServiceDatabase(ServicesDatabaseLock);
/*
* Tell the user there was a configuration error
* (our best guess).
*/
LoadString(myInstance, IDS_DRIVER_CONFIG_ERROR, szMesg, sizeof(szMesg));
LoadString(myInstance, IDS_CONFIGURE_DRIVER, szTitle, sizeof(szTitle));
wsprintf(szMesg2, szMesg, FileName(pIDriver->szFile));
MessageBox(hMesgBoxParent, szMesg2, szTitle, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
}
}
CloseServiceHandle(ServiceHandle);
}
CloseServiceHandle(SCManagerHandle);
} else {
//
// Couldn't open Service Control Manager.
//
Err = GetLastError();
}
} else {
/*
* Put up a message if the driver can't be loaded or doesn't
* respond favourably to the DRV_INSTALL message.
*/
BOOL bPutUpMessage;
bPutUpMessage = FALSE;
/*
* See if we can open the driver
*/
hDriver = OpenDriver(pIDriver->wszFile, NULL, 0L);
if (hDriver)
{
Success = TRUE;
InitDrvConfigInfo(&DrvConfigInfo, pIDriver);
/*
* See if activating the driver will require restarting the
* system.
*
* Also check the driver wants to install (it may not
* have the right privilege level).
*/
if(DeviceInfoSet != INVALID_HANDLE_VALUE) {
SP_DEVINSTALL_PARAMS DeviceInstallParams;
//
// This is a PnP device--send it our new PnP install message.
//
switch(SendDriverMessage(hDriver,
DRV_PNPINSTALL,
(LONG)DeviceInfoSet,
(LONG)DeviceInfoData))
{
case DRVCNF_RESTART :
//
// The installation was successful, but a reboot is required.
// Ensure that the 'need reboot' flag in the device's installation
// parameters.
//
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
DeviceInstallParams.Flags |= DI_NEEDREBOOT;
SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
}
//
// Let fall through to processing of successful installation.
//
case DRVCNF_OK :
//
// The device was successfully configured.
//
Success = TRUE;
break;
case DRVCNF_CANCEL :
//
// The driver did not want to install. Unfortunately, we don't have fine enough
// granularity in the return codes to distinguish between the case where the
// user cancelled, and the case where the installation failed for some other
// reason. Just leave the failure code as ERROR_GEN_FAILURE.
//
bPutUpMessage = TRUE;
Success = FALSE;
break;
}
} else {
//
// This isn't a PnP device--configure it via legacy mechanism.
//
switch (SendDriverMessage(hDriver,
DRV_INSTALL,
0L,
(LONG)(LPDRVCONFIGINFO)&DrvConfigInfo))
{
case DRVCNF_RESTART:
bRestart = TRUE;
break;
case DRVCNF_CANCEL:
/*
* The driver did not want to install
*/
bPutUpMessage = TRUE;
Success = FALSE;
break;
}
/*
* Remember whether the driver is configurable
*/
pIDriver->fQueryable =
(int)SendDriverMessage(hDriver,
DRV_QUERYCONFIGURE,
0L,
0L);
/*
* If the driver is configurable then configure it.
* Configuring the driver may result in a need to restart
* the system. The user may also cancel install.
*/
if (pIDriver->fQueryable) {
switch (SendDriverMessage(
hDriver,
DRV_CONFIGURE,
(LONG)hwnd,
(LONG)(LPDRVCONFIGINFO)&DrvConfigInfo)) {
case DRVCNF_RESTART:
bRestart = TRUE;
break;
case DRVCNF_CANCEL:
/*
* Don't put up the error box if the user cancelled
*/
Err = ERROR_CANCELLED;
Success = FALSE;
break;
}
}
}
CloseDriver(hDriver, 0L, 0L);
} else {
bPutUpMessage = TRUE;
Success = FALSE;
}
if (bPutUpMessage) {
/*
* If dealing with the driver resulted in error then put
* up a message
*/
OpenDriverError(hwnd, pIDriver->szDesc, pIDriver->szFile);
}
}
wsEndWait();
if(!Success) {
SetLastError(Err);
}
return Success;
}
/***********************************************************************
*
* InitDrvConfigInfo()
*
* Initialize Driver Configuration Information.
*
***********************************************************************/
void InitDrvConfigInfo( LPDRVCONFIGINFO lpDrvConfigInfo, PIDRIVER pIDriver )
{
lpDrvConfigInfo->dwDCISize = sizeof(DRVCONFIGINFO);
lpDrvConfigInfo->lpszDCISectionName = pIDriver->wszSection;
lpDrvConfigInfo->lpszDCIAliasName = pIDriver->wszAlias;
}
/***********************************************************************
*
* GetValidAlias()
*
* pstrType - Input - the type
* Output - New alias for that type
*
* pstrSection - The system.ini section we're dealing with
*
* Create a valid alias name for a type. Searches the system.ini file
* in the drivers section for aliases of the type already defined and
* returns a new alias (eg WAVE1).
*
***********************************************************************/
BOOL GetValidAlias(PSTR pstrType, PSTR pstrSection)
{
#define MAXDRVTYPES 10
char *keystr;
char allkeystr[MAXSTR];
BOOL found = FALSE;
int val, maxval = 0, typelen;
typelen = strlen(pstrType);
GetPrivateProfileString(pstrSection, NULL, NULL, allkeystr,
sizeof(allkeystr), szSysIni);
keystr = allkeystr;
/*
* See if we have driver if this type already installed by searching
* our the [drivers] section.
*/
while (*keystr != '\0')
{
if (!_strnicmp(keystr, pstrType, typelen) && ((keystr[typelen] > '0' &&
keystr[typelen] <= '9') ||
keystr[typelen] == TEXT('\0') ))
{
found = TRUE;
val = atoi(&keystr[typelen]);
if (val > maxval)
maxval = val;
}
keystr = &keystr[strlen(keystr) + 1];
}
if (found)
{
if (maxval == MAXDRVTYPES)
return FALSE; // too many of my type!
pstrType[typelen] = (char)(maxval + '1');
pstrType[typelen+1] = '\0';
}
return TRUE;
}
/*******************************************************************
*
* IsConfigurable
*
* Find if a driver supports configuration
*
*******************************************************************/
BOOL IsConfigurable(PIDRIVER pIDriver, HWND hwnd)
{
HANDLE hDriver;
wsStartWait();
/*
* have we ever checked if this driver is queryable?
*/
if ( pIDriver->fQueryable == -1 )
{
/*
* Check it's not a kernel driver
*/
if (pIDriver->KernelDriver) {
pIDriver->fQueryable = 0;
} else {
/*
* Open the driver and ask it if it is configurable
*/
hDriver = OpenDriver(pIDriver->wszAlias, pIDriver->wszSection, 0L);
if (hDriver)
{
pIDriver->fQueryable =
(int)SendDriverMessage(hDriver,
DRV_QUERYCONFIGURE,
0L,
0L);
CloseDriver(hDriver, 0L, 0L);
}
else
{
pIDriver->fQueryable = 0;
OpenDriverError(hwnd, pIDriver->szDesc, pIDriver->szFile);
wsEndWait();
return(FALSE);
}
}
}
wsEndWait();
return((BOOL)pIDriver->fQueryable);
}
/******************************************************************
*
* Find any driver with the same name currently installed and
* remove it
*
* szFile - File name of driver
* szSection - system.ini section ([MCI] or [drivers]).
*
******************************************************************/
void RemoveAlreadyInstalled(PSTR szFile, PSTR szSection)
{
PIDRIVER pIDriver;
pIDriver = FindIDriverByName (szFile);
if (pIDriver != NULL)
{
PostRemove(pIDriver, FALSE);
return;
}
CheckIniDrivers(szFile, szSection);
}
/******************************************************************
*
* Remove system.ini file entries for our driver
*
* szFile - driver file name
* szSection - [drivers] or [MCI]
*
******************************************************************/
void CheckIniDrivers(PSTR szFile, PSTR szSection)
{
char allkeystr[MAXSTR * 2];
char szRemovefile[20];
char *keystr;
GetPrivateProfileString(szSection,
NULL,
NULL,
allkeystr,
sizeof(allkeystr),
szSysIni);
keystr = allkeystr;
while (strlen(keystr) > 0)
{
GetPrivateProfileString(szSection,
keystr,
NULL,
szRemovefile,
sizeof(szRemovefile),
szSysIni);
if (!FileNameCmp(szFile, szRemovefile))
RemoveDriverEntry(keystr, szFile, szSection, FALSE);
keystr = &keystr[strlen(keystr) + 1];
}
}
/******************************************************************
*
* RemoveDriverParams
*
* Remove anything after the next token
*
******************************************************************/
void RemoveDriverParams(LPSTR szFile, LPSTR Params)
{
for(;*szFile == ' '; szFile++);
for(;*szFile != ' ' && *szFile != '\0'; szFile++);
if (*szFile == ' ') {
*szFile = '\0';
for (;*++szFile == ' ';);
strcpy(Params, szFile);
} else {
*Params = '\0';
}
}
DWORD
InstallDriversForPnPDevice(
IN HWND hWnd,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData
)
/*++
Routine Description:
This routine traverses the "Drivers" tree under the specified device's software
key, adding each multimedia type entry present to the Drivers32 key of the registry.
The driver is then invoked to perform any configuration necessary for that type.
Arguments:
hWnd - Supplies the handle of the window to be used as the parent for any UI.
DeviceInfoSet - Supplies a handle to the device information set containing the
multimedia device being installed.
DeviceInfoData - Supplies the address of the SP_DEVINFO_DATA structure representing
the multimedia device being installed.
Return Value:
If successful, the return value is NO_ERROR, otherwise it is a Win32 error code.
--*/
{
HKEY hKey, hDriversKey, hTypeInstanceKey;
CHAR szTypes[MAXSTR];
CHAR szType[MAXSTR];
DWORD Err;
DWORD RegDataType, RegDataSize, RegKeyIndex;
int i;
PIDRIVER pIDriver, pPrevIDriver;
PIDRIVER IDriverList = NULL, IDriverListToCleanUp = NULL;
CHAR CharBuffer[MAX_PATH + 1];
PCSTR CurrentFilename;
if((hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
KEY_ALL_ACCESS)) == INVALID_HANDLE_VALUE) {
return GetLastError();
}
//
// What we're really interested in is the "Drivers" subkey.
//
Err = (DWORD)RegOpenKeyExA(hKey, gszAnsiDriversSubkeyName, 0, KEY_ALL_ACCESS, &hDriversKey);
RegCloseKey(hKey); // don't need this key anymore.
if(Err != ERROR_SUCCESS) {
return Err;
}
//
// Retrieve the "SubClasses" value from this key. This contains a comma-delimited
// list of all multimedia type entries associated with this device.
//
RegDataSize = sizeof(szTypes);
if((Err = RegQueryValueExA(hDriversKey,
gszAnsiSubClassesValue,
NULL,
&RegDataType,
(PBYTE)szTypes,
&RegDataSize)) != ERROR_SUCCESS) {
goto clean0;
}
if((RegDataType != REG_SZ) || !RegDataSize) {
Err = ERROR_INVALID_DATA;
goto clean0;
}
//
// OK, we have the list of types, now process each one.
//
for(i = 1; ((Err == NO_ERROR) && infParseField(szTypes, i, szType)); i++) {
if(RegOpenKeyExA(hDriversKey, szType, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) {
//
// Couldn't find a subkey for this entry--move on to the next one.
//
continue;
}
for(RegKeyIndex = 0;
((Err == NO_ERROR) &&
(RegEnumKeyA(hKey, RegKeyIndex, CharBuffer, sizeof(CharBuffer)) == ERROR_SUCCESS));
RegKeyIndex++)
{
if(RegOpenKeyExA(hKey, CharBuffer, 0, KEY_ALL_ACCESS, &hTypeInstanceKey) != ERROR_SUCCESS) {
//
// For some reason, we couldn't open the key we just enumerated. Oh well, move on
// to the next one.
//
continue;
}
if(!(pIDriver = (PIDRIVER)LocalAlloc(LPTR, sizeof(IDRIVER)))) {
//
// Not enough memory! Abort the whole thing.
//
Err = ERROR_NOT_ENOUGH_MEMORY;
goto CloseInstanceAndContinue;
}
//
// Retrieve the description and driver filename from this key.
//
RegDataSize = sizeof(pIDriver->szDesc);
if((RegQueryValueExA(hTypeInstanceKey,
gszAnsiDescriptionValue,
NULL,
&RegDataType,
pIDriver->szDesc,
&RegDataSize) != ERROR_SUCCESS)
|| (RegDataType != REG_SZ) || !RegDataSize)
{
LocalFree((HANDLE)pIDriver);
goto CloseInstanceAndContinue;
}
strncpy(pIDriver->szSection,
strstr(pIDriver->szDesc, "MCI") ? szMCI : szDrivers,
sizeof(pIDriver->szSection) - 1
);
RegDataSize = sizeof(pIDriver->szFile);
if((RegQueryValueExA(hTypeInstanceKey,
gszAnsiDriverValue,
NULL,
&RegDataType,
pIDriver->szFile,
&RegDataSize) != ERROR_SUCCESS)
|| (RegDataType != REG_SZ) || !RegDataSize)
{
LocalFree((HANDLE)pIDriver);
goto CloseInstanceAndContinue;
}
pIDriver->KernelDriver = IsFileKernelDriver(pIDriver->szFile);
//
// Find a valid alias for this device (eg Wave2). This is
// used as the key in the [MCI] or [Drivers32] section.
//
strncpy(pIDriver->szAlias, szType, sizeof(pIDriver->szAlias) - 1);
if(!GetValidAlias(pIDriver->szAlias, pIDriver->szSection)) {
//
// Exceeded the maximum--tell the user.
//
PSTR pstrMessage;
char szApp[MAXSTR];
char szMessage[MAXSTR];
LoadString(myInstance,
IDS_CONFIGURE_DRIVER,
szApp,
sizeof(szApp));
LoadString(myInstance,
IDS_TOO_MANY_DRIVERS,
szMessage,
sizeof(szMessage));
if (NULL !=
(pstrMessage =
(PSTR)LocalAlloc(LPTR,
sizeof(szMessage) + lstrlen(szType))))
{
wsprintf(pstrMessage, szMessage, (LPSTR)szType);
MessageBox(hWnd,
pstrMessage,
szApp,
MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
LocalFree((HANDLE)pstrMessage);
}
LocalFree((HANDLE)pIDriver);
goto CloseInstanceAndContinue;
}
//
// Fill in the Unicode fields from the ANSI ones.
//
mbstowcs(pIDriver->wszSection, pIDriver->szSection, MAXSTR);
mbstowcs(pIDriver->wszAlias, pIDriver->szAlias, MAXSTR);
mbstowcs(pIDriver->wszFile, pIDriver->szFile, MAX_PATH);
//
// We must write the alias out now, because we may need to generate
// other aliases for this same type, and we can't generate a unique
// alias unless all existing aliases are present in the relevant
// registry key.
//
WritePrivateProfileStringA(pIDriver->szSection,
pIDriver->szAlias,
pIDriver->szFile,
szSysIni
);
//
// We also must write the alias out to the key we're currently in (under
// the device's software key), because during uninstall, we need to be
// able to figure out what devices get removed.
//
RegSetValueExA(hTypeInstanceKey,
gszAnsiAliasValue,
0,
REG_SZ,
(PBYTE)(pIDriver->szAlias),
strlen(pIDriver->szAlias) + sizeof(CHAR)
);
//
// Add this new IDriver node to our linked list. The list is sorted by
// driver filename, and this node should be inserted at the end of the
// the group of nodes that have the same driver filename.
//
InsertNewIDriverNodeInList(&IDriverList, pIDriver);
CloseInstanceAndContinue:
RegCloseKey(hTypeInstanceKey);
}
RegCloseKey(hKey);
}
if((Err == NO_ERROR) && !IDriverList) {
//
// We didn't find anything to install!
//
Err = ERROR_INVALID_DATA;
}
if(Err != NO_ERROR) {
//
// Clean up anything we put in the multimedia sections of the registry.
//
DestroyIDriverNodeList(IDriverList, TRUE, FALSE);
goto clean0;
}
//
// If we get to here, then we've successfully built up a list of all driver entries
// we need to install. Now, traverse the list, and install each one.
//
CurrentFilename = NULL;
*CharBuffer = '\0'; // use this character buffer to contain (empty) parameter string.
pIDriver = IDriverList;
pPrevIDriver = NULL;
while(pIDriver) {
if(!CurrentFilename || _stricmp(CurrentFilename, pIDriver->szFile)) {
//
// This is the first entry we've encountered for this driver. We need
// to call the driver to see if it can be configured, and configure it
// if it can be.
//
if(SelectInstalled(hWnd, pIDriver, CharBuffer, DeviceInfoSet, DeviceInfoData)) {
//
// Move this IDriver node to our list of clean-up items. This is used in
// case we hit an error with some other driver, and we need to notify this
// driver that even though it was successful, someone else screwed up and
// complete removal of the device must occur.
//
if(pPrevIDriver) {
pPrevIDriver->related = pIDriver->related;
} else {
IDriverList = pIDriver->related;
}
pIDriver->related = IDriverListToCleanUp;
IDriverListToCleanUp = pIDriver;
} else {
//
// Error talking to driver
//
Err = GetLastError();
goto clean1;
}
#if 0 // We don't need this piece of code in the Plug&Play install case.
/*
* for displaying the driver desc. in the restart mesg
*/
if (!bRelated || pIDriver->bRelated) {
strcpy(szRestartDrv, pIDriver->szDesc);
}
#endif
//
// We need to write out the driver description to the
// control.ini section [Userinstallable.drivers]
// so we can differentiate between user and system drivers
//
// This is tested by the function UserInstalled when
// the user tries to remove a driver and merely
// affects which message the user gets when being
// asked to confirm removal (non user-installed drivers
// are described as being necessary to the system).
//
WritePrivateProfileStringA(szUserDrivers,
pIDriver->szAlias,
pIDriver->szFile,
szControlIni
);
//
// Update [related.desc] section of control.ini :
//
// ALIAS=driver name list
//
// When the driver whose alias is ALIAS is removed
// the drivers in the name list will also be removed.
// These were the drivers in the related drivers list
// when the driver is installed.
//
WritePrivateProfileStringA(szRelatedDesc,
pIDriver->szAlias,
pIDriver->szRemove,
szControlIni
);
//
// Cache the description string in control.ini in the
// drivers description section.
//
// The key is the driver file name + extension.
//
WritePrivateProfileStringA(szDriversDesc,
pIDriver->szFile,
pIDriver->szDesc,
szControlIni
);
#ifdef DOBOOT // We don't do the boot section on NT
if (bInstallBootLine) {
szTemp[MAXSTR];
GetPrivateProfileStringA(szBoot,
szDrivers,
szTemp,
szTemp,
sizeof(szTemp),
szSysIni);
strcat(szTemp, " ");
strcat(szTemp, pIDriver->szAlias);
WritePrivateProfileStringA(szBoot,
szDrivers,
szTemp,
szSysIni);
bInstallBootLine = FALSE;
}
#endif // DOBOOT
//
// Update our "CurrentFilename" pointer, so that we'll know when we
// move from one driver filename to another.
//
CurrentFilename = pIDriver->szFile;
//
// Move on to the next IDriver node IN THE ORIGINAL LIST. We can't simply
// move on the 'related' pointer in our node anymore, since we moved it
// into our clean-up list.
//
if(pPrevIDriver) {
pIDriver = pPrevIDriver->related;
} else {
pIDriver = IDriverList;
}
} else {
//
// We've already configured this driver. Leave it in its original list,
// and move on to the next node.
//
pPrevIDriver = pIDriver;
pIDriver = pIDriver->related;
}
}
clean1:
DestroyIDriverNodeList(IDriverListToCleanUp, (Err != NO_ERROR), TRUE);
DestroyIDriverNodeList(IDriverList, (Err != NO_ERROR), FALSE);
clean0:
RegCloseKey(hDriversKey);
return Err;
}
void
InsertNewIDriverNodeInList(
IN OUT PIDRIVER *IDriverList,
IN PIDRIVER NewIDriverNode
)
/*++
Routine Description:
This routine inserts a new IDriver node into the specified linked list of IDriver
nodes. The list is sorted by driver filename, and this node will be placed after
any existing nodes having this same driver filename.
Arguments:
IDriverList - Supplies the address of the variable that points to the head of the
linked list. If the new node is inserted at the head of the list, this variable
will be updated upon return to reflect the new head of the list.
NewIDriverNode - Supplies the address of the new driver node to be inserted into the
list.
Return Value:
None.
--*/
{
PIDRIVER CurNode, PrevNode;
for(CurNode = *IDriverList, PrevNode = NULL;
CurNode;
PrevNode = CurNode, CurNode = CurNode->related)
{
if(_stricmp(CurNode->szFile, NewIDriverNode->szFile) > 0) {
break;
}
}
//
// Insert the new IDriver node in front of the current one.
//
NewIDriverNode->related = CurNode;
if(PrevNode) {
PrevNode->related = NewIDriverNode;
} else {
*IDriverList = NewIDriverNode;
}
}
void
DestroyIDriverNodeList(
IN PIDRIVER IDriverList,
IN BOOL CleanRegistryValues,
IN BOOL NotifyDriverOfCleanUp
)
/*++
Routine Description:
This routine frees all memory associated with the nodes in the specified IDriver
linked list. It also optionally cleans up any modifications that were previously
made as a result of an attempted install.
Arguments:
IDriverList - Points to the head of the linked list of IDriver nodes.
CleanRegistryValues - If TRUE, then the multimedia registry values previously
created (e.g., Drivers32 aliases) will be deleted.
NotifyDriverOfCleanUp - If TRUE, then the driver will be notified of its removal.
This only applies to non-kernel (i.e., installable) drivers, and this flag is
ignored if CleanRegistryValues is FALSE.
Return Value:
None.
--*/
{
PIDRIVER NextNode;
HANDLE hDriver;
while(IDriverList) {
NextNode = IDriverList->related;
if(CleanRegistryValues) {
if(NotifyDriverOfCleanUp && !IDriverList->KernelDriver) {
if(hDriver = OpenDriver(IDriverList->wszAlias, IDriverList->wszSection, 0L)) {
SendDriverMessage(hDriver, DRV_REMOVE, 0L, 0L);
CloseDriver(hDriver, 0L, 0L);
}
}
WritePrivateProfileStringA(IDriverList->szSection,
IDriverList->szAlias,
NULL,
szSysIni
);
WriteProfileStringA(IDriverList->szFile, IDriverList->szAlias, NULL);
}
LocalFree((HANDLE)IDriverList);
IDriverList = NextNode;
}
}