#include "precomp.h" #pragma hdrstop #include // // Define and initialize a global variable, GUID_NULL // (from coguid.h) // DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // // Define the size (in characters) of a GUID string, including terminating NULL. // #define GUID_STRING_LEN (39) // // Define a global variable to hold the source path to be used. // TCHAR SourcePath[MAX_PATH]; // // Define a file enumeration callback prototype. // (Used by pSysSetupEnumerateFiles) // typedef BOOL (*PFILEENUM_CALLBACK) ( IN PCTSTR, IN OUT PVOID ); // // Private function prototypes: // BOOL PrecompileSingleInf( IN PCTSTR FullInfPath, IN OUT PVOID Context ); BOOL DeleteSinglePnf( IN PCTSTR FullPnfPath, IN OUT PVOID Context ); VOID pSysSetupEnumerateFiles( IN OUT PWSTR SearchSpec, IN PFILEENUM_CALLBACK FileEnumCallback, IN OUT PVOID Context ); #if 1 UINT FileQueueScanCallback( IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 ); #else UINT DriverListMsgHandler( IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 ); #endif DWORD FilesFromInfSectionAndNeededSections( IN HINF InfHandle, IN PCTSTR InfPath, IN PCTSTR SectionName, IN HDEVINFO DeviceInfoSet, OPTIONAL IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL IN HSPFILEQ UserFileQ OPTIONAL ); BOOL GetActualSectionToInstallEx( IN HINF InfHandle, IN PCTSTR InfSectionName, IN WORD ProcessorArchitecture, OUT PTSTR InfSectionWithExt, IN DWORD InfSectionWithExtSize ); VOID Usage( VOID ); int __cdecl main( IN int argc, IN char *argv[] ) { int StringLen; HDEVINFO DeviceInfoSet; SP_DEVINFO_DATA DeviceInfoData; DWORD Err = NO_ERROR; DWORD i; SP_DRVINFO_DATA DriverInfoData; HSPFILEQ QueueHandle = INVALID_HANDLE_VALUE; SP_DEVINSTALL_PARAMS DeviceInstallParams; DWORD ScanResult; // SP_DRVINSTALL_PARAMS DriverInstallParams; TCHAR SearchSpec[MAX_PATH]; BOOL CacheEnable; BOOL DontCallClassInstaller = FALSE; BOOL NonNativeSearch = FALSE; BOOL IncludeInfsInList = FALSE; BOOL DownLevel = FALSE; TCHAR CertClassInfPath[MAX_PATH]; SP_DRVINFO_DETAIL_DATA DriverInfoDetailData; TCHAR TargetInfDirectory[MAX_PATH]; TCHAR ActualSectionName[LINE_LEN]; TCHAR ActualSectionName2[LINE_LEN]; PTSTR p; LONG GuidIndex, ClassGuidCount = 0; HINF hInf; LPGUID ClassGuidList = NULL; INFCONTEXT InfContext; TCHAR GuidStringBuffer[GUID_STRING_LEN]; HRESULT hr; SP_ALTPLATFORM_INFO_V1 AltPlatformInfo; ULONG Ver = 0; ZeroMemory(&AltPlatformInfo,sizeof(AltPlatformInfo)); AltPlatformInfo.cbSize = sizeof(AltPlatformInfo); // // Process any optional arguments that may precede the (non-optional) // SourcePath. // *CertClassInfPath = TEXT('\0'); for(i = 1; i < (DWORD)argc; i++) { if((*(argv[i]) != TEXT('/')) && (*(argv[i]) != TEXT('-'))) { break; } if(!(*(argv[i]+1)) || *(argv[i]+2)) { Usage(); return -1; } switch(*(argv[i]+1)) { case 'H' : case 'h' : case '?' : // // Display usage help // Usage(); return -1; case 'S' : case 's' : // // Skip class-/co-installers, queue files directly from INF // DontCallClassInstaller = TRUE; break; case 'F' : case 'f' : // // Filter the list based on the INF in the next argument // i++; if(i == (DWORD)argc) { Usage(); return -1; } #ifdef UNICODE StringLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, argv[i], -1, CertClassInfPath, sizeof(CertClassInfPath) / sizeof(WCHAR) ); if(!StringLen) { _tprintf(TEXT("CertClassInfPath must be less than %d characters.\n"), MAX_PATH); return -1; } #else // !UNICODE StringLen = lstrlen(argv[i]); if(StringLen >= MAX_PATH) { _tprintf(TEXT("CertClassInfPath must be less than %d characters.\n"), MAX_PATH); return -1; } CopyMemory(CertClassInfPath, argv[i], StringLen); #endif // !UNICODE // // Now open this INF and retrieve all the GUIDs contained in the // [DriverSigningClasses] section. // hInf = SetupOpenInfFile(CertClassInfPath, NULL, INF_STYLE_WIN4, NULL ); if(hInf == INVALID_HANDLE_VALUE) { _tprintf(TEXT("SetupOpenInfFile failed with %lx\n"), GetLastError()); return -1; } ClassGuidCount = SetupGetLineCount(hInf, TEXT("DriverSigningClasses")); if(ClassGuidCount < 0) { _tprintf(TEXT("CertClassInf specified doesn't contain a [DriverSigningClasses] section\n")); return -1; } if(!ClassGuidCount) { // // No classes in the section--nothing to do. // return 0; } ClassGuidList = malloc(ClassGuidCount * sizeof(GUID)); if(!ClassGuidList) { _tprintf(TEXT("Out of memory\n")); return -1; } for(GuidIndex = 0; GuidIndex < ClassGuidCount; GuidIndex++) { if(!SetupGetLineByIndex(hInf, TEXT("DriverSigningClasses"), GuidIndex, &InfContext)) { _tprintf(TEXT("SetupGetLineByIndex failed with %lx\n"), GetLastError()); return -1; } if(!SetupGetStringField(&InfContext, 0, GuidStringBuffer, sizeof(GuidStringBuffer) / sizeof(TCHAR), NULL)) { _tprintf(TEXT("SetupGetStringField failed with %lx\n"), GetLastError()); return -1; } hr = CLSIDFromString(GuidStringBuffer, &(ClassGuidList[GuidIndex])); if(FAILED(hr)) { _tprintf(TEXT("CLSIDFromString failed with %lx\n"), hr); return -1; } } // // We're finished with the INF. // SetupCloseInfFile(hInf); break; case 'A' : case 'a' : // // Target Architecture // 0 = Intel x86 // 6 = IA64 // 9 = AMD64 // i++; if(i == (DWORD)argc) { Usage(); return -1; } AltPlatformInfo.ProcessorArchitecture = (WORD)strtoul(argv[i],NULL,0); NonNativeSearch = TRUE; break; case 'V' : case 'v' : // // Version, eg 5.1 // i++; if(i == (DWORD)argc) { Usage(); return -1; } Ver = strtoul(argv[i],NULL,16); AltPlatformInfo.MajorVersion = HIBYTE(Ver); AltPlatformInfo.MinorVersion = LOBYTE(Ver); NonNativeSearch = TRUE; break; case 'I' : case 'i' : // // Include INFs in the list // IncludeInfsInList = TRUE; // // Retrieve the location of the INF directory, so when we add // the INFs to the copy queue it reports the proper path for // their destination. // StringLen = GetSystemWindowsDirectory( TargetInfDirectory, sizeof(TargetInfDirectory) / sizeof(TCHAR) ); if(!StringLen) { _tprintf(TEXT("GetSystemWindowsDirectory failed with %lx\n"), GetLastError()); return -1; } if(StringLen >= (sizeof(TargetInfDirectory) / sizeof(TCHAR))) { _tprintf(TEXT("GetSystemWindowsDirectory requires a larger buffer than we supplied\n")); return -1; } if(TargetInfDirectory[StringLen - 1] != TEXT('\\')) { TargetInfDirectory[StringLen++] = TEXT('\\'); } lstrcpyn(TargetInfDirectory + StringLen, TEXT("INF"), (sizeof(TargetInfDirectory) / sizeof(TCHAR)) - StringLen ); break; default : // // Invalid option // Usage(); return -1; } } // // We should have processed all arguments except the last one, which should // contain the SourcePath. // if(i != ((DWORD)argc - 1)) { Usage(); return -1; } #ifdef UNICODE StringLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, argv[i], -1, SourcePath, sizeof(SourcePath) / sizeof(WCHAR) ); if(!StringLen) { _tprintf(TEXT("SourcePath must be less than %d characters.\n"), MAX_PATH); return -1; } // // We don't want StringLen to include the terminating null character. // StringLen--; #else // !UNICODE StringLen = lstrlen(argv[i]); if(!StringLen) { _tprintf(TEXT("SourcePath cannot be an empty string.\n")); return -1; } if(StringLen >= MAX_PATH) { _tprintf(TEXT("SourcePath must be less than %d characters.\n"), MAX_PATH); return -1; } CopyMemory(SourcePath, argv[i], StringLen); #endif // !UNICODE if(NonNativeSearch) { // // fix up platform information // AltPlatformInfo.Platform = VER_PLATFORM_WIN32_NT; if(!Ver) { AltPlatformInfo.MajorVersion = HIBYTE(_WIN32_WINNT); AltPlatformInfo.MinorVersion = LOBYTE(_WIN32_WINNT); } AltPlatformInfo.Reserved = 0; } // // Precompile all INFs in the specified directory (we'll delete the PNFs // when we're done). // CopyMemory(SearchSpec, SourcePath, StringLen * sizeof(TCHAR)); if(SearchSpec[StringLen - 1] != TEXT('\\')) { SearchSpec[StringLen++] = TEXT('\\'); } lstrcpyn(SearchSpec + StringLen, TEXT("*.INF"), (sizeof(SearchSpec) / sizeof(TCHAR)) - StringLen ); CacheEnable = TRUE; pSysSetupEnumerateFiles(SearchSpec, PrecompileSingleInf, &CacheEnable); // // Create an HDEVINFO set to contain our placeholder device. // DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL); if(DeviceInfoSet == INVALID_HANDLE_VALUE) { _tprintf(TEXT("SetupDiCreateDeviceInfoList failed with %lx\n"), GetLastError()); return -1; } // // Now create the placeholder device for which each driver node will be selected/analyzed. // DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if(!SetupDiCreateDeviceInfo(DeviceInfoSet, TEXT("DRIVER_LIST_PLACEHOLDER"), (LPGUID)&GUID_NULL, NULL, NULL, DICD_GENERATE_ID, &DeviceInfoData)) { Err = GetLastError(); _tprintf(TEXT("SetupDiCreateDeviceInfo failed with %lx\n"), Err); goto clean0; } // // Create file queue here before search so that we can associate a different // platform with the search // QueueHandle = SetupOpenFileQueue(); if(QueueHandle == INVALID_HANDLE_VALUE) { // // This can only happen due to out-of-memory, and GetLastError() actually isn't even // being set currently in this case. // Err = ERROR_NOT_ENOUGH_MEMORY; _tprintf(TEXT("SetupOpenFileQueue failed with %lx\n"), Err); goto clean0; } if(NonNativeSearch) { if(!SetupSetFileQueueAlternatePlatform(QueueHandle,(PSP_ALTPLATFORM_INFO)&AltPlatformInfo,NULL)) { DownLevel = TRUE; } } // // Redirect our driver search to look in the specified directory. // specify file queue that we'll use to base search on // and use for all cumulative installs // DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); if(!SetupDiGetDeviceInstallParams(DeviceInfoSet, &DeviceInfoData, &DeviceInstallParams)) { Err = GetLastError(); _tprintf(TEXT("SetupDiGetDeviceInstallParams (1st time) failed with %lx\n"), Err); goto clean0; } // // specify search path // lstrcpy(DeviceInstallParams.DriverPath, SourcePath); DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS; // // specify file queue to search // DeviceInstallParams.FileQueue = QueueHandle; DeviceInstallParams.Flags |= DI_NOVCP; if(!SetupDiSetDeviceInstallParams(DeviceInfoSet, &DeviceInfoData, &DeviceInstallParams)) { Err = GetLastError(); _tprintf(TEXT("SetupDiSetDeviceInstallParams (1st time) failed with %lx\n"), Err); goto clean0; } // // other flags we desire to have // if(NonNativeSearch && !DownLevel) { // // if we can, try to make use of DI_FLAGSEX_ALTPLATFORM_DRVSEARCH // this supports manufacturer decoration // DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALTPLATFORM_DRVSEARCH; if(!SetupDiSetDeviceInstallParams(DeviceInfoSet, &DeviceInfoData, &DeviceInstallParams)) { DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_ALTPLATFORM_DRVSEARCH; DownLevel = TRUE; } } // // if we can, try to make use of DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE // this ensures we look at duplicate nodes (which is broken in itself) // DeviceInstallParams.FlagsEx |= DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE; if(!SetupDiSetDeviceInstallParams(DeviceInfoSet, &DeviceInfoData, &DeviceInstallParams)) { DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE; } // // Now build a class driver list with every driver node we support. // if(!SetupDiBuildDriverInfoList(DeviceInfoSet, &DeviceInfoData, SPDIT_CLASSDRIVER)) { Err = GetLastError(); _tprintf(TEXT("SetupDiBuildDriverInfoList failed with %lx\n"), Err); goto clean0; } DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA); for(i = 0; SetupDiEnumDriverInfo(DeviceInfoSet, &DeviceInfoData, SPDIT_CLASSDRIVER, i, &DriverInfoData); i++) { if(!SetupDiSetSelectedDriver(DeviceInfoSet, &DeviceInfoData, &DriverInfoData)) { Err = GetLastError(); _tprintf(TEXT("SetupDiSetSelectedDriver failed with %lx\n"), Err); goto clean1; } // // The device information element's class GUID will have automatically // been updated by SetupDiSetSelectedDriver to reflect the class of the // driver node's INF. If we're supposed to filter based on a certclas.inf, // then check to make sure that this class is in our list. // if(ClassGuidCount) { for(GuidIndex = 0; GuidIndex < ClassGuidCount; GuidIndex++) { if(IsEqualGUID(&(DeviceInfoData.ClassGuid), &(ClassGuidList[GuidIndex]))) { break; } } if(GuidIndex == ClassGuidCount) { // // Then we didn't find the class GUID in our list--skip this // driver node. // continue; } } // // If we're also supposed to include the INFs in our list of driver // files, then retrieve the detailed driver info to find out what INF // is associated with this driver node. // if(IncludeInfsInList) { DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); if(!SetupDiGetDriverInfoDetail(DeviceInfoSet, &DeviceInfoData, &DriverInfoData, &DriverInfoDetailData, sizeof(DriverInfoDetailData), NULL)) { // // If we failed with ERROR_INSUFFICIENT_BUFFER, then that's OK. // Err = GetLastError(); if(Err != ERROR_INSUFFICIENT_BUFFER) { _tprintf(TEXT("SetupDiGetDriverInfoDetail failed with %lx\n"), Err); goto clean1; } } // // OK, now that we have the INF name, add it to our queue. // p = _tcsrchr(DriverInfoDetailData.InfFileName, TEXT('\\')); if(!p || !(*(++p))) { _tprintf(TEXT("Invalid INF name encountered\n")); goto clean1; } if(!SetupQueueCopy(QueueHandle, SourcePath, NULL, p, NULL, NULL, TargetInfDirectory, p, 0)) { Err = GetLastError(); _tprintf(TEXT("SetupQueueCopy failed with %lx\n"), Err); goto clean1; } } if(NonNativeSearch) { // // have to go around the houses here // since SetupDiInstallDriverFiles does not support alternate platform // DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); if(!SetupDiGetDriverInfoDetail(DeviceInfoSet, &DeviceInfoData, &DriverInfoData, &DriverInfoDetailData, sizeof(DriverInfoDetailData), NULL)) { // // If we failed with ERROR_INSUFFICIENT_BUFFER, then that's OK. // Err = GetLastError(); if(Err != ERROR_INSUFFICIENT_BUFFER) { _tprintf(TEXT("SetupDiGetDriverInfoDetail failed with %lx\n"), Err); goto clean1; } } hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName,NULL,INF_STYLE_WIN4,NULL); if(hInf == INVALID_HANDLE_VALUE) { _tprintf(TEXT("SetupOpenInfFile %s failed with %lx\n"),DriverInfoDetailData.InfFileName, GetLastError()); goto clean1; } if(!GetActualSectionToInstallEx(hInf, DriverInfoDetailData.SectionName, AltPlatformInfo.ProcessorArchitecture, ActualSectionName, LINE_LEN)) { Err = GetLastError(); _tprintf(TEXT("GetActualSectionToInstallEx failed with %lx\n"), Err); goto clean1; } Err = FilesFromInfSectionAndNeededSections(hInf, SourcePath, ActualSectionName, DeviceInfoSet, &DeviceInfoData, QueueHandle); if(Err) { _tprintf(TEXT("FilesFromInfSectionAndNeededSections failed with %lx\n"), Err); goto clean1; } lstrcpy(ActualSectionName2,ActualSectionName); lstrcat(ActualSectionName2,TEXT(".CoInstallers")); Err = FilesFromInfSectionAndNeededSections(hInf, SourcePath, ActualSectionName2, DeviceInfoSet, &DeviceInfoData, QueueHandle); if(Err) { _tprintf(TEXT("FilesFromInfSectionAndNeededSections failed with %lx\n"), Err); goto clean1; } lstrcpy(ActualSectionName2,ActualSectionName); lstrcat(ActualSectionName2,TEXT(".Interfaces")); Err = FilesFromInfSectionAndNeededSections(hInf, SourcePath, ActualSectionName2, DeviceInfoSet, &DeviceInfoData, QueueHandle); if(Err) { _tprintf(TEXT("FilesFromInfSectionAndNeededSections failed with %lx\n"), Err); goto clean1; } // // done // SetupCloseInfFile(hInf); } else if(DontCallClassInstaller) { // // appeneded to the queue we've associated with DeviceInfoSet // if(!SetupDiInstallDriverFiles(DeviceInfoSet, &DeviceInfoData)) { Err = GetLastError(); _tprintf(TEXT("SetupDiInstallDriverFiles failed with %lx\n"), Err); goto clean1; } } else { if(!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, DeviceInfoSet, &DeviceInfoData)) { Err = GetLastError(); _tprintf(TEXT("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with %lx\n"), Err); goto clean1; } } } // // OK, now we've got all the file operations in our file queue. Now scan // the file queue and print out each file to be copied. // if(!SetupScanFileQueue(QueueHandle, SPQ_SCAN_USE_CALLBACKEX|SPQ_SCAN_FILE_PRESENCE, NULL, FileQueueScanCallback, NULL, &ScanResult)) { // // Might have been because SPQ_SCAN_FILE_PRESENCE combo not understood // try as a 2nd resort... // if(!SetupScanFileQueue(QueueHandle, SPQ_SCAN_USE_CALLBACKEX, NULL, FileQueueScanCallback, NULL, &ScanResult)) { Err = GetLastError(); _tprintf(TEXT("SetupScanFileQueue failed with %lx\n"), Err); goto clean1; } } // // We're done! We've successfully printed out all files that are installed by this driver // node. // clean1: clean0: SetupDiDestroyDeviceInfoList(DeviceInfoSet); if (QueueHandle != INVALID_HANDLE_VALUE) { SetupCloseFileQueue(QueueHandle); } // // Clean up PNFs. // lstrcpy(SearchSpec + StringLen, TEXT("*.PNF")); pSysSetupEnumerateFiles(SearchSpec, DeleteSinglePnf, NULL); return ((Err == NO_ERROR) ? 0 : -1); } VOID pSysSetupEnumerateFiles( IN OUT PWSTR SearchSpec, IN PFILEENUM_CALLBACK FileEnumCallback, IN OUT PVOID Context ) /*++ Routine Description: This routine enumerates every (non-directory) file matching the specified wildcard, and passes the filename (w/path) to the specified callback, along with the caller-supplied context. Arguments: SearchSpec - Specifies the files to be enumerated (e.g., "C:\WINNT\INF\*.INF"). The character buffer pointed to must be at least MAX_PATH characters large. THIS BUFFER IS USED AS WORKING SPACE BY THIS ROUTINE, AND ITS CONTENTS WILL BE MODIFIED! FileEnumCallback - Supplies the address of the callback routine to be called for each file enumerated. The prototype of this function is: typedef BOOL (*PFILEENUM_CALLBACK) { IN PCTSTR Filename, IN OUT PVOID Context ); (Returning TRUE from the callback continues enumeration, FALSE aborts it.) Context - Supplies a context that is passed to the callback for each file. Return Value: None. --*/ { PWSTR FilenameStart; HANDLE FindHandle; WIN32_FIND_DATA FindData; FilenameStart = _tcsrchr(SearchSpec, TEXT('\\')); FilenameStart++; if((FindHandle = FindFirstFile(SearchSpec, &FindData)) != INVALID_HANDLE_VALUE) { do { // // Skip directories // if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { continue; } // // Form full pathname of file in SearchSpec. // lstrcpy(FilenameStart, FindData.cFileName); // // Call the callback for this file. // if(!FileEnumCallback(SearchSpec, Context)) { // // Callback aborted enumeration. // break; } } while(FindNextFile(FindHandle, &FindData)); FindClose(FindHandle); } } BOOL PrecompileSingleInf( IN PCTSTR FullInfPath, IN OUT PVOID Context ) /*++ Routine Description: This routine precompiles the specified INF. Arguments: FullInfPath - Supplies the name of the INF to be precompiled. Context - Supplies a pointer to a boolean. If non-zero, caching is enabled, otherwise it's disabled (i.e., the corresponding PNF is deleted). Return Value: TRUE to continue enumeration, FALSE to abort it (we always return TRUE). --*/ { HINF hInf; hInf = SetupOpenInfFile(FullInfPath, NULL, INF_STYLE_WIN4 | (*((PBOOL)Context) ? INF_STYLE_CACHE_ENABLE : INF_STYLE_CACHE_DISABLE), NULL ); if(hInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInf); } return TRUE; } BOOL DeleteSinglePnf( IN PCTSTR FullPnfPath, IN OUT PVOID Context ) { UNREFERENCED_PARAMETER(Context); DeleteFile(FullPnfPath); return TRUE; } #if 1 UINT FileQueueScanCallback( IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 ) { PFILEPATHS FilePaths = (PFILEPATHS)Param1; PTSTR Source, Target; if(Notification == SPFILENOTIFY_QUEUESCAN_EX) { #if FULL_FILEPATHS_SPEW _tprintf(TEXT("%s -> %s (err %lx, flags %lx)\n"), FilePaths->Source, FilePaths->Target, FilePaths->Win32Error, FilePaths->Flags ); #else // // Get simple filenames for source and target... // Source = _tcsrchr(FilePaths->Source, TEXT('\\')); if(!Source) { _tprintf(TEXT("ERROR! Full source path not included for %s--aborting!\n"), FilePaths->Source); return ERROR_PATH_NOT_FOUND; } Target = _tcsrchr(FilePaths->Target, TEXT('\\')); if(!Target) { _tprintf(TEXT("ERROR! Full target path not included for %s--aborting!\n"), FilePaths->Target); return ERROR_PATH_NOT_FOUND; } Source++; Target++; _tprintf(TEXT("%s\n"), Source); #endif // FULL_FILEPATHS_SPEW } return NO_ERROR; } #else UINT DriverListMsgHandler( IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 ) { UINT ret = FILEOP_SKIP; PFILEPATHS FilePaths = (PFILEPATHS)Param1; UNREFERENCED_PARAMETER(Context); UNREFERENCED_PARAMETER(Param2); if(Notification == SPFILENOTIFY_STARTCOPY) { // // Print out the source filename... // _tprintf(TEXT("%s ( "), FilePaths->Source); // // Now print out any flags set for this copy operation. // // // First, here are the flags that can't come from an INF (but the // class installer might have set them)... // if(FilePaths->Flags & SP_COPY_DELETESOURCE) { _tprintf(TEXT("DELETESOURCE ")); } if(FilePaths->Flags & SP_COPY_NOOVERWRITE) { _tprintf(TEXT("NOOVERWRITE ")); } if(FilePaths->Flags & SP_COPY_LANGUAGEAWARE) { _tprintf(TEXT("LANGUAGEAWARE ")); } if(FilePaths->Flags & SP_COPY_SOURCE_ABSOLUTE) { _tprintf(TEXT("SOURCE_ABSOLUTE ")); } if(FilePaths->Flags & SP_COPY_SOURCEPATH_ABSOLUTE) { _tprintf(TEXT("SOURCEPATH_ABSOLUTE ")); } if(FilePaths->Flags & SP_COPY_NOBROWSE) { _tprintf(TEXT("NOBROWSE ")); } if(FilePaths->Flags & SP_COPY_SOURCE_SIS_MASTER) { _tprintf(TEXT("SOURCE_SIS_MASTER ")); } // // Now for the flags that are settable via an INF... // // // Did the INF specify the COPYFLG_REPLACEONLY bit? // (The class-installer may have also set this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_REPLACEONLY) { _tprintf(TEXT("REPLACEONLY ")); } // // Did the INF specify the COPYFLG_NOVERSIONCHECK bit? If so, then // the SP_COPY_NEWER_OR_SAME bit will be _cleared_. // (The class-installer may have also cleared this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_NEWER_OR_SAME) { // same as SP_COPY_NEWER _tprintf(TEXT("NEWER_OR_SAME ")); } // // Did the INF specify the COPYFLG_NODECOMP bit? // (The class-installer may have also set this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_NODECOMP) { _tprintf(TEXT("NODECOMP ")); } // // Did the INF specify the COPYFLG_FORCE_FILE_IN_USE bit? If so, then // both the SP_COPY_IN_USE_NEEDS_REBOOT and SP_COPY_FORCE_IN_USE flags // will be set. // (The class-installer may have also set these flags, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_IN_USE_NEEDS_REBOOT) { _tprintf(TEXT("IN_USE_NEEDS_REBOOT ")); } if(FilePaths->Flags & SP_COPY_FORCE_IN_USE) { _tprintf(TEXT("FORCE_IN_USE ")); } // // Did the INF specify the COPYFLG_NOSKIP bit? // (The class-installer may have also set this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_NOSKIP) { _tprintf(TEXT("NOSKIP ")); } // // Did the INF specify the COPYFLG_NO_OVERWRITE bit? // (The class-installer may have also set this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_FORCE_NOOVERWRITE) { _tprintf(TEXT("FORCE_NOOVERWRITE ")); } // // Did the INF specify the COPYFLG_NO_VERSION_DIALOG bit? // (The class-installer may have also set this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_FORCE_NEWER) { _tprintf(TEXT("FORCE_NEWER ")); } // // Did the INF specify the COPYFLG_WARN_IF_SKIP bit? // (The class-installer may have also set this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_WARNIFSKIP) { _tprintf(TEXT("WARNIFSKIP ")); } // // Did the INF specify the COPYFLG_OVERWRITE_OLDER_ONLY bit? // (The class-installer may have also set this flag, but it's unlikely.) // if(FilePaths->Flags & SP_COPY_NEWER_ONLY) { _tprintf(TEXT("NEWER_ONLY ")); } // // Get ready for next line... // _tprintf(TEXT(")\n")); } else if(Notification == SPFILENOTIFY_NEEDMEDIA) { lstrcpy((PTSTR)Param2, SourcePath); ret = FILEOP_NEWPATH; } // // Since FILEOP_SKIP is a nonzero value, it's OK to always return this. // return ret; } #endif DWORD FilesFromInfSectionAndNeededSections( IN HINF InfHandle, IN PCTSTR InfPath, IN PCTSTR SectionName, IN HDEVINFO DeviceInfoSet, OPTIONAL IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL IN HSPFILEQ UserFileQ OPTIONAL ) /*++ Routine Description: Process Copy directives from specified section taking note of Include/Needs Return Value: If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code indicating the cause of the failure. --*/ { DWORD FieldIndex, Err; INFCONTEXT InfContext; BOOL NeedsEntriesToProcess; TCHAR SectionToInstall[LINE_LEN]; TCHAR InfFullPath[MAX_PATH]; int FileLen; // // Store the full directory path to where the supplied INF is located, so we // can first attempt to append-load the included INFs from that same directory. // lstrcpyn(InfFullPath, InfPath, MAX_PATH-3); FileLen = lstrlen(InfFullPath); if((*CharPrev(InfFullPath,InfFullPath+FileLen)!=TEXT('\\')) && (*CharPrev(InfFullPath,InfFullPath+FileLen)!=TEXT('/'))) { InfFullPath[FileLen++] = TEXT('\\'); } if(SetupFindFirstLine(InfHandle, SectionName, TEXT("include"), &InfContext)) { for(FieldIndex = 1; SetupGetStringField(&InfContext, FieldIndex, InfFullPath+FileLen, (DWORD)(MAX_PATH-FileLen), NULL); FieldIndex++) { // // Try only full path, if that fails, tough // SetupOpenAppendInfFile(InfFullPath, InfHandle, NULL); } } SetupOpenAppendInfFile(NULL, InfHandle, NULL); lstrcpyn(SectionToInstall, SectionName, LINE_LEN); NeedsEntriesToProcess = SetupFindFirstLine(InfHandle, SectionName, TEXT("needs"), &InfContext ); Err = NO_ERROR; for(FieldIndex = 0; (!FieldIndex || NeedsEntriesToProcess); FieldIndex++) { if(FieldIndex) { // // Get next section name on "needs=" line to be processed. // if(!SetupGetStringField(&InfContext, FieldIndex, SectionToInstall, LINE_LEN, NULL)) { // // We've exhausted all the extra sections we needed to install. // break; } } SetupInstallFilesFromInfSection(InfHandle,NULL,UserFileQ,SectionToInstall,NULL,0); } return Err; } BOOL GetActualSectionToInstallEx( IN HINF InfHandle, IN PCTSTR InfSectionName, IN WORD ProcessorArchitecture, OUT PTSTR InfSectionWithExt, IN DWORD InfSectionWithExtSize ) { // // Poor mans SetupDiGetActualSectionToInstallEx // DWORD SectionNameLen = (DWORD)lstrlen(InfSectionName); DWORD ExtBufferLen; BOOL ExtFound = TRUE; DWORD Err = NO_ERROR; DWORD Platform; PCTSTR NtArchSuffix; DWORD NtArchSuffixSize; switch(ProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL : NtArchSuffix = TEXT(".ntx86"); break; case PROCESSOR_ARCHITECTURE_IA64 : NtArchSuffix = TEXT(".ntia64"); break; case PROCESSOR_ARCHITECTURE_AMD64 : NtArchSuffix = TEXT(".ntamd64"); break; default: // // Unknown/invalid architecture // SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } NtArchSuffixSize = (DWORD)lstrlen(NtArchSuffix)+1; if((SectionNameLen+NtArchSuffixSize)>InfSectionWithExtSize) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } lstrcpy(InfSectionWithExt,InfSectionName); lstrcat(InfSectionWithExt,NtArchSuffix); if(SetupGetLineCount(InfHandle, InfSectionWithExt) != -1) { return TRUE; } lstrcpy(InfSectionWithExt,InfSectionName); lstrcat(InfSectionWithExt,TEXT(".nt")); if(SetupGetLineCount(InfHandle, InfSectionWithExt) != -1) { return TRUE; } lstrcpy(InfSectionWithExt,InfSectionName); return TRUE; } VOID Usage( VOID ) { _tprintf(TEXT("Usage: DRVLIST [/S] [/I] [/F CertClassInfPath] [/A arch] [/V ver] SourcePath\n\n")); _tprintf(TEXT("Options:\n\n")); _tprintf(TEXT("/I Include INFs in the list\n")); _tprintf(TEXT("/S Skip class-/co-installers; build list strictly from INFs\n")); _tprintf(TEXT("/F Filter based on list of class GUIDs in [DriverSigningClasses]\n")); _tprintf(TEXT(" section of specified INF\n")); _tprintf(TEXT("/A Architecture to build for, eg '/A 6' (IA64). Assumes /S\n")); _tprintf(TEXT("/V Version to build for, eg '/V 0501' (5.1). Assumes /S\n")); _tprintf(TEXT("/? or /H Display brief usage message\n")); }