windows-nt/Source/XPSP1/NT/drivers/input/upgrade/upgrade.c
2020-09-26 16:20:57 +08:00

419 lines
10 KiB
C

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <tchar.h>
#include <regstr.h>
// this will change when the .h is moved to a public location
#include "comp.h"
HINSTANCE hInstance;
PCOMPAIBILITYCALLBACK CompatCallback;
LPVOID CompatContext;
#define szServicesPath REGSTR_PATH_SERVICES TEXT("\\")
#define szDeviceMap TEXT("HARDWARE\\DEVICEMAP")
typedef struct _INPUT_DRIVER_DATA {
LPTSTR Service;
BOOL DisableReplacements;
LPTSTR DeviceMapSubKey;
} INPUT_DRIVER_DATA;
INPUT_DRIVER_DATA DriverData[] = {
{ TEXT("sermouse"), FALSE, NULL },
{ TEXT("i8042prt"), TRUE, TEXT("KeyboardPort") },
{ TEXT("mouclass"), TRUE, TEXT("PointerClass") },
{ TEXT("kbdclass"), TRUE, TEXT("KeyboardClass") },
};
#define NUM_DRIVER_DATA (sizeof(DriverData) / sizeof(INPUT_DRIVER_DATA))
LPENUM_SERVICE_STATUS
AllocEnumServiceStatus(SC_HANDLE hSCManager, LPDWORD Count)
{
LPENUM_SERVICE_STATUS ess;
DWORD size;
DWORD resume;
EnumServicesStatus(hSCManager,
SERVICE_DRIVER,
SERVICE_ACTIVE,
NULL,
0,
&size,
Count,
&resume);
if (size == 0) {
return NULL;
}
ess = (LPENUM_SERVICE_STATUS) LocalAlloc(LPTR, size);
if (!ess) {
return NULL;
}
EnumServicesStatus(hSCManager,
SERVICE_DRIVER,
SERVICE_ACTIVE,
ess,
size,
&size,
Count,
&resume);
return ess;
}
LPQUERY_SERVICE_CONFIG
GetServiceConfig(SC_HANDLE hService)
{
LPQUERY_SERVICE_CONFIG pConfig;
DWORD configSize;
QueryServiceConfig(hService, NULL, 0, &configSize);
pConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, configSize);
if (pConfig == NULL) {
return NULL;
}
if (!QueryServiceConfig(hService, pConfig, configSize, &configSize)) {
LocalFree(pConfig);
pConfig = NULL;
}
return pConfig;
}
BOOL
ValidImagePath(LPTSTR Service, LPTSTR ImagePath, LPTSTR *ImageName)
{
LPTSTR pszDriver, pszDriverEnd, pszDriverBegin;
if (!ImagePath) {
return FALSE;
}
if (lstrlen(ImagePath) == 0) {
return TRUE;
}
if (_tcschr(ImagePath, TEXT('\\')) == 0) {
return FALSE;
}
pszDriver = ImagePath;
pszDriverEnd = pszDriver + lstrlen(pszDriver);
while(pszDriverEnd != pszDriver &&
*pszDriverEnd != TEXT('.')) {
pszDriverEnd--;
}
// pszDriverEnd points to either the beginning of the string or '.'
pszDriverBegin = pszDriverEnd;
while(pszDriverBegin != pszDriver &&
*pszDriverBegin != TEXT('\\')) {
pszDriverBegin--;
}
pszDriverBegin++;
//
// If pszDriver and pszDriverEnd are different, we now
// have the driver name.
//
if (pszDriverBegin > pszDriver &&
pszDriverEnd > pszDriverBegin) {
LONG len, res;
LPTSTR image;
len = ((LONG) (pszDriverEnd - pszDriverBegin)) + 1;
image = (LPTSTR) LocalAlloc(LPTR, len * sizeof(TCHAR));
if (!image) {
return FALSE;
}
// want to copy up to, but not including, the ','
lstrcpyn(image, pszDriverBegin, len);
res = lstrcmpi(image, Service);
if (ImageName != NULL) {
*ImageName = image;
}
else {
LocalFree(image);
}
return res == 0;
}
else {
return FALSE;
}
}
VOID
SetServiceStartValue(LPTSTR Service, DWORD StartValue)
{
COMPATIBILITY_ENTRY ce;
TCHAR szStart[] = TEXT("Start");
LPTSTR regPath;
DWORD len;
len = lstrlen(Service) + lstrlen(szServicesPath) + 1;
len *= sizeof(TCHAR);
regPath = (LPTSTR) LocalAlloc(LPTR, len);
if (!regPath) {
return;
}
lstrcpy(regPath, szServicesPath);
lstrcat(regPath, Service);
ZeroMemory(&ce, sizeof(COMPATIBILITY_ENTRY));
// Description and TextName are need even though this is hidden
ce.Description = Service;
ce.TextName = Service;
ce.RegKeyName = regPath;
ce.RegValName = szStart;
ce.RegValDataSize = sizeof(DWORD);
ce.RegValData = (LPVOID) &StartValue;
ce.Flags |= COMPFLAG_HIDE;
CompatCallback(&ce, CompatContext);
LocalFree(regPath);
}
VOID
SetServiceImagePath(LPTSTR Service)
{
COMPATIBILITY_ENTRY ce;
TCHAR szImagePath[] = TEXT("ImagePath");
TCHAR szPath[] = TEXT("System32\\Drivers\\");
LPTSTR imagePath, regPath;
DWORD len;
len = lstrlen(Service) + lstrlen(szServicesPath) + 1;
len *= sizeof(TCHAR);
regPath = (LPTSTR) LocalAlloc(LPTR, len);
if (!regPath) {
return;
}
len = lstrlen(szPath) + lstrlen(Service) + lstrlen(TEXT(".sys")) + 1;
len *= sizeof(TCHAR);
imagePath = (LPTSTR) LocalAlloc(LPTR, len);
if (!imagePath) {
LocalFree(regPath);
return;
}
lstrcpy(regPath, szServicesPath);
lstrcat(regPath, Service);
lstrcpy(imagePath, szPath);
lstrcat(imagePath, Service);
lstrcat(imagePath, TEXT(".sys"));
ZeroMemory(&ce, sizeof(COMPATIBILITY_ENTRY));
// Description and TextName are need even though this is hidden
ce.Description = Service;
ce.TextName = Service;
ce.RegKeyName = regPath;
ce.RegValName = szImagePath;
ce.RegValDataSize = len;
ce.RegValData = (LPVOID) imagePath;
ce.Flags |= COMPFLAG_HIDE;
CompatCallback(&ce, CompatContext);
LocalFree(regPath);
LocalFree(imagePath);
}
SC_HANDLE
CheckService(SC_HANDLE hSCManager, LPTSTR Service, BOOL *Disabled)
{
SC_HANDLE hService;
LPQUERY_SERVICE_CONFIG pConfig;
hService = OpenService(hSCManager, Service, SERVICE_QUERY_CONFIG);
if (hService) {
pConfig = GetServiceConfig(hService);
if (pConfig) {
if (pConfig->dwStartType == SERVICE_DISABLED &&
pConfig->lpBinaryPathName &&
lstrlen(pConfig->lpBinaryPathName) == 0) {
//
// The service has been preinstalled in the registry, but never
// installed on the machine (indicated byno image path,
// disabled). Setting its start value to demand start will not
// cause any conflicts at all in the PNP world of input drivers.
//
SetServiceStartValue(Service, SERVICE_DEMAND_START);
}
else {
if (pConfig->dwStartType != SERVICE_SYSTEM_START &&
pConfig->dwStartType != SERVICE_DEMAND_START) {
if (Disabled) {
*Disabled = TRUE;
}
SetServiceStartValue(Service, SERVICE_DEMAND_START);
}
if (!ValidImagePath(Service, pConfig->lpBinaryPathName, NULL)) {
SetServiceImagePath(Service);
}
}
LocalFree(pConfig);
pConfig = NULL;
}
}
return hService;
}
BOOL
KnownInputDriver(LPTSTR Service)
{
int i = 0;
for ( ; i < NUM_DRIVER_DATA; i++) {
if (lstrcmpi(Service, DriverData[i].Service) == 0) {
return TRUE;
}
}
return FALSE;
}
VOID
EnumAndDisableFromDeviceMap(SC_HANDLE hSCManager, LPTSTR Key)
{
HKEY hMap, hSubKey;
DWORD dwIndex = 0, dwType, err, dwValueNameSize, dwDataSize;
TCHAR szValueName[255], szData[255];
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szDeviceMap,
0,
KEY_READ,
&hMap) != ERROR_SUCCESS) {
return;
}
if (RegOpenKeyEx(hMap, Key, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS) {
RegCloseKey(hMap);
return;
}
RegCloseKey(hMap);
do {
dwValueNameSize = sizeof(szValueName) / sizeof(TCHAR);
dwDataSize = sizeof(szData);
err = RegEnumValue(hSubKey,
dwIndex++,
szValueName,
&dwValueNameSize,
0,
&dwType,
(LPBYTE) szData,
&dwDataSize);
if (err == ERROR_SUCCESS) {
LPTSTR service = _tcsrchr(szData, TEXT('\\'));
if (service) {
service++;
if (!KnownInputDriver(service)) {
SetServiceStartValue(service, SERVICE_DISABLED);
}
}
}
} while (err == ERROR_SUCCESS);
RegCloseKey(hSubKey);
}
BOOL
InputUpgradeCheck(PCOMPAIBILITYCALLBACK CompatibilityCallback, LPVOID Context)
{
SC_HANDLE hSCManager, hService;
BOOL disabled;
int i;
LPENUM_SERVICE_STATUS ess = NULL;
DWORD count, resume;
CompatCallback = CompatibilityCallback;
CompatContext = Context;
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCManager == NULL) {
return TRUE;
}
for (i = 0; i < NUM_DRIVER_DATA; i++) {
disabled = FALSE;
hService = CheckService(hSCManager, DriverData[i].Service, &disabled);
if (hService) {
if (disabled && DriverData[i].DisableReplacements) {
// search and destroy
EnumAndDisableFromDeviceMap(hSCManager,
DriverData[i].DeviceMapSubKey);
}
CloseServiceHandle(hService);
}
}
CloseServiceHandle(hSCManager);
return TRUE;
}
BOOL APIENTRY
DllMain(HINSTANCE hDll,
DWORD dwReason,
LPVOID lpReserved)
{
switch (dwReason) {
case DLL_PROCESS_ATTACH:
hInstance = hDll;
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
default:
break;
}
return TRUE;
}