windows-nt/Source/XPSP1/NT/shell/osshell/control/drivers/install.c
2020-09-26 16:20:57 +08:00

902 lines
27 KiB
C

/*************************************************************************
*
* 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 (HWND, PSTR, PSTR);
BOOL SelectInstalled (HWND, PIDRIVER, LPSTR);
void InitDrvConfigInfo (LPDRVCONFIGINFO, PIDRIVER );
BOOL InstallDrivers (HWND, HWND, PSTR);
void RemoveAlreadyInstalled (PSTR, PSTR);
void CheckIniDrivers (PSTR, PSTR);
void RemoveDriverParams (LPSTR, LPSTR);
/**************************************************************************
*
* 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,iIndex;
HWND hWndI;
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
*/
hWndI = GetDlgItem(hWnd, LB_INSTALLED);
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(hWndI, 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 {
/*
* Add the driver description to our listbox
*/
iIndex = (int)SendMessage(hWndI,
LB_ADDSTRING,
0,
(LONG)pIDriver->szDesc);
if (iIndex >= LB_OKAY) {
/*
* Our PIDRIVER data is our listbox item
*/
SendMessage(hWndI, LB_SETITEMDATA, iIndex, (LONG)pIDriver);
/*
* 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))
{
/*
* Error talking to driver
*/
WritePrivateProfileString(pIDriver->szSection,
pIDriver->szAlias,
NULL,
szSysIni);
WriteProfileString(pIDriver->szFile,
pIDriver->szAlias,
NULL);
SendMessage(hWndI, LB_DELETESTRING, iIndex, 0L);
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 {
/*
* Problem getting an alias or adding a driver to the listbox
*/
LocalFree((HANDLE)pIDriver);
pIDriver = NULL;
return FALSE; //ERROR
}
}
}
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.
*
* Returns FALSE if an error occurred, otherwise TRUE
*
************************************************************************/
BOOL SelectInstalled(HWND hwnd, PIDRIVER pIDriver, LPSTR pszParams)
{
DRVCONFIGINFO DrvConfigInfo;
HANDLE hDriver;
BOOL Success = FALSE;
DWORD dwTagId;
wsStartWait();
/*
* If it's a kernel driver call the services controller to
* install the driver
*/
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;
/*
* 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);
}
ServiceHandle = CreateService(SCManagerHandle,
ServiceName,
NULL,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
BinaryPath,
"Base",
&dwTagId,
"\0",
NULL,
NULL);
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;
} 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];
/*
* 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 {
/*
* 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).
*/
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
*/
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();
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()
*
* hwnd - Window handle - not used
* 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(HWND hwnd, 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)
{
int iIndex;
PIDRIVER pIDriver;
iIndex = (int)SendMessage(hlistbox, LB_GETCOUNT, 0, 0L);
while ( iIndex-- > 0) {
pIDriver = (PIDRIVER)SendMessage(hlistbox, LB_GETITEMDATA, iIndex, 0L);
if ( (int)pIDriver != LB_ERR) {
if (!FileNameCmp(pIDriver->szFile, szFile)) {
PostRemove(hlistbox, pIDriver, FALSE, iIndex);
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';
}
}