// Header
#include
#include
#include
#include
#pragma comment(lib, "SetupAPI.lib")
#ifdef _UNICODE
#define STR_UpdateDriverForPlugAndPlayDevices "UpdateDriverForPlugAndPlayDevicesW"
#else
#define STR_UpdateDriverForPlugAndPlayDevices "UpdateDriverForPlugAndPlayDevicesA"
#endif
typedef BOOL (WINAPI* PUPNP)(HWND hWnd, PCTSTR ptzID, PCTSTR ptzPath, DWORD dwFlags, PBOOL bReboot);
// Compare device
PSTR DevCmp(PSTR pszStr1, PSTR pszStr2)
{
PSTR p = pszStr2;
for (UINT i = 0; *p; p++)
{
if ((*p == '&') && (++i == 2))
{
break;
}
}
UINT uCmp = (UINT) (p - pszStr2);
p = pszStr1;
while (*p)
{
if (UMemCmp(p, pszStr2, uCmp) == 0)
{
return p;
}
p++;
}
return NULL;
}
// CAB callback
UINT CALLBACK DevProc(PVOID pvContext, UINT uMsg, UINT_PTR upParam1, UINT_PTR upParam2)
{
static BOOL s_bExtract = FALSE;
static TCHAR s_tzDevID[MAX_NAME] = {0};
static TCHAR s_tzInfPath[MAX_PATH] = {0};
if (uMsg == SPFILENOTIFY_FILEINCABINET)
{
// Is INF file or followed by INF file
FILE_IN_CABINET_INFO *p = (FILE_IN_CABINET_INFO*) upParam1;
PCTSTR q = UStrRChr(p->NameInCabinet, '\\');
q = q ? (q + 1) : p->NameInCabinet;
if ((*q == '_') || s_bExtract)
{
// Extract INF or driver file
if (*q == '_')
{
q++;
}
UStrCopy(p->FullTargetName + GetTempPath(MAX_PATH, p->FullTargetName), q);
return FILEOP_DOIT;
}
else
{
// Skip
return FILEOP_SKIP;
}
}
else if (uMsg == SPFILENOTIFY_FILEEXTRACTED)
{
PCTSTR ptzTarget = ((FILEPATHS*) upParam1)->Target;
if (UStrStr(ptzTarget, TEXT(".INF")) == NULL)
{
// Not INF
return NO_ERROR;
}
// Open INF
PSTR pszFile = (PSTR) UFileLoad(ptzTarget, NULL);
if (pszFile == NULL)
{
return NO_ERROR;
}
for (PSTR p = (PSTR) pvContext; *p; p += UAStrLen(p) + 1)
{
if ((*p != '#') && DevCmp(pszFile, p))
{
// Found Device
UAStrToStr(s_tzDevID, p, MAX_NAME);
UStrCopy(s_tzInfPath, ptzTarget);
//UTrack(TEXT("\r\nFound %s: %s\r\n\r\n"), s_tzDevID, s_tzInfPath);
s_bExtract = TRUE;
*p = '#';
return NO_ERROR;
}
}
// This is next INF
if (s_bExtract)
{
// Previous is uses INF
s_bExtract = FALSE;
HMODULE hLib = LoadLibrary(TEXT("NewDev"));
if (hLib)
{
// Install INF
PUPNP p = (PUPNP) GetProcAddress(hLib, STR_UpdateDriverForPlugAndPlayDevices);
if (p)
{
BOOL bReboot = FALSE;
p(NULL, s_tzDevID, s_tzInfPath, 3, &bReboot);
UTrack(TEXT("\r\nInstall %s: %s\r\n\r\n"), s_tzDevID, s_tzInfPath);
}
FreeLibrary(hLib);
}
}
// Delete INF
UFileDelete(ptzTarget);
}
return NO_ERROR;
}
#define MAX_DevID (MAX_STR * 4)
UINT DevEnum(PSTR pszDev, PCTSTR ptzClass = REGSTR_KEY_PCIENUM)
{
// Lookup device
HDEVINFO hDev = SetupDiGetClassDevs(NULL, ptzClass, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES );
if (hDev == INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
// Lookup Device ID
UINT uSize = 0;
SP_DEVINFO_DATA sdDev = {sizeof(SP_DEVINFO_DATA)};
for (UINT i = 0; (uSize < MAX_DevID) && SetupDiEnumDeviceInfo(hDev, i, &sdDev); i++)
{
DWORD dwData;
DWORD dwSize = MAX_DevID- uSize;
if (SetupDiGetDeviceRegistryPropertyA(hDev, &sdDev, SPDRP_HARDWAREID, &dwData, (PBYTE) pszDev + uSize, dwSize, &dwSize))
{
#ifndef _DEBUG
// List problem device only
ULONG uProblem = 0;
ULONG uStatus = DN_HAS_PROBLEM;
CM_Get_DevNode_Status(&uStatus, &uProblem, sdDev.DevInst, 0);
if (uProblem)
#endif
{
uSize += UAStrLen(pszDev + uSize) + 1;
}
}
}
SetupDiDestroyDeviceInfoList(hDev);
pszDev[uSize] = pszDev[uSize + 1] = 0;
return uSize;
}
// Install device
HRESULT Devi(PTSTR ptzCmd)
{
// Skip if Control Key pressed.
if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
{
return S_FALSE;
}
// Enum device ID
CHAR szDev[MAX_DevID];
UINT uSize = DevEnum(szDev, TEXT("PCI"));
uSize += DevEnum(szDev + uSize, TEXT("USB"));
if (uSize == 0)
{
// No device
return ERROR_DEVICE_NOT_CONNECTED;
}
#ifdef _DEBUG
for (PSTR p = szDev; *p; p += UAStrLen(p) + 1)
{
UTrack(TEXT("%hs\r\n"), p);
}
#endif
// Lookup CAB file
TCHAR tzPath[MAX_PATH];
ExpandEnvironmentStrings(ptzCmd, tzPath, MAX_PATH);
SetupIterateCabinet(tzPath, 0, DevProc, szDev);
return S_OK;
}