724 lines
18 KiB
C
724 lines
18 KiB
C
#include "pch.h"
|
|
|
|
#ifdef UNICODE
|
|
#error UNICODE not allowed
|
|
#endif
|
|
|
|
#define PNPREPT_HWND (HWND)1
|
|
|
|
BOOL
|
|
WINAPI
|
|
MemDb_Entry (
|
|
IN HINSTANCE hinstDLL,
|
|
IN DWORD dwReason,
|
|
IN LPVOID lpv
|
|
);
|
|
|
|
BOOL
|
|
WINAPI
|
|
MigUtil_Entry (
|
|
HINSTANCE hinstDLL,
|
|
DWORD fdwReason,
|
|
LPVOID lpvReserved
|
|
);
|
|
|
|
|
|
VOID
|
|
pInitProgBarVars (
|
|
VOID
|
|
);
|
|
|
|
INT
|
|
pCallMains (
|
|
DWORD Reason
|
|
)
|
|
{
|
|
if (!MigUtil_Entry (g_hInst, Reason, NULL)) {
|
|
fprintf (stderr, "MigUtil_Entry error!\n");
|
|
return 254;
|
|
}
|
|
|
|
if (!MemDb_Entry (g_hInst, Reason, NULL)) {
|
|
fprintf (stderr, "MemDb_Entry error!\n");
|
|
return 254;
|
|
}
|
|
|
|
if (!HwComp_Entry (g_hInst, Reason, NULL)) {
|
|
fprintf (stderr, "HwComp_Entry error!\n");
|
|
return 254;
|
|
}
|
|
|
|
pInitProgBarVars();
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL CancelFlag = FALSE;
|
|
BOOL *g_CancelFlagPtr = &CancelFlag;
|
|
|
|
#ifdef PRERELEASE
|
|
BOOL g_Stress;
|
|
#endif
|
|
|
|
HANDLE g_hHeap;
|
|
HINSTANCE g_hInst;
|
|
HINF g_OverrideInf = INVALID_HANDLE_VALUE;
|
|
BOOL g_ManualOverrideMode = FALSE;
|
|
|
|
CHAR g_TempDirBuf[MAX_MBCHAR_PATH]; // location for hwcomp.dat
|
|
CHAR g_TempDirWackBuf[MAX_MBCHAR_PATH];
|
|
CHAR g_WinDirBuf[MAX_MBCHAR_PATH];
|
|
INT g_TempDirWackChars;
|
|
PCSTR g_SourceDirectories[MAX_SOURCE_COUNT]; // location of INFs
|
|
DWORD g_SourceDirectoryCount;
|
|
PSTR g_TempDir;
|
|
PSTR g_TempDirWack;
|
|
PSTR g_WinDir;
|
|
|
|
USEROPTIONS g_ConfigOptions; // Needed by migutil. Unused.
|
|
|
|
extern HWND g_Component, g_SubComponent;
|
|
|
|
void
|
|
HelpAndExit (
|
|
void
|
|
)
|
|
{
|
|
fprintf (stderr,
|
|
"Command line syntax:\n\n"
|
|
"pnprept {-a|-s|-u|-c} [-e<n>] <Inf Dir 1> <Inf Dir 2>\n\n"
|
|
"Optional Arguments:\n"
|
|
" <Inf Dir 1> - Specifies the directory containing the first set of INFs\n"
|
|
" <Inf Dir 2> - Specifies the directory containing the second set of INFs\n"
|
|
"\nOutput Options (specify at least one):\n"
|
|
" -a - Dumps all devices for both Dir 1 and Dir 2.\n"
|
|
" -1 - Dumps devices supported by Dir 1 only (devices unsupported by Dir 2)\n"
|
|
" -2 - Dumps devices supported by Dir 2 only (devices unsupported by Dir 1)\n"
|
|
" -c - Dumps devices common to Dir 1 and Dir 2\n"
|
|
"\nOther Options:\n"
|
|
" -i:<path> - Specifies path to win95upg.inf for override list\n"
|
|
" -m - Dumps only PNP IDs that are manually overridden (requires -i)\n"
|
|
" -e<n> - Puts an equals instead of a tab after column <n>\n"
|
|
"\n"
|
|
);
|
|
|
|
exit(255);
|
|
}
|
|
|
|
DWORD g_Mode = 0;
|
|
#define MODE_DIR1 0x0001
|
|
#define MODE_DIR2 0x0002
|
|
|
|
#define MAX_SEPARATORS 3
|
|
CHAR g_Separators[MAX_SEPARATORS];
|
|
LPSTR g_Dir1Path, g_Dir2Path;
|
|
|
|
VOID
|
|
Dump (
|
|
DWORD MustHave,
|
|
DWORD MustNotHave
|
|
)
|
|
{
|
|
MEMDB_ENUM e, e2;
|
|
CHAR PnpOutput[MAX_ENCODED_PNPID_LENGTH];
|
|
CHAR DescOutput[MAX_INF_DESCRIPTION*2];
|
|
BOOL IsDir1, IsDir2;
|
|
LPSTR Dir1File, Dir2File;
|
|
GROWBUFFER Dir1List = GROWBUF_INIT;
|
|
GROWBUFFER Dir2List = GROWBUF_INIT;
|
|
BOOL Dir1Flag, Dir2Flag;
|
|
DWORD Flags;
|
|
CHAR Node[MEMDB_MAX];
|
|
INFCONTEXT ic;
|
|
|
|
if (!g_ManualOverrideMode) {
|
|
printf ("%s%c%s%cPNP ID\tDevice Description%c\n",
|
|
g_Dir1Path, g_Separators[0], g_Dir2Path, g_Separators[1], g_Separators[2]);
|
|
} else {
|
|
printf ("Overridden PNP IDs\n");
|
|
}
|
|
|
|
if (MemDbEnumFirstValue (&e, TEXT("Devices\\*"), MEMDB_THIS_LEVEL_ONLY, MEMDB_ALL_BUT_PROXY)) {
|
|
|
|
do {
|
|
//
|
|
// Test this PNP ID to see if it should be displayed
|
|
//
|
|
|
|
if (((e.dwValue & MustHave) == MustHave) &&
|
|
((e.dwValue & MustNotHave) == 0)) {
|
|
|
|
//
|
|
// Prepare display string for PNP ID
|
|
//
|
|
|
|
StringCopyA (PnpOutput, e.szName);
|
|
DecodePnpId (PnpOutput);
|
|
|
|
//
|
|
// Is PNP ID suppressed? If so, continue memdb enum.
|
|
//
|
|
|
|
if (g_OverrideInf != INVALID_HANDLE_VALUE) {
|
|
if (SetupFindFirstLine (
|
|
g_OverrideInf,
|
|
"Standard PNP IDs",
|
|
PnpOutput,
|
|
&ic
|
|
)) {
|
|
if (g_ManualOverrideMode) {
|
|
printf ("%s\n", PnpOutput);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If only dumping manually overridden PNP IDs, continue.
|
|
//
|
|
|
|
if (g_ManualOverrideMode) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Enumerate each description for the PNP ID
|
|
//
|
|
|
|
IsDir1 = (e.dwValue & MODE_DIR1) != 0;
|
|
IsDir2 = (e.dwValue & MODE_DIR2) != 0;
|
|
|
|
wsprintf (Node, TEXT("Devices\\%s\\*"), e.szName);
|
|
|
|
if (MemDbEnumFirstValue (
|
|
&e2,
|
|
Node,
|
|
MEMDB_ALL_SUBLEVELS,
|
|
MEMDB_ENDPOINTS_ONLY
|
|
)) {
|
|
|
|
//
|
|
// Prepare display string for description by stripping off
|
|
// the sequencer and decoding it, then reset INF file name
|
|
// buffers.
|
|
//
|
|
|
|
StringCopyA (DescOutput, e2.szName);
|
|
*_mbschr (DescOutput, '\\') = 0;
|
|
DecodePnpId (DescOutput);
|
|
|
|
Dir1List.End = 0;
|
|
Dir2List.End = 0;
|
|
|
|
do {
|
|
//
|
|
// For each description, get the value of the string
|
|
// specified by the description sequencer's offset.
|
|
//
|
|
// We store the file names in a table, so we can organize
|
|
// matches correctly. After the table is complete, we
|
|
// then dump it out.
|
|
//
|
|
|
|
MemDbBuildKeyFromOffset (e2.dwValue, Node, 1, &Flags);
|
|
|
|
if (((Flags & MustHave) || !MustHave) &&
|
|
((Flags & MustNotHave) == 0)) {
|
|
|
|
Dir1Flag = (Flags & MODE_DIR1) != 0;
|
|
Dir2Flag = (Flags & MODE_DIR2) != 0;
|
|
|
|
if (Dir1Flag) {
|
|
MultiSzAppend (&Dir1List, Node);
|
|
}
|
|
if (Dir2Flag) {
|
|
MultiSzAppend (&Dir2List, Node);
|
|
}
|
|
}
|
|
} while (MemDbEnumNextValue (&e2));
|
|
|
|
MultiSzAppend (&Dir1List, "");
|
|
MultiSzAppend (&Dir2List, "");
|
|
|
|
//
|
|
// Dump all matches
|
|
//
|
|
|
|
Dir1File = (LPSTR) Dir1List.Buf;
|
|
if (!Dir1File) {
|
|
Dir1File = "";
|
|
}
|
|
Dir2File = (LPSTR) Dir2List.Buf;
|
|
if (!Dir2File) {
|
|
Dir2File = "";
|
|
}
|
|
|
|
while (*Dir1File || *Dir2File) {
|
|
|
|
printf (
|
|
"%s%c%s%c%s%c%s\n",
|
|
Dir1File,
|
|
g_Separators[0],
|
|
Dir2File,
|
|
g_Separators[1],
|
|
PnpOutput,
|
|
g_Separators[2],
|
|
DescOutput
|
|
);
|
|
|
|
if (*Dir1File) {
|
|
Dir1File = GetEndOfStringA (Dir1File) + 1;
|
|
}
|
|
if (*Dir2File) {
|
|
Dir2File = GetEndOfStringA (Dir2File) + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (MemDbEnumNextValue (&e));
|
|
} else {
|
|
printf ("No devices found.\n");
|
|
}
|
|
|
|
FreeGrowBuffer (&Dir1List);
|
|
FreeGrowBuffer (&Dir2List);
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
main (
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
LPSTR Dir1InputPath;
|
|
LPSTR Dir2InputPath;
|
|
INT i, j;
|
|
LONG rc;
|
|
INT UIMode;
|
|
BOOL AllFlag = FALSE;
|
|
BOOL Dir2Only = FALSE;
|
|
BOOL Dir1Only = FALSE;
|
|
BOOL Common = FALSE;
|
|
PCSTR OverrideList = NULL;
|
|
DWORD Count;
|
|
|
|
//
|
|
// Init project globals
|
|
//
|
|
|
|
GetTempPathA (MAX_MBCHAR_PATH, g_TempDirBuf);
|
|
g_TempDir = g_TempDirBuf;
|
|
|
|
StringCopyA (g_TempDirWackBuf, g_TempDir);
|
|
AppendWack (g_TempDirWackBuf);
|
|
g_TempDirWackChars = CharCountA (g_TempDirWackBuf);
|
|
g_TempDirWack = g_TempDirWackBuf;
|
|
|
|
GetWindowsDirectoryA (g_WinDirBuf, MAX_MBCHAR_PATH);
|
|
g_WinDir = g_WinDirBuf;
|
|
|
|
ZeroMemory(&g_ConfigOptions,sizeof(USEROPTIONS));
|
|
|
|
UIMode = PNPREPT_OUTPUT;
|
|
g_Component = NULL;
|
|
g_SubComponent = PNPREPT_HWND;
|
|
|
|
//
|
|
// Parse command line
|
|
//
|
|
|
|
Dir1InputPath = NULL;
|
|
Dir2InputPath = NULL;
|
|
|
|
for (i = 0 ; i < MAX_SEPARATORS ; i++) {
|
|
g_Separators[i] = '\t';
|
|
}
|
|
|
|
for (i = 1 ; i < argc ; i++) {
|
|
if (argv[i][0] == '-' || argv[i][0] == '/') {
|
|
switch (tolower (argv[i][1])) {
|
|
case 'a':
|
|
AllFlag = TRUE;
|
|
break;
|
|
|
|
case '2':
|
|
Dir2Only = TRUE;
|
|
break;
|
|
|
|
case '1':
|
|
Dir1Only = TRUE;
|
|
break;
|
|
|
|
case 'c':
|
|
Common = TRUE;
|
|
break;
|
|
|
|
case 'm':
|
|
g_ManualOverrideMode = TRUE;
|
|
break;
|
|
|
|
case 'e':
|
|
j = atoi (&argv[i][2]);
|
|
if (j < 1 || j > MAX_SEPARATORS) {
|
|
HelpAndExit();
|
|
}
|
|
g_Separators[j] = '=';
|
|
break;
|
|
|
|
case 'i':
|
|
if (!argv[i][2] && (i + 1) < argc) {
|
|
i++;
|
|
OverrideList = argv[i];
|
|
} else if (argv[i][2] == ':') {
|
|
OverrideList = &argv[i][3];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
HelpAndExit();
|
|
}
|
|
} else {
|
|
if (Dir1InputPath && Dir2InputPath) {
|
|
HelpAndExit();
|
|
} else if (Dir1InputPath) {
|
|
Dir2InputPath = argv[i];
|
|
} else {
|
|
Dir1InputPath = argv[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!AllFlag && !Dir2Only && !Dir1Only && !Common) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (g_ManualOverrideMode && !OverrideList) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (!Dir2InputPath) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
//
|
|
// Init globals and libs
|
|
//
|
|
|
|
g_hHeap = GetProcessHeap();
|
|
g_hInst = GetModuleHandle (NULL);
|
|
|
|
g_SourceDirectories[0] = Dir1InputPath;
|
|
Count = 1;
|
|
g_SourceDirectoryCount = Count;
|
|
|
|
if (pCallMains (DLL_PROCESS_ATTACH)) {
|
|
fprintf (stderr, "Initialization error!\n");
|
|
return 254;
|
|
}
|
|
|
|
g_Dir1Path = _mbsrchr (Dir1InputPath, '\\');
|
|
if (!g_Dir1Path) {
|
|
g_Dir1Path = Dir1InputPath;
|
|
} else {
|
|
g_Dir2Path++;
|
|
}
|
|
|
|
g_Dir2Path = _mbsrchr (Dir2InputPath, '\\');
|
|
if (!g_Dir2Path) {
|
|
g_Dir2Path = Dir2InputPath;
|
|
} else {
|
|
g_Dir2Path++;
|
|
}
|
|
|
|
if (StringIMatch (g_Dir1Path, g_Dir2Path)) {
|
|
g_Dir1Path = Dir1InputPath;
|
|
g_Dir2Path = Dir2InputPath;
|
|
}
|
|
|
|
if (StringIMatch (g_Dir1Path, g_Dir2Path)) {
|
|
fprintf (stderr, "Dir 1 and Dir 2 must be different\n");
|
|
return 247;
|
|
}
|
|
|
|
if (OverrideList) {
|
|
CHAR FullPath[MAX_MBCHAR_PATH];
|
|
PSTR DontCare;
|
|
|
|
if (!SearchPathA (NULL, OverrideList, NULL, MAX_MBCHAR_PATH, FullPath, &DontCare)) {
|
|
StringCopyA (FullPath, OverrideList);
|
|
}
|
|
|
|
g_OverrideInf = SetupOpenInfFile (
|
|
FullPath,
|
|
NULL,
|
|
INF_STYLE_OLDNT|INF_STYLE_WIN4,
|
|
NULL
|
|
);
|
|
if (g_OverrideInf == INVALID_HANDLE_VALUE) {
|
|
fprintf (stderr, "Cannot open %s\n", FullPath);
|
|
return 246;
|
|
}
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// Generate memdb entries for Dir 1 INFs
|
|
//
|
|
|
|
fprintf (stderr, "Processing...\n", Dir1InputPath);
|
|
|
|
g_Mode = MODE_DIR1;
|
|
if (!CreateNtHardwareList (&Dir1InputPath, 1, NULL, UIMode)) {
|
|
rc = GetLastError();
|
|
fprintf (stderr, "Could not build complete %s device list. Win32 Error Code: %xh\n", Dir1InputPath, rc);
|
|
return 1;
|
|
} else {
|
|
fprintf (stderr, " %s processed\n", Dir1InputPath);
|
|
}
|
|
|
|
//
|
|
// Restart hwcomp.lib
|
|
//
|
|
|
|
if (!HwComp_Entry (g_hInst, DLL_PROCESS_DETACH, NULL)) {
|
|
fprintf (stderr, "Termination error!\n");
|
|
return 253;
|
|
}
|
|
|
|
if (!HwComp_Entry (g_hInst, DLL_PROCESS_ATTACH, NULL)) {
|
|
fprintf (stderr, "Initialization error!\n");
|
|
return 252;
|
|
}
|
|
|
|
//
|
|
// Generate memdb entries for Dir 2 INFs
|
|
//
|
|
|
|
g_Mode = MODE_DIR2;
|
|
if (!CreateNtHardwareList (&Dir2InputPath, 1, NULL, UIMode)) {
|
|
rc = GetLastError();
|
|
fprintf (stderr, "Could not build complete %s device list. Win32 Error Code: %xh\n", Dir2InputPath, rc);
|
|
return 2;
|
|
} else {
|
|
fprintf (stderr, " %s processed\n", Dir2InputPath);
|
|
}
|
|
|
|
//
|
|
// Dump output
|
|
//
|
|
|
|
if (AllFlag) {
|
|
Dump (0, 0);
|
|
}
|
|
|
|
if (Dir2Only) {
|
|
Dump (MODE_DIR2, MODE_DIR1);
|
|
}
|
|
|
|
if (Dir1Only) {
|
|
Dump (MODE_DIR1, MODE_DIR2);
|
|
}
|
|
|
|
if (Common) {
|
|
Dump (MODE_DIR2|MODE_DIR1, 0);
|
|
}
|
|
|
|
//
|
|
// Terminate hwcomp.lib
|
|
//
|
|
|
|
if (pCallMains (DLL_PROCESS_DETACH)) {
|
|
fprintf (stderr, "Initialization error!\n");
|
|
return 251;
|
|
}
|
|
|
|
fprintf (stderr, "Done\n");
|
|
}
|
|
|
|
__finally {
|
|
if (g_OverrideInf != INVALID_HANDLE_VALUE) {
|
|
SetupCloseInfFile (g_OverrideInf);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
ProcessPnpId (
|
|
IN PCSTR SubComponent
|
|
)
|
|
{
|
|
DWORD Value;
|
|
TCHAR Node[MEMDB_MAX];
|
|
LPTSTR PnpId, Desc, File;
|
|
LPTSTR p;
|
|
DWORD FileOffset;
|
|
static DWORD d = 0;
|
|
|
|
if (SubComponent) {
|
|
PnpId = (LPTSTR) SubComponent;
|
|
|
|
p = _tcschr (PnpId, TEXT('\\'));
|
|
if (!p) {
|
|
return TRUE;
|
|
}
|
|
*p = 0;
|
|
Desc = p+1;
|
|
|
|
p = _tcschr (Desc, TEXT('\\'));
|
|
if (!p) {
|
|
return TRUE;
|
|
}
|
|
*p = 0;
|
|
File = p+1;
|
|
|
|
//
|
|
// Add the file (it may already exist) and remember the offset.
|
|
// Keep the files in two separate lists.
|
|
//
|
|
|
|
MemDbSetValueEx (
|
|
g_Mode == MODE_DIR1 ? TEXT("Dir1") : TEXT("Dir2"),
|
|
File,
|
|
NULL,
|
|
NULL,
|
|
g_Mode,
|
|
&FileOffset
|
|
);
|
|
|
|
//
|
|
// Add the PNP ID and OR the mode
|
|
//
|
|
|
|
wsprintf (Node, TEXT("Devices\\%s"), PnpId);
|
|
if (!MemDbGetValue (Node, &Value)) {
|
|
Value = 0;
|
|
}
|
|
|
|
Value |= g_Mode;
|
|
|
|
MemDbSetValue (Node, Value);
|
|
|
|
//
|
|
// Add the description, and attach a sequencer to make sure
|
|
// the description is unique. Make the description point
|
|
// to the file offset.
|
|
//
|
|
|
|
d++;
|
|
wsprintf (Node, TEXT("Devices\\%s\\%s\\%u"), PnpId, Desc, d);
|
|
MemDbSetValue (Node, FileOffset);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Stubs
|
|
//
|
|
|
|
HWND g_Component;
|
|
HWND g_SubComponent;
|
|
HANDLE g_ComponentCancelEvent;
|
|
HANDLE g_SubComponentCancelEvent;
|
|
|
|
VOID
|
|
pInitProgBarVars (
|
|
VOID
|
|
)
|
|
{
|
|
g_Component = NULL;
|
|
g_SubComponent = NULL;
|
|
g_ComponentCancelEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
g_SubComponentCancelEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ProgressBar_SetWindowStringA (
|
|
IN HWND Window,
|
|
IN HANDLE CancelEvent,
|
|
IN PCSTR Message, OPTIONAL
|
|
IN DWORD MessageId OPTIONAL
|
|
)
|
|
{
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TickProgressBar (
|
|
VOID
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TickProgressBarDelta (
|
|
IN UINT TickCount
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
InitializeProgressBar (
|
|
IN HWND ProgressBar,
|
|
IN HWND Component, OPTIONAL
|
|
IN HWND SubComponent, OPTIONAL
|
|
IN BOOL *CancelFlagPtr OPTIONAL
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
TerminateProgressBar (
|
|
VOID
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
EndSliceProcessing (
|
|
VOID
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UINT
|
|
RegisterProgressBarSlice (
|
|
IN UINT InitialEstimate
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReviseSliceEstimate (
|
|
IN UINT SliceId,
|
|
IN UINT RevisedEstimate
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
BeginSliceProcessing (
|
|
IN UINT SliceId
|
|
)
|
|
{
|
|
}
|
|
|