1822 lines
45 KiB
C
1822 lines
45 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
hwdb.c
|
|
|
|
Abstract:
|
|
|
|
PNP device manipulation routines.
|
|
Adapted from the win95upg project.
|
|
|
|
Author:
|
|
|
|
Ovidiu Temereanca (ovidiut) 02-Jul-2000 Initial implementation
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "pch.h"
|
|
#include "hwdbp.h"
|
|
|
|
#define DBG_HWDB "Hwdb"
|
|
|
|
static HANDLE g_hHwdbHeap = NULL;
|
|
static PCSTR g_TempDir = NULL;
|
|
|
|
#define HWCOMPDAT_SIGNATURE "HwCompDat-v2"
|
|
#define MAX_PNPID 1024
|
|
|
|
#ifdef DEBUG
|
|
extern BOOL g_DoLog;
|
|
extern BOOL g_ResetLog;
|
|
#endif
|
|
|
|
typedef struct {
|
|
HANDLE File;
|
|
HASHITEM InfFileOffset;
|
|
BOOL UnsupportedDevice;
|
|
PHWDB Hwbd;
|
|
} SAVE_ENUM_PARAMS, *PSAVE_ENUM_PARAMS;
|
|
|
|
|
|
PCWSTR
|
|
pConvertMultiSzToUnicode (
|
|
IN PCSTR MultiSz
|
|
)
|
|
{
|
|
UINT logChars;
|
|
|
|
if (!MultiSz) {
|
|
return NULL;
|
|
}
|
|
|
|
logChars = MultiSzSizeInCharsA (MultiSz);
|
|
|
|
return DbcsToUnicodeN (NULL, MultiSz, logChars);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// REM - g_ExcludedInfs was removed because hwdb will be used for any 3rd party driver files
|
|
// and we need to make suer ALL infs are scanned
|
|
//
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
|
|
BOOL
|
|
WINAPI
|
|
MigUtil_Entry (
|
|
HINSTANCE hInstance,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved
|
|
);
|
|
|
|
HINSTANCE g_hInst;
|
|
HANDLE g_hHeap;
|
|
|
|
|
|
BOOL
|
|
HwdbpInitialized (
|
|
VOID
|
|
)
|
|
{
|
|
return g_hHwdbHeap != NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpInitialize (
|
|
VOID
|
|
)
|
|
{
|
|
BOOL b = TRUE;
|
|
|
|
//
|
|
// only initialize data once
|
|
//
|
|
MYASSERT (!g_hHwdbHeap);
|
|
|
|
g_hHwdbHeap = HeapCreate (0, 65536, 0);
|
|
if (!g_hHwdbHeap) {
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
g_DoLog = TRUE;
|
|
g_ResetLog = TRUE;
|
|
#endif
|
|
g_hHeap = g_hHwdbHeap;
|
|
|
|
if (!g_hInst) {
|
|
//
|
|
// If DllMain didn't set this, then set it now
|
|
//
|
|
|
|
g_hInst = GetModuleHandle (NULL);
|
|
}
|
|
|
|
if (!MigUtil_Entry (g_hInst, DLL_PROCESS_ATTACH, NULL)) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if (!b) {
|
|
HwdbpTerminate ();
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
HwdbpTerminate (
|
|
VOID
|
|
)
|
|
{
|
|
HwdbpSetTempDir (NULL);
|
|
|
|
MigUtil_Entry (g_hInst, DLL_PROCESS_DETACH, NULL);
|
|
|
|
if (g_hHwdbHeap) {
|
|
HeapDestroy (g_hHwdbHeap);
|
|
g_hHwdbHeap = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
pReadDword (
|
|
IN HANDLE File,
|
|
OUT PDWORD Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pReadDword reads the next DWORD at the current file position of File.
|
|
|
|
Arguments:
|
|
|
|
File - Specifies file to read
|
|
|
|
Data - Receives the DWORD
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
Call GetLastError for additional failure information.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD BytesRead;
|
|
|
|
return ReadFile (File, Data, sizeof (DWORD), &BytesRead, NULL) &&
|
|
BytesRead == sizeof (DWORD);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pReadWord (
|
|
IN HANDLE File,
|
|
OUT PWORD Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pReadWord reads the next WORD at the current file position of File.
|
|
|
|
Arguments:
|
|
|
|
File - Specifies file to read
|
|
|
|
Data - Receive s the WORD
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
Call GetLastError for additional failure information.
|
|
|
|
--*/
|
|
{
|
|
DWORD BytesRead;
|
|
|
|
return ReadFile (File, Data, sizeof (WORD), &BytesRead, NULL) &&
|
|
BytesRead == sizeof (WORD);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pReadString (
|
|
IN HANDLE File,
|
|
OUT PSTR Buf,
|
|
IN DWORD BufSizeInBytes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pReadString reads a WORD length from File, and then reads in the
|
|
string from File.
|
|
|
|
Arguments:
|
|
|
|
File - Specifies file to read
|
|
|
|
Buf - Receives the zero-terminated string
|
|
|
|
BufSizeInBytes - Specifies the size of Buf in bytes
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
This function will fail if the string is larger than Buf.
|
|
Call GetLastError for additional failure information.
|
|
|
|
--*/
|
|
{
|
|
DWORD BytesRead;
|
|
WORD Length;
|
|
|
|
MYASSERT (BufSizeInBytes);
|
|
if (!BufSizeInBytes) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pReadWord (File, &Length)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Length + 1 ) * sizeof (CHAR) > BufSizeInBytes) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Length) {
|
|
if (!ReadFile (File, Buf, Length, &BytesRead, NULL) ||
|
|
Length != BytesRead
|
|
) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
Buf[Length] = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pWriteDword (
|
|
IN HANDLE File,
|
|
IN DWORD Val
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pWriteDword writes the specified DWORD value to File.
|
|
|
|
Arguments:
|
|
|
|
File - Specifies file to write to
|
|
|
|
Val - Specifies value to write
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
Call GetLastError for additional failure information.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD bytesWritten;
|
|
|
|
return WriteFile (File, &Val, sizeof (Val), &bytesWritten, NULL) &&
|
|
bytesWritten == sizeof (Val);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pWriteWord (
|
|
IN HANDLE File,
|
|
IN WORD Val
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pWriteWord writes the specified WORD vlue to File.
|
|
|
|
Arguments:
|
|
|
|
File - Specifies file to write to
|
|
|
|
Val - Specifies value to write
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
Call GetLastError for additional failure information.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD bytesWritten;
|
|
|
|
return WriteFile (File, &Val, sizeof (Val), &bytesWritten, NULL) &&
|
|
bytesWritten == sizeof (Val);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pWriteString (
|
|
IN HANDLE File,
|
|
IN PCSTR String
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pWriteString writes a string to a File
|
|
|
|
Arguments:
|
|
|
|
File - Specifies file to write to
|
|
|
|
String - Specifies the zero-terminated string
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
Call GetLastError for additional failure information.
|
|
|
|
--*/
|
|
{
|
|
DWORD bytesWritten;
|
|
DWORD Length;
|
|
PCSTR End;
|
|
BOOL b = TRUE;
|
|
|
|
Length = lstrlenA (String);
|
|
|
|
if (Length > 0xffff) {
|
|
SetLastError (ERROR_INTERNAL_ERROR);
|
|
DEBUGMSGA ((DBG_ERROR, "pWriteString: string too long!"));
|
|
return FALSE;
|
|
}
|
|
|
|
b = pWriteWord (File, (WORD)Length);
|
|
|
|
if (b && Length) {
|
|
b = WriteFile (File, String, Length, &bytesWritten, NULL) &&
|
|
Length == bytesWritten;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
PHWDB
|
|
HwdbpOpen (
|
|
IN PCSTR DatabaseFile OPTIONAL
|
|
)
|
|
{
|
|
CHAR buffer[MAX_PATH];
|
|
CHAR infFile[MAX_MBCHAR_PATH];
|
|
CHAR pnpId[1024];
|
|
CHAR sig[sizeof (HWCOMPDAT_SIGNATURE)];
|
|
DWORD rc;
|
|
HANDLE file = INVALID_HANDLE_VALUE;
|
|
PHWDB phwdb;
|
|
DWORD BytesRead;
|
|
HASHITEM infOffset, result;
|
|
BOOL b = FALSE;
|
|
|
|
__try {
|
|
|
|
phwdb = (PHWDB) MemAlloc (g_hHwdbHeap, 0, sizeof (*phwdb));
|
|
if (!phwdb) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
ZeroMemory (phwdb, sizeof (*phwdb));
|
|
|
|
//
|
|
// Create hash tables
|
|
//
|
|
phwdb->InfFileTable = HtAlloc ();
|
|
phwdb->PnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
|
|
phwdb->UnsupPnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
|
|
if (!phwdb->InfFileTable || !phwdb->PnpIdTable || !phwdb->UnsupPnpIdTable) {
|
|
__leave;
|
|
}
|
|
|
|
if (DatabaseFile) {
|
|
|
|
if (!GetFullPathNameA (DatabaseFile, ARRAYSIZE(buffer), buffer, NULL)) {
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Try to open the file
|
|
//
|
|
file = CreateFileA (
|
|
buffer,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ, // share for read access
|
|
NULL, // no security attribs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL // no template
|
|
);
|
|
if (file == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
//
|
|
// Look at the signature
|
|
//
|
|
ZeroMemory (sig, sizeof(sig));
|
|
if (!ReadFile (file, sig, sizeof (HWCOMPDAT_SIGNATURE) - 1, &BytesRead, NULL) ||
|
|
lstrcmpA (HWCOMPDAT_SIGNATURE, sig)
|
|
) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
__leave;
|
|
}
|
|
//
|
|
// Get INF checksum
|
|
//
|
|
if (!pReadDword (file, &phwdb->Checksum)) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
__leave;
|
|
}
|
|
//
|
|
// Read in all PNP IDs
|
|
//
|
|
for (;;) {
|
|
//
|
|
// Get INF file name. If empty, we are done.
|
|
//
|
|
if (!pReadString (file, infFile, sizeof (infFile))) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
__leave;
|
|
}
|
|
if (*infFile == 0) {
|
|
break;
|
|
}
|
|
infOffset = HtAddStringA (phwdb->InfFileTable, infFile);
|
|
if (!infOffset) {
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Read in all PNP IDs for the INF
|
|
//
|
|
for (;;) {
|
|
//
|
|
// Get the PNP ID. If empty, we are done.
|
|
//
|
|
if (!pReadString (file, pnpId, sizeof (pnpId))) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
__leave;
|
|
}
|
|
if (*pnpId == 0) {
|
|
break;
|
|
}
|
|
//
|
|
// Add to hash table
|
|
//
|
|
if (*pnpId == '!') {
|
|
result = HtAddStringExA (phwdb->UnsupPnpIdTable, pnpId + 1, &infOffset, CASE_INSENSITIVE);
|
|
} else {
|
|
result = HtAddStringExA (phwdb->PnpIdTable, pnpId, &infOffset, CASE_INSENSITIVE);
|
|
}
|
|
if (!result) {
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
rc = GetLastError ();
|
|
|
|
if (file != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (file);
|
|
}
|
|
if (!b && phwdb) {
|
|
if (phwdb->InfFileTable) {
|
|
HtFree (phwdb->InfFileTable);
|
|
}
|
|
if (phwdb->PnpIdTable) {
|
|
HtFree (phwdb->PnpIdTable);
|
|
}
|
|
if (phwdb->UnsupPnpIdTable) {
|
|
HtFree (phwdb->UnsupPnpIdTable);
|
|
}
|
|
MemFree (g_hHwdbHeap, 0, phwdb);
|
|
}
|
|
|
|
SetLastError (rc);
|
|
}
|
|
|
|
return phwdb;
|
|
}
|
|
|
|
/*
|
|
BOOL
|
|
pWriteHashTableString (
|
|
IN HASHTABLE HashTable,
|
|
IN HASHITEM Index,
|
|
IN PCSTR String,
|
|
IN PVOID ExtraData,
|
|
IN UINT ExtraDataSize,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
MYASSERT (String && *String);
|
|
return pWriteString ((HANDLE)lParam, String);
|
|
}
|
|
*/
|
|
|
|
BOOL
|
|
pSavePnpID (
|
|
IN HASHTABLE Table,
|
|
IN HASHITEM StringId,
|
|
IN PCSTR String,
|
|
IN PVOID ExtraData,
|
|
IN UINT ExtraDataSize,
|
|
IN LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pSavePnpID is a string table callback function that writes a PNP
|
|
ID to the file indicated in the params struct (the lParam argument).
|
|
|
|
This function only writes PNP IDs for a specific INF file (indicated
|
|
by the ExtraData arg).
|
|
|
|
Arguments:
|
|
|
|
Table - Specifies table being enumerated
|
|
|
|
StringId - Specifies offset of string in Table
|
|
|
|
String - Specifies string being enumerated
|
|
|
|
ExtraData - Specifies a pointer to a LONG that holds the INF ID
|
|
to enumerate. The PNP ID's INF ID must match this
|
|
parameter.
|
|
|
|
lParam - Specifies a pointer to a SAVE_ENUM_PARAMS struct
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSAVE_ENUM_PARAMS params;
|
|
CHAR bangString[MAX_PNPID + 2];
|
|
BOOL b = TRUE;
|
|
|
|
params = (PSAVE_ENUM_PARAMS) lParam;
|
|
|
|
if (*(HASHITEM UNALIGNED*)ExtraData == params->InfFileOffset) {
|
|
//
|
|
// Write this PNP ID to the file
|
|
//
|
|
if (params->UnsupportedDevice) {
|
|
|
|
bangString[0] = '!';
|
|
b = SUCCEEDED (StringCchCopyA (bangString + 1, ARRAYSIZE(bangString) - 1, String)) &&
|
|
pWriteString (params->File, bangString);
|
|
|
|
} else {
|
|
|
|
b = pWriteString (params->File, String);
|
|
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pSaveInfWithPnpIDList (
|
|
IN HASHTABLE Table,
|
|
IN HASHITEM StringId,
|
|
IN PCSTR String,
|
|
IN PVOID ExtraData,
|
|
IN UINT ExtraDataSize,
|
|
IN LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pSaveInfWithPnpIDList is a string table callback function and is called for
|
|
each INF in g_InfFileTable.
|
|
|
|
This routine writes the name of the INF to disk, and then enumerates
|
|
the PNP IDs for the INF, writing them to disk.
|
|
|
|
The PNP ID list is terminated with an empty string.
|
|
|
|
Arguments:
|
|
|
|
Table - Specifies g_InfFileTable
|
|
|
|
StringId - Specifies offset of String in g_InfFileTable
|
|
|
|
String - Specifies current INF file being enumerated
|
|
|
|
ExtraData - unused
|
|
|
|
ExtraDataSize - unused
|
|
|
|
lParam - Specifies a pointer to SAVE_ENUM_PARAMS struct.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSAVE_ENUM_PARAMS params;
|
|
|
|
params = (PSAVE_ENUM_PARAMS) lParam;
|
|
params->InfFileOffset = StringId;
|
|
|
|
//
|
|
// Save the file name
|
|
//
|
|
|
|
if (!pWriteString (params->File, String)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enumerate all PNP IDs
|
|
//
|
|
|
|
params->UnsupportedDevice = FALSE;
|
|
|
|
if (!EnumHashTableWithCallbackA (params->Hwbd->PnpIdTable, pSavePnpID, lParam)) {
|
|
LOGA ((LOG_ERROR, "Error while saving device list."));
|
|
return FALSE;
|
|
}
|
|
|
|
params->UnsupportedDevice = TRUE;
|
|
|
|
if (!EnumHashTableWithCallbackA (params->Hwbd->UnsupPnpIdTable, pSavePnpID, lParam)) {
|
|
LOGA ((LOG_ERROR, "Error while saving device list. (2)"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Terminate the PNP ID list
|
|
//
|
|
|
|
if (!pWriteString (params->File, "")) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpFlush (
|
|
IN PHWDB Hwdb,
|
|
IN PCSTR OutputFile
|
|
)
|
|
{
|
|
CHAR buffer[MAX_PATH];
|
|
DWORD rc;
|
|
HANDLE file = INVALID_HANDLE_VALUE;
|
|
DWORD bytesWritten;
|
|
SAVE_ENUM_PARAMS params;
|
|
BOOL b = FALSE;
|
|
|
|
__try {
|
|
if (!OutputFile) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
__leave;
|
|
}
|
|
|
|
if (!GetFullPathNameA (OutputFile, ARRAYSIZE(buffer), buffer, NULL)) {
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Try to open the file
|
|
//
|
|
file = CreateFileA (
|
|
OutputFile,
|
|
GENERIC_WRITE,
|
|
0, // no sharing
|
|
NULL, // no security attribs
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL // no template
|
|
);
|
|
if (file == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
//
|
|
// Write the signature
|
|
//
|
|
if (!WriteFile (file, HWCOMPDAT_SIGNATURE, sizeof (HWCOMPDAT_SIGNATURE) - 1, &bytesWritten, NULL)) {
|
|
__leave;
|
|
}
|
|
//
|
|
// Store INF checksum
|
|
//
|
|
if (!pWriteDword (file, Hwdb->Checksum)) {
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Enumerate the INF table, writing the INF file name and all PNP IDs
|
|
//
|
|
|
|
params.File = file;
|
|
params.Hwbd = Hwdb;
|
|
|
|
if (!EnumHashTableWithCallbackA (
|
|
Hwdb->InfFileTable,
|
|
pSaveInfWithPnpIDList,
|
|
(LPARAM) (¶ms)
|
|
)) {
|
|
DEBUGMSGA ((DBG_WARNING, "SaveDeviceList: EnumHashTableWithCallbackA returned FALSE"));
|
|
__leave;
|
|
}
|
|
//
|
|
// end with an empty string
|
|
//
|
|
pWriteString (file, "");
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
rc = GetLastError ();
|
|
|
|
if (file != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (file);
|
|
}
|
|
if (!b) {
|
|
DeleteFile (OutputFile);
|
|
}
|
|
|
|
SetLastError (rc);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpClose (
|
|
IN PHWDB Hwdb
|
|
)
|
|
{
|
|
BOOL b = FALSE;
|
|
|
|
__try {
|
|
if (Hwdb) {
|
|
if (Hwdb->InfFileTable) {
|
|
HtFree (Hwdb->InfFileTable);
|
|
}
|
|
if (Hwdb->PnpIdTable) {
|
|
HtFree (Hwdb->PnpIdTable);
|
|
}
|
|
if (Hwdb->UnsupPnpIdTable) {
|
|
HtFree (Hwdb->UnsupPnpIdTable);
|
|
}
|
|
|
|
MemFree (g_hHwdbHeap, 0, Hwdb);
|
|
|
|
b = TRUE;
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwpIsValidInfName (
|
|
IN PCSTR FileName,
|
|
OUT PSTR UncompressedFileName,
|
|
IN DWORD BufferSizeInChars
|
|
)
|
|
{
|
|
PSTR p;
|
|
PCSTR* q;
|
|
PCSTR comparationName;
|
|
|
|
if (!FileName || *FileName == 0) {
|
|
MYASSERT (FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (FAILED (StringCchCopyA (UncompressedFileName, BufferSizeInChars, FileName))) {
|
|
return FALSE;
|
|
}
|
|
|
|
p = our_mbsdec (UncompressedFileName, GetEndOfStringA (UncompressedFileName));
|
|
if (!p) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (*p == '_') {
|
|
*p = 'f';
|
|
comparationName = UncompressedFileName;
|
|
} else {
|
|
if (_mbctolower (_mbsnextc (p)) != 'f') {
|
|
return FALSE;
|
|
}
|
|
*UncompressedFileName = 0;
|
|
comparationName = FileName;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwpAddPnpIdsInInf (
|
|
IN PCSTR InfPath,
|
|
IN OUT PHWDB Hwdb,
|
|
IN PCSTR SourceDirectory,
|
|
IN PCSTR InfFilename,
|
|
IN HWDBAPPENDINFSCALLBACKA Callback, OPTIONAL
|
|
IN PVOID CallbackContext, OPTIONAL
|
|
IN BOOL CallbackIsUnicode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
HwpAddPnpIdsInInf scans an NT INF and places all hardware device
|
|
IDs in the PNP string table.
|
|
|
|
Arguments:
|
|
|
|
InfPath - The path to an INF file
|
|
Hwdb - Database to append PNPIDs to
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function completes successfully, or FALSE if it fails.
|
|
Call GetLastError for additional failure information.
|
|
|
|
--*/
|
|
|
|
{
|
|
HINF inf;
|
|
INFCONTEXT is;
|
|
INFCONTEXT isMfg;
|
|
INFCONTEXT isDev;
|
|
CHAR manufacturer[2048];
|
|
CHAR devSection[2048];
|
|
CHAR pnpId[2048];
|
|
BOOL unsupportedDevice;
|
|
PSTR AppendPos;
|
|
CHAR trimmedPnpId[512];
|
|
CHAR field[12];
|
|
PCSTR p;
|
|
LONG rc;
|
|
BOOL b;
|
|
PCSTR fileName;
|
|
PCWSTR uInfPath = NULL;
|
|
PCWSTR uSourceDirectory = NULL;
|
|
PCWSTR uInfFilename = NULL;
|
|
HASHITEM infOffset = NULL;
|
|
BOOL result = FALSE;
|
|
|
|
//
|
|
// Determine if this is an NT4 INF
|
|
//
|
|
inf = SetupOpenInfFileA (InfPath, NULL, INF_STYLE_WIN4, NULL);
|
|
if (inf == INVALID_HANDLE_VALUE) {
|
|
DEBUGMSGA ((DBG_ERROR, "HwpAddPnpIdsInInf: SetupOpenInfFileA (%s) failed", InfPath));
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUGMSGA ((DBG_HWDB, "HwpAddPnpIdsInInf: analyzing %s", InfPath));
|
|
|
|
__try {
|
|
//
|
|
// Enumerate [Manufacturer] section
|
|
//
|
|
if (SetupFindFirstLineA (inf, "Manufacturer", NULL, &is)) {
|
|
|
|
do {
|
|
//
|
|
// Get the manufacturer name
|
|
//
|
|
if (!SetupGetLineTextA (&is, NULL, NULL, NULL, manufacturer, ARRAYSIZE(manufacturer), NULL)) {
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwpAddPnpIdsInInf: SetupGetLineText failed at line %u in [Manufacturer]",
|
|
is.Line
|
|
));
|
|
__leave;
|
|
}
|
|
//
|
|
// Enumerate the devices listed in the manufacturer's section,
|
|
// looking for PnpId
|
|
//
|
|
if (!SetupFindFirstLineA (inf, manufacturer, NULL, &isMfg)) {
|
|
rc = GetLastError();
|
|
//
|
|
// if section not found, move on to next manufacturer
|
|
//
|
|
if (rc == ERROR_SECTION_NOT_FOUND || rc == ERROR_LINE_NOT_FOUND) {
|
|
DEBUGMSGA ((
|
|
DBG_HWDB,
|
|
"HwpAddPnpIdsInInf: manufacturer %s section does not exist",
|
|
manufacturer
|
|
));
|
|
continue;
|
|
}
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwpAddPnpIdsInInf: error searching for lines in [%s]",
|
|
manufacturer
|
|
));
|
|
__leave;
|
|
}
|
|
|
|
do {
|
|
if (!SetupGetStringFieldA (&isMfg, 1, devSection, ARRAYSIZE(devSection), NULL)) {
|
|
DEBUGMSGA ((
|
|
DBG_HWDB,
|
|
"HwpAddPnpIdsInInf: error retrieving first field in line %u in [%s]",
|
|
isMfg.Line,
|
|
devSection
|
|
));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Try platform-specific section first, then section.NT, then section
|
|
//
|
|
AppendPos = GetEndOfStringA (devSection);
|
|
#if defined(_AMD64_)
|
|
if (FAILED (StringCchPrintfA (
|
|
AppendPos,
|
|
ARRAYSIZE(devSection) - (AppendPos - devSection),
|
|
TEXT(".%s"),
|
|
INFSTR_PLATFORM_NTAMD64
|
|
))) {
|
|
#elif defined(_IA64_)
|
|
if (FAILED (StringCchPrintfA (
|
|
AppendPos,
|
|
ARRAYSIZE(devSection) - (AppendPos - devSection),
|
|
TEXT(".%s"),
|
|
INFSTR_PLATFORM_NTIA64
|
|
))) {
|
|
#elif defined(_X86_)
|
|
if (FAILED (StringCchPrintfA (
|
|
AppendPos,
|
|
ARRAYSIZE(devSection) - (AppendPos - devSection),
|
|
TEXT(".%s"),
|
|
INFSTR_PLATFORM_NTX86
|
|
))) {
|
|
#else
|
|
#error "No Target Architecture"
|
|
#endif
|
|
__leave;
|
|
}
|
|
|
|
b = SetupFindFirstLineA (inf, devSection, NULL, &isDev);
|
|
if (!b) {
|
|
if (FAILED (StringCchPrintfA (
|
|
AppendPos,
|
|
ARRAYSIZE(devSection) - (AppendPos - devSection),
|
|
TEXT(".%s"),
|
|
INFSTR_PLATFORM_NT
|
|
))) {
|
|
__leave;
|
|
}
|
|
b = SetupFindFirstLineA (inf, devSection, NULL, &isDev);
|
|
if (!b) {
|
|
*AppendPos = 0;
|
|
b = SetupFindFirstLineA (inf, devSection, NULL, &isDev);
|
|
}
|
|
}
|
|
|
|
unsupportedDevice = FALSE;
|
|
if (b) {
|
|
if (SetupFindFirstLineA (inf, devSection, "DeviceUpgradeUnsupported", &isDev)) {
|
|
if (SetupGetStringFieldA (&isDev, 1, field, ARRAYSIZE(field), NULL)) {
|
|
if (atoi (field)) {
|
|
unsupportedDevice = TRUE;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
DEBUGMSGA ((
|
|
DBG_HWDB,
|
|
"HwpAddPnpIdsInInf: no device section [%s] for [%s]",
|
|
devSection,
|
|
manufacturer
|
|
));
|
|
}
|
|
|
|
//
|
|
// Get the device id
|
|
//
|
|
if (!SetupGetMultiSzFieldA (&isMfg, 2, pnpId, ARRAYSIZE(pnpId), NULL)) {
|
|
DEBUGMSGA ((
|
|
DBG_HWDB,
|
|
"HwpAddPnpIdsInInf: error retrieving PNPID field(s) in line %u in [%s]",
|
|
isMfg.Line,
|
|
manufacturer
|
|
));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Add each device id to the hash table
|
|
//
|
|
p = pnpId;
|
|
while (*p) {
|
|
BOOL b = TRUE;
|
|
//
|
|
// first invoke the callback (if specified)
|
|
//
|
|
if (Callback) {
|
|
if (CallbackIsUnicode) {
|
|
PCWSTR uPnpid = ConvertAtoW (p);
|
|
if (!uPnpid) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
if (!uInfPath) {
|
|
uInfPath = ConvertAtoW (InfPath);
|
|
}
|
|
if (!uSourceDirectory) {
|
|
uSourceDirectory = ConvertAtoW (SourceDirectory);
|
|
}
|
|
if (!uInfFilename) {
|
|
uInfFilename = ConvertAtoW (InfFilename);
|
|
}
|
|
b = (*(HWDBAPPENDINFSCALLBACKW)Callback) (CallbackContext, uPnpid, uInfFilename, uSourceDirectory, uInfPath);
|
|
FreeConvertedStr (uPnpid);
|
|
} else {
|
|
b = (*Callback) (CallbackContext, p, InfFilename, SourceDirectory, InfPath);
|
|
}
|
|
}
|
|
if (b) {
|
|
//
|
|
// First time through add the INF file name to string table
|
|
//
|
|
if (!infOffset) {
|
|
if (Hwdb->InfFileTable) {
|
|
fileName = _mbsrchr (InfPath, '\\') + 1;
|
|
infOffset = HtAddStringA (Hwdb->InfFileTable, fileName);
|
|
if (!infOffset) {
|
|
DEBUGMSGA ((DBG_ERROR, "Cannot add %s to table of INFs.", fileName));
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED (StringCchCopyA (trimmedPnpId, ARRAYSIZE(trimmedPnpId), SkipSpaceA (p)))) {
|
|
__leave;
|
|
}
|
|
TruncateTrailingSpaceA (trimmedPnpId);
|
|
|
|
if (!HtAddStringExA (
|
|
unsupportedDevice ? Hwdb->UnsupPnpIdTable : Hwdb->PnpIdTable,
|
|
trimmedPnpId,
|
|
(PVOID)&infOffset,
|
|
CASE_INSENSITIVE
|
|
)) {
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwpAddPnpIdsInInf: cannot add %s to table of PNP IDs",
|
|
trimmedPnpId
|
|
));
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
p = GetEndOfStringA (p) + 1;
|
|
}
|
|
|
|
} while (SetupFindNextLine (&isMfg, &isMfg));
|
|
|
|
} while (SetupFindNextLine (&is, &is));
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
//
|
|
// If section not found, return success
|
|
//
|
|
if (rc == ERROR_SECTION_NOT_FOUND || rc == ERROR_LINE_NOT_FOUND) {
|
|
SetLastError (ERROR_SUCCESS);
|
|
DEBUGMSGA ((
|
|
DBG_HWDB,
|
|
"HwpAddPnpIdsInInf: %s has no [manufacturer] section or it's empty",
|
|
InfPath
|
|
));
|
|
} else {
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwpAddPnpIdsInInf: error trying to find the [manufacturer] section",
|
|
InfPath
|
|
));
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
result = TRUE;
|
|
}
|
|
__finally {
|
|
PushError();
|
|
SetupCloseInfFile (inf);
|
|
FreeConvertedStr (uInfPath);
|
|
FreeConvertedStr (uSourceDirectory);
|
|
FreeConvertedStr (uInfFilename);
|
|
PopError();
|
|
DEBUGMSGA ((DBG_HWDB, "HwpAddPnpIdsInInf: done parsing %s", InfPath));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpAppendInfs (
|
|
IN PHWDB Hwdb,
|
|
IN PCSTR SourceDirectory,
|
|
IN HWDBAPPENDINFSCALLBACKA Callback, OPTIONAL
|
|
IN PVOID CallbackContext, OPTIONAL
|
|
IN BOOL CallbackIsUnicode
|
|
)
|
|
{
|
|
HANDLE h;
|
|
WIN32_FIND_DATA fd;
|
|
CHAR buffer[MAX_PATH];
|
|
CHAR uncompressedFile[MAX_PATH];
|
|
CHAR fullPath[MAX_PATH];
|
|
DWORD rc;
|
|
|
|
if (!g_TempDir) {
|
|
//
|
|
// the temp dir must be set first
|
|
//
|
|
SetLastError (ERROR_INVALID_FUNCTION);
|
|
return FALSE;
|
|
}
|
|
|
|
if (FAILED (StringCchPrintfA (buffer, ARRAYSIZE(buffer), "%s\\*.in?", SourceDirectory))) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwdbpAppendInfs: SourceDir name too long: %s",
|
|
SourceDirectory
|
|
));
|
|
return FALSE;
|
|
}
|
|
|
|
h = FindFirstFileA (buffer, &fd);
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
if (!HwpIsValidInfName (fd.cFileName, buffer, ARRAYSIZE(buffer))) {
|
|
continue;
|
|
}
|
|
if (*buffer) {
|
|
if (FAILED (StringCchPrintfA (uncompressedFile, ARRAYSIZE(uncompressedFile), "%s\\%s", g_TempDir, buffer))) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwdbpAppendInfs: file name too long: %s\\%s",
|
|
g_TempDir,
|
|
buffer
|
|
));
|
|
continue;
|
|
}
|
|
if (FAILED (StringCchPrintfA (fullPath, ARRAYSIZE(fullPath), "%s\\%s", SourceDirectory, fd.cFileName))) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwdbpAppendInfs: file name too long: %s\\%s",
|
|
SourceDirectory,
|
|
fd.cFileName
|
|
));
|
|
continue;
|
|
}
|
|
|
|
SetFileAttributesA (uncompressedFile, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFileA (uncompressedFile);
|
|
|
|
rc = SetupDecompressOrCopyFileA (fullPath, uncompressedFile, 0);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((
|
|
LOG_ERROR,
|
|
"HwdbpAppendInfs: Could not decompress %s to %s",
|
|
fullPath,
|
|
uncompressedFile
|
|
));
|
|
continue;
|
|
}
|
|
} else {
|
|
if (FAILED (StringCchPrintfA (uncompressedFile, ARRAYSIZE(uncompressedFile), "%s\\%s", SourceDirectory, fd.cFileName))) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwdbpAppendInfs: file name too long: %s\\%s",
|
|
g_TempDir,
|
|
buffer
|
|
));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!HwpAddPnpIdsInInf (
|
|
uncompressedFile,
|
|
Hwdb,
|
|
SourceDirectory,
|
|
*buffer ? buffer : fd.cFileName,
|
|
Callback,
|
|
CallbackContext,
|
|
CallbackIsUnicode
|
|
)) {
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"HwdbpAppendInfs: HwpAddPnpIdsInInf(%s) failed",
|
|
*buffer ? fullPath : uncompressedFile
|
|
));
|
|
continue;
|
|
}
|
|
|
|
if (*buffer) {
|
|
SetFileAttributesA (uncompressedFile, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFileA (uncompressedFile);
|
|
}
|
|
} while (FindNextFile (h, &fd));
|
|
|
|
FindClose (h);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pAppendToHashTable (
|
|
IN HASHTABLE HashTable,
|
|
IN HASHITEM Index,
|
|
IN PCSTR String,
|
|
IN PVOID ExtraData,
|
|
IN UINT ExtraDataSize,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
MYASSERT (lParam);
|
|
return HtAddStringA ((HASHTABLE)lParam, String) != NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpAppendDatabase (
|
|
IN PHWDB HwdbTarget,
|
|
IN PHWDB HwdbSource
|
|
)
|
|
{
|
|
#if 0
|
|
BOOL b = TRUE;
|
|
|
|
if (HwdbSource->PnpIdTable) {
|
|
if (!HwdbTarget->PnpIdTable) {
|
|
HwdbTarget->PnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
|
|
if (!HwdbTarget->PnpIdTable) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
if (b) {
|
|
b = EnumHashTableWithCallbackA (
|
|
HwdbSource->PnpIdTable,
|
|
pAppendToHashTable,
|
|
HwdbTarget->PnpIdTable
|
|
);
|
|
}
|
|
}
|
|
if (b && HwdbSource->UnsupPnpIdTable) {
|
|
if (!HwdbTarget->UnsupPnpIdTable) {
|
|
HwdbTarget->UnsupPnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
|
|
if (!HwdbTarget->UnsupPnpIdTable) {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
if (b) {
|
|
b = EnumHashTableWithCallbackA (
|
|
HwdbSource->UnsupPnpIdTable,
|
|
pAppendToHashTable,
|
|
HwdbTarget->UnsupPnpIdTable
|
|
);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
#endif
|
|
//
|
|
// not implemented
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpHasDriver (
|
|
IN PHWDB Hwdb,
|
|
IN PCSTR PnpId,
|
|
OUT PBOOL Unsupported
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
HwdbpHasDriver determines if the PnpId is in the database
|
|
|
|
Arguments:
|
|
|
|
Hwdb - Specifies the database to search
|
|
|
|
PnpId - Specifies the PNPID to look for
|
|
|
|
Unsupported - Receives TRUE if the PNPID is unsupported
|
|
|
|
Return Value:
|
|
|
|
TRUE if the database has the PNPID
|
|
|
|
--*/
|
|
|
|
{
|
|
if (!Hwdb || !PnpId || !Unsupported) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// check if it's unsupported first
|
|
//
|
|
if (HtFindStringA (Hwdb->UnsupPnpIdTable, PnpId)) {
|
|
*Unsupported = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!HtFindStringA (Hwdb->PnpIdTable, PnpId)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// fill out info
|
|
//
|
|
*Unsupported = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpHasAnyDriver (
|
|
IN PHWDB Hwdb,
|
|
IN PCSTR PnpIds,
|
|
OUT PBOOL Unsupported
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
HwdbpHasAnyDriver determines if any PNPID from the PnpIds multisz is in the database
|
|
|
|
Arguments:
|
|
|
|
Hwdb - Specifies the database to search
|
|
|
|
PnpIds - Specifies the list (multisz) of PNPIDs to look for
|
|
|
|
Unsupported - Receives TRUE if any PNPID in this list is unsupported
|
|
|
|
Return Value:
|
|
|
|
TRUE if the database has at least one of the PNPIDs in the list
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bFound = FALSE;
|
|
PCSTR pnpID;
|
|
|
|
if (!Hwdb || !PnpIds || !Unsupported) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
for (pnpID = PnpIds; *pnpID; pnpID = strchr (pnpID, 0) + 1) {
|
|
//
|
|
// check if it's unsupported first
|
|
//
|
|
if (HtFindStringA (Hwdb->UnsupPnpIdTable, pnpID)) {
|
|
*Unsupported = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if (HtFindStringA (Hwdb->PnpIdTable, pnpID)) {
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// fill out info
|
|
//
|
|
*Unsupported = FALSE;
|
|
|
|
return bFound;
|
|
}
|
|
|
|
#if 0
|
|
|
|
typedef struct {
|
|
PHWDB Hwdb;
|
|
PHWDBENUM_CALLBACKA EnumCallback;
|
|
PVOID UserContext;
|
|
} HWDBENUM_DATAA, *PHWDBENUM_DATAA;
|
|
|
|
typedef struct {
|
|
PHWDB Hwdb;
|
|
PHWDBENUM_CALLBACKW EnumCallback;
|
|
PVOID UserContext;
|
|
} HWDBENUM_DATAW, *PHWDBENUM_DATAW;
|
|
|
|
|
|
BOOL
|
|
pCallbackEnumA (
|
|
IN HASHTABLE HashTable,
|
|
IN HASHITEM Index,
|
|
IN PCSTR PnpId,
|
|
IN PVOID ExtraData,
|
|
IN UINT ExtraDataSize,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
PHWDBENUM_DATAA ped = (PHWDBENUM_DATAA)lParam;
|
|
/*
|
|
PPNPID_DATA data = (PPNPID_DATA)ExtraData;
|
|
|
|
MYASSERT (ExtraDataSize == sizeof (PNPID_DATA);
|
|
|
|
return (*ped->EnumCallback) (
|
|
ped->UserContext,
|
|
PnpId,
|
|
pGetInfPath (ped->Hwdb, data->InfOffset),
|
|
data->Flags
|
|
);
|
|
*/
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
HwdbpEnumeratePnpIdA (
|
|
IN PHWDB Hwdb,
|
|
IN PHWDBENUM_CALLBACKA EnumCallback,
|
|
IN PVOID UserContext
|
|
)
|
|
{
|
|
HWDBENUM_DATAA ed;
|
|
|
|
if (!Hwdb || !EnumCallback) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
ed.Hwdb = Hwdb;
|
|
ed.EnumCallback = EnumCallback;
|
|
ed.UserContext = UserContext;
|
|
return EnumHashTableWithCallbackA (Hwdb->PnpIdTable, pCallbackEnumA, (LPARAM)&ed);
|
|
}
|
|
|
|
BOOL
|
|
pCallbackEnumW (
|
|
IN HASHTABLE HashTable,
|
|
IN HASHITEM Index,
|
|
IN PCSTR PnpId,
|
|
IN PVOID ExtraData,
|
|
IN UINT ExtraDataSize,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
PHWDBENUM_DATAW ped = (PHWDBENUM_DATAW)lParam;
|
|
/*
|
|
PPNPID_DATA data = (PPNPID_DATA)ExtraData;
|
|
|
|
MYASSERT (ExtraDataSize == sizeof (PNPID_DATA);
|
|
|
|
return (*ped->EnumCallback) (
|
|
ped->UserContext,
|
|
PnpId,
|
|
pGetInfPath (ped->Hwdb, data->InfOffset),
|
|
data->Flags
|
|
);
|
|
*/
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
HwdbpEnumeratePnpIdW (
|
|
IN PHWDB Hwdb,
|
|
IN PHWDBENUM_CALLBACKW EnumCallback,
|
|
IN PVOID UserContext
|
|
)
|
|
{
|
|
HWDBENUM_DATAW ed;
|
|
|
|
if (!Hwdb || !EnumCallback) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
ed.Hwdb = Hwdb;
|
|
ed.EnumCallback = EnumCallback;
|
|
ed.UserContext = UserContext;
|
|
return EnumHashTableWithCallbackA (Hwdb->PnpIdTable, pCallbackEnumW, (LPARAM)&ed);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
BOOL
|
|
HwdbpEnumFirstInfA (
|
|
OUT PHWDBINF_ENUMA EnumPtr,
|
|
IN PCSTR DatabaseFile
|
|
)
|
|
{
|
|
CHAR buffer[MAX_PATH];
|
|
CHAR sig[sizeof (HWCOMPDAT_SIGNATURE)];
|
|
DWORD checksum;
|
|
DWORD rc;
|
|
DWORD BytesRead;
|
|
HASHITEM infOffset;
|
|
PHWDBINF_ENUM_INTERNAL pei;
|
|
|
|
if (!DatabaseFile || !EnumPtr) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetFullPathNameA (DatabaseFile, MAX_PATH, buffer, NULL)) {
|
|
return FALSE;
|
|
}
|
|
|
|
EnumPtr->Internal = (PHWDBINF_ENUM_INTERNAL) MemAlloc (g_hHwdbHeap, 0, sizeof (HWDBINF_ENUM_INTERNAL));
|
|
if (!EnumPtr->Internal) {
|
|
SetLastError (ERROR_OUTOFMEMORY);
|
|
return FALSE;
|
|
}
|
|
ZeroMemory (EnumPtr->Internal, sizeof (HWDBINF_ENUM_INTERNAL));
|
|
pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
|
|
|
|
//
|
|
// Try to open the file
|
|
//
|
|
pei->File = CreateFileA (
|
|
buffer,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ, // share for read access
|
|
NULL, // no security attribs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL // no template
|
|
);
|
|
if (pei->File == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Look at the signature
|
|
//
|
|
ZeroMemory (sig, sizeof(sig));
|
|
if (!ReadFile (pei->File, sig, sizeof (HWCOMPDAT_SIGNATURE) - 1, &BytesRead, NULL) ||
|
|
lstrcmpA (HWCOMPDAT_SIGNATURE, sig)
|
|
) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get INF checksum
|
|
//
|
|
if (!pReadDword (pei->File, &checksum)) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
//
|
|
// Read in all PNP IDs
|
|
//
|
|
return HwdbpEnumNextInfA (EnumPtr);
|
|
|
|
exit:
|
|
HwdbpAbortEnumInfA (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpEnumFirstInfW (
|
|
OUT PHWDBINF_ENUMW EnumPtr,
|
|
IN PCSTR DatabaseFile
|
|
)
|
|
{
|
|
HWDBINF_ENUMA ea;
|
|
|
|
if (!HwdbpEnumFirstInfA (&ea, DatabaseFile)) {
|
|
return FALSE;
|
|
}
|
|
EnumPtr->Internal = ea.Internal;
|
|
EnumPtr->InfFile = ConvertAtoW (ea.InfFile);
|
|
EnumPtr->PnpIds = pConvertMultiSzToUnicode (ea.PnpIds);
|
|
if (EnumPtr->InfFile && EnumPtr->PnpIds) {
|
|
return TRUE;
|
|
}
|
|
HwdbpAbortEnumInfW (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HwdbpEnumNextInfA (
|
|
IN OUT PHWDBINF_ENUMA EnumPtr
|
|
)
|
|
{
|
|
CHAR pnpId[1024];
|
|
PHWDBINF_ENUM_INTERNAL pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
|
|
|
|
//
|
|
// Get next INF file name. If empty, we are done.
|
|
//
|
|
if (!pReadString (pei->File, EnumPtr->InfFile, sizeof (EnumPtr->InfFile))) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
if (EnumPtr->InfFile[0] == 0) {
|
|
SetLastError (ERROR_SUCCESS);
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Read in all PNP IDs for the INF
|
|
//
|
|
for (;;) {
|
|
//
|
|
// Get the PNP ID. If empty, we are done.
|
|
//
|
|
if (!pReadString (pei->File, pnpId, sizeof (pnpId))) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
if (*pnpId == 0) {
|
|
break;
|
|
}
|
|
|
|
if (!MultiSzAppendA (&pei->GrowBuf, pnpId)) {
|
|
SetLastError (ERROR_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
EnumPtr->PnpIds = (PCSTR)pei->GrowBuf.Buf;
|
|
|
|
return TRUE;
|
|
|
|
exit:
|
|
HwdbpAbortEnumInfA (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
HwdbpEnumNextInfW (
|
|
IN OUT PHWDBINF_ENUMW EnumPtr
|
|
)
|
|
{
|
|
HWDBINF_ENUMA ea;
|
|
|
|
ea.Internal = EnumPtr->Internal;
|
|
|
|
if (!HwdbpEnumNextInfA (&ea)) {
|
|
return FALSE;
|
|
}
|
|
EnumPtr->InfFile = ConvertAtoW (ea.InfFile);
|
|
EnumPtr->PnpIds = pConvertMultiSzToUnicode (ea.PnpIds);
|
|
if (EnumPtr->InfFile && EnumPtr->PnpIds) {
|
|
return TRUE;
|
|
}
|
|
HwdbpAbortEnumInfW (EnumPtr);
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
HwdbpAbortEnumInfA (
|
|
IN OUT PHWDBINF_ENUMA EnumPtr
|
|
)
|
|
{
|
|
PHWDBINF_ENUM_INTERNAL pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
|
|
DWORD rc = GetLastError ();
|
|
|
|
if (pei) {
|
|
if (pei->File != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (pei->File);
|
|
pei->File = INVALID_HANDLE_VALUE;
|
|
}
|
|
FreeGrowBuffer (&pei->GrowBuf);
|
|
}
|
|
|
|
SetLastError (rc);
|
|
}
|
|
|
|
|
|
VOID
|
|
HwdbpAbortEnumInfW (
|
|
IN OUT PHWDBINF_ENUMW EnumPtr
|
|
)
|
|
{
|
|
PHWDBINF_ENUM_INTERNAL pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
|
|
DWORD rc = GetLastError ();
|
|
|
|
if (EnumPtr->InfFile) {
|
|
FreeConvertedStr (EnumPtr->InfFile);
|
|
EnumPtr->InfFile = NULL;
|
|
}
|
|
if (EnumPtr->PnpIds) {
|
|
FreeConvertedStr (EnumPtr->PnpIds);
|
|
EnumPtr->PnpIds = NULL;
|
|
}
|
|
if (pei) {
|
|
if (pei->File != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (pei->File);
|
|
pei->File = INVALID_HANDLE_VALUE;
|
|
}
|
|
FreeGrowBuffer (&pei->GrowBuf);
|
|
}
|
|
|
|
SetLastError (rc);
|
|
}
|
|
|
|
BOOL
|
|
HwdbpSetTempDir (
|
|
IN PCSTR TempDir
|
|
)
|
|
{
|
|
BOOL b = TRUE;
|
|
|
|
if (TempDir) {
|
|
g_TempDir = DuplicateTextA (TempDir);
|
|
if (!g_TempDir) {
|
|
b = FALSE;
|
|
}
|
|
} else {
|
|
if (g_TempDir) {
|
|
FreeTextA (g_TempDir);
|
|
g_TempDir = NULL;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|