705 lines
17 KiB
C
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;
|
|
}
|