705 lines
17 KiB
C

/*
InstDrv.dll - Installs or Removes Device Drivers
Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment in the
product documentation would be appreciated but is not required.
2. Altered versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any distribution.
*/
#include <windows.h>
#include <setupapi.h>
#include <newdev.h>
#include "../exdll/exdll.h"
char paramBuf[1024];
GUID devClass;
char hwIdBuf[1024];
int initialized = 0;
void* memset(void* dst, int val, unsigned int len)
{
while (len-- > 0)
*((char *)dst)++ = val;
return NULL;
}
void* memcpy(void* dst, const void* src, unsigned int len)
{
while (len-- > 0)
*((char *)dst)++ = *((char *)src)++;
return NULL;
}
int HexCharToInt(char c)
{
if ((c >= '0') && (c <= '9'))
return c - '0';
else if ((c >= 'a') && (c <= 'f'))
return c - 'a' + 10;
else if ((c >= 'A') && (c <= 'F'))
return c - 'A' + 10;
else
return -1;
}
BOOLEAN HexStringToUInt(char* str, int width, void* valBuf)
{
int i, val;
for (i = width - 4; i >= 0; i -= 4)
{
val = HexCharToInt(*str++);
if (val < 0)
return FALSE;
*(unsigned int *)valBuf += val << i;
}
return TRUE;
}
BOOLEAN StringToGUID(char* guidStr, GUID* pGuid)
{
int i;
memset(pGuid, 0, sizeof(GUID));
if (*guidStr++ != '{')
return FALSE;
if (!HexStringToUInt(guidStr, 32, &pGuid->Data1))
return FALSE;
guidStr += 8;
if (*guidStr++ != '-')
return FALSE;
if (!HexStringToUInt(guidStr, 16, &pGuid->Data2))
return FALSE;
guidStr += 4;
if (*guidStr++ != '-')
return FALSE;
if (!HexStringToUInt(guidStr, 16, &pGuid->Data3))
return FALSE;
guidStr += 4;
if (*guidStr++ != '-')
return FALSE;
for (i = 0; i < 2; i++)
{
if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))
return FALSE;
guidStr += 2;
}
if (*guidStr++ != '-')
return FALSE;
for (i = 2; i < 8; i++)
{
if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))
return FALSE;
guidStr += 2;
}
if (*guidStr++ != '}')
return FALSE;
return TRUE;
}
DWORD FindNextDevice(HDEVINFO devInfoSet, SP_DEVINFO_DATA* pDevInfoData, DWORD* pIndex)
{
DWORD buffersize = 0;
LPTSTR buffer = NULL;
DWORD dataType;
DWORD result;
while (1)
{
if (!SetupDiEnumDeviceInfo(devInfoSet, (*pIndex)++, pDevInfoData))
{
result = GetLastError();
break;
}
GetDeviceRegistryProperty:
if (!SetupDiGetDeviceRegistryProperty(devInfoSet, pDevInfoData, SPDRP_HARDWAREID,
&dataType, (PBYTE)buffer, buffersize,
&buffersize))
{
result = GetLastError();
if (result == ERROR_INSUFFICIENT_BUFFER)
{
if (buffer != NULL)
LocalFree(buffer);
buffer = (LPTSTR)LocalAlloc(LPTR, buffersize);
if (buffer == NULL)
break;
goto GetDeviceRegistryProperty;
}
else if (result == ERROR_INVALID_DATA)
continue; // ignore invalid entries
else
break; // break on other errors
}
if (lstrcmpi(buffer, hwIdBuf) == 0)
{
result = 0;
break;
}
}
if (buffer != NULL)
LocalFree(buffer);
return result;
}
DWORD FindFirstDevice(HWND hwndParent, const GUID* pDevClass, const LPTSTR hwId,
HDEVINFO* pDevInfoSet, SP_DEVINFO_DATA* pDevInfoData,
DWORD *pIndex, DWORD flags)
{
DWORD result;
*pDevInfoSet = SetupDiGetClassDevs((GUID*)pDevClass, NULL, hwndParent, flags);
if (*pDevInfoSet == INVALID_HANDLE_VALUE)
return GetLastError();
pDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
*pIndex = 0;
result = FindNextDevice(*pDevInfoSet, pDevInfoData, pIndex);
if (result != 0)
SetupDiDestroyDeviceInfoList(*pDevInfoSet);
return result;
}
/*
* InstDrv::InitDriverSetup devClass drvHWID
*
* devClass - GUID of the driver's device setup class
* drvHWID - Hardware ID of the supported device
*
* Return:
* result - error message, empty on success
*/
void __declspec(dllexport) InitDriverSetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
EXDLL_INIT();
/* convert class GUID */
popstring(paramBuf);
if (!StringToGUID(paramBuf, &devClass))
{
popstring(paramBuf);
pushstring("Invalid GUID!");
return;
}
/* get hardware ID */
memset(hwIdBuf, 0, sizeof(hwIdBuf));
popstring(hwIdBuf);
initialized = 1;
pushstring("");
}
/*
* InstDrv::CountDevices
*
* Return:
* result - Number of installed devices the driver supports
*/
void __declspec(dllexport) CountDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfoSet;
SP_DEVINFO_DATA devInfoData;
int count = 0;
char countBuf[16];
DWORD index;
DWORD result;
EXDLL_INIT();
if (!initialized)
{
pushstring("Fatal error!");
return;
}
result = FindFirstDevice(hwndParent, &devClass, hwIdBuf, &devInfoSet, &devInfoData,
&index, DIGCF_PRESENT);
if (result != 0)
{
pushstring("0");
return;
}
do
{
count++;
} while (FindNextDevice(devInfoSet, &devInfoData, &index) == 0);
SetupDiDestroyDeviceInfoList(devInfoSet);
wsprintf(countBuf, "%d", count);
pushstring(countBuf);
}
/*
* InstDrv::CreateDevice
*
* Return:
* result - Windows error code
*/
void __declspec(dllexport) CreateDevice(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfoSet;
SP_DEVINFO_DATA devInfoData;
DWORD result = 0;
char resultBuf[16];
EXDLL_INIT();
if (!initialized)
{
pushstring("Fatal error!");
return;
}
devInfoSet = SetupDiCreateDeviceInfoList(&devClass, hwndParent);
if (devInfoSet == INVALID_HANDLE_VALUE)
{
wsprintf(resultBuf, "%08X", GetLastError());
pushstring(resultBuf);
return;
}
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiCreateDeviceInfo(devInfoSet, hwIdBuf, &devClass, NULL,
hwndParent, DICD_GENERATE_ID, &devInfoData))
{
result = GetLastError();
goto InstallCleanup;
}
if (!SetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID,
hwIdBuf, (lstrlen(hwIdBuf)+2)*sizeof(TCHAR)))
{
result = GetLastError();
goto InstallCleanup;
}
if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))
result = GetLastError();
InstallCleanup:
SetupDiDestroyDeviceInfoList(devInfoSet);
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
/*
* InstDrv::InstallDriver infPath
*
* Return:
* result - Windows error code
* reboot - non-zero if reboot is required
*/
void __declspec(dllexport) InstallDriver(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
char resultBuf[16];
BOOL reboot;
EXDLL_INIT();
popstring(paramBuf);
if (!initialized)
{
pushstring("Fatal error!");
return;
}
if (!UpdateDriverForPlugAndPlayDevices(hwndParent, hwIdBuf, paramBuf,
INSTALLFLAG_FORCE, &reboot))
{
wsprintf(resultBuf, "%08X", GetLastError());
pushstring(resultBuf);
}
else
{
wsprintf(resultBuf, "%d", reboot);
pushstring(resultBuf);
pushstring("00000000");
}
}
/*
* InstDrv::DeleteOemInfFiles
*
* Return:
* result - Windows error code
* oeminf - Path of the deleted devices setup file (oemXX.inf)
* oempnf - Path of the deleted devices setup file (oemXX.pnf)
*/
void __declspec(dllexport) DeleteOemInfFiles(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
SP_DRVINFO_DATA drvInfoData;
SP_DRVINFO_DETAIL_DATA drvInfoDetail;
DWORD index;
DWORD result;
char resultBuf[16];
if (!initialized)
{
pushstring("Fatal error!");
return;
}
result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);
if (result != 0)
goto Cleanup1;
if (!SetupDiBuildDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER))
{
result = GetLastError();
goto Cleanup2;
}
drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
drvInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
if (!SetupDiEnumDriverInfo(devInfo, &devInfoData, SPDIT_COMPATDRIVER, 0, &drvInfoData))
{
result = GetLastError();
goto Cleanup3;
}
if (!SetupDiGetDriverInfoDetail(devInfo, &devInfoData, &drvInfoData,
&drvInfoDetail, sizeof(drvInfoDetail), NULL))
{
result = GetLastError();
if (result != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup3;
result = 0;
}
pushstring(drvInfoDetail.InfFileName);
if (!DeleteFile(drvInfoDetail.InfFileName))
result = GetLastError();
else
{
index = lstrlen(drvInfoDetail.InfFileName);
if (index > 3)
{
lstrcpy(drvInfoDetail.InfFileName+index-3, "pnf");
pushstring(drvInfoDetail.InfFileName);
if (!DeleteFile(drvInfoDetail.InfFileName))
result = GetLastError();
}
}
Cleanup3:
SetupDiDestroyDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER);
Cleanup2:
SetupDiDestroyDeviceInfoList(devInfo);
Cleanup1:
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
/*
* InstDrv::RemoveAllDevices
*
* Return:
* result - Windows error code
* reboot - non-zero if reboot is required
*/
void __declspec(dllexport) RemoveAllDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
DWORD index;
DWORD result;
char resultBuf[16];
BOOL reboot = FALSE;
SP_DEVINSTALL_PARAMS instParams;
EXDLL_INIT();
if (!initialized)
{
pushstring("Fatal error!");
return;
}
result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);
if (result != 0)
goto Cleanup1;
do
{
if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData))
{
result = GetLastError();
break;
}
instParams.cbSize = sizeof(instParams);
if (!reboot &&
SetupDiGetDeviceInstallParams(devInfo, &devInfoData, &instParams) &&
((instParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0))
{
reboot = TRUE;
}
result = FindNextDevice(devInfo, &devInfoData, &index);
} while (result == 0);
SetupDiDestroyDeviceInfoList(devInfo);
Cleanup1:
if ((result == 0) || (result == ERROR_NO_MORE_ITEMS))
{
wsprintf(resultBuf, "%d", reboot);
pushstring(resultBuf);
pushstring("00000000");
}
else
{
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
}
/*
* InstDrv::StartSystemService serviceName
*
* Return:
* result - Windows error code
*/
void __declspec(dllexport) StartSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
SC_HANDLE managerHndl;
SC_HANDLE svcHndl;
SERVICE_STATUS svcStatus;
DWORD oldCheckPoint;
DWORD result;
char resultBuf[16];
EXDLL_INIT();
popstring(paramBuf);
managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (managerHndl == NULL)
{
result = GetLastError();
goto Cleanup1;
}
svcHndl = OpenService(managerHndl, paramBuf, SERVICE_START | SERVICE_QUERY_STATUS);
if (svcHndl == NULL)
{
result = GetLastError();
goto Cleanup2;
}
if (!StartService(svcHndl, 0, NULL) || !QueryServiceStatus(svcHndl, &svcStatus))
{
result = GetLastError();
goto Cleanup3;
}
while (svcStatus.dwCurrentState == SERVICE_START_PENDING)
{
oldCheckPoint = svcStatus.dwCheckPoint;
Sleep(svcStatus.dwWaitHint);
if (!QueryServiceStatus(svcHndl, &svcStatus))
{
result = GetLastError();
break;
}
if (oldCheckPoint >= svcStatus.dwCheckPoint)
{
if ((svcStatus.dwCurrentState == SERVICE_STOPPED) &&
(svcStatus.dwWin32ExitCode != 0))
result = svcStatus.dwWin32ExitCode;
else
result = ERROR_SERVICE_REQUEST_TIMEOUT;
}
}
if (svcStatus.dwCurrentState == SERVICE_RUNNING)
result = 0;
Cleanup3:
CloseServiceHandle(svcHndl);
Cleanup2:
CloseServiceHandle(managerHndl);
Cleanup1:
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
/*
* InstDrv::StopSystemService serviceName
*
* Return:
* result - Windows error code
*/
void __declspec(dllexport) StopSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
SC_HANDLE managerHndl;
SC_HANDLE svcHndl;
SERVICE_STATUS svcStatus;
DWORD oldCheckPoint;
DWORD result;
char resultBuf[16];
EXDLL_INIT();
popstring(paramBuf);
managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (managerHndl == NULL)
{
result = GetLastError();
goto Cleanup1;
}
svcHndl = OpenService(managerHndl, paramBuf, SERVICE_STOP | SERVICE_QUERY_STATUS);
if (svcHndl == NULL)
{
result = GetLastError();
goto Cleanup2;
}
if (!ControlService(svcHndl, SERVICE_CONTROL_STOP, &svcStatus))
{
result = GetLastError();
goto Cleanup3;
}
while (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
oldCheckPoint = svcStatus.dwCheckPoint;
Sleep(svcStatus.dwWaitHint);
if (!QueryServiceStatus(svcHndl, &svcStatus))
{
result = GetLastError();
break;
}
if (oldCheckPoint >= svcStatus.dwCheckPoint)
{
result = ERROR_SERVICE_REQUEST_TIMEOUT;
break;
}
}
if (svcStatus.dwCurrentState == SERVICE_STOPPED)
result = 0;
Cleanup3:
CloseServiceHandle(svcHndl);
Cleanup2:
CloseServiceHandle(managerHndl);
Cleanup1:
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}