#include "mmcpl.h" #include #include #include #include "drivers.h" #include "sulib.h" #include "trayvol.h" #include "debug.h" static PTSTR szLocalAllocFailMsg = TEXT("Failed memory allocation\n"); #define GUESS_LEGACY_SERVICE_NAME 0 #define tsizeof(s) (sizeof(s)/sizeof(TCHAR)) // Generic listnode structure typedef struct _LISTNODE { struct _LISTNODE *pNext; } LISTNODE; // Structure describing a source disk entry typedef struct _SOURCEDISK { struct _SOURCEDISK *pNext; // Next source disk in list TCHAR szDiskName[_MAX_PATH]; // Description of this disk int DiskId; } SOURCEDISK; // Structure describing a file to copy // We keep a list of these files in two places: // 1. A global list of all files copied by the inf attached to the LEGACY_INF struct. // 2. A pair driver-specific lists (user & kernel) attached to the LEGACY_DRIVER struct. typedef struct _FILETOCOPY { struct _FILETOCOPY *pNext; // Next file to copy TCHAR szFileName[_MAX_FNAME]; // Name of file to copy int DiskId; } FILETOCOPY; // Structure representing a legacy driver's information typedef struct _LEGACY_DRIVER { struct _LEGACY_DRIVER *pNext; TCHAR szDevNameKey[32]; // Device name key TCHAR szUserDevDrv[32]; // User-level device driver TCHAR szClasses[128]; // List of device classes this driver supports TCHAR szDesc[128]; // Description of device TCHAR szVxD[32]; // Name of VxD driver (not supported) TCHAR szParams[128]; // Params (not supported) TCHAR szDependency[128]; // Dependent device (not supported) FILETOCOPY *UserCopyList; // List of all user files to copy FILETOCOPY *KernCopyList; // List of all kernel files to copy } LEGACY_DRIVER; // Structure representing a legacy inf typedef struct _LEGACY_INF { struct _LEGACY_INF *pNext; TCHAR szLegInfPath[_MAX_PATH]; // Path to original legacy inf TCHAR szNewInfPath[_MAX_PATH]; // Path to converted inf LEGACY_DRIVER *DriverList; // List of all drivers in this inf SOURCEDISK *SourceDiskList; // List of all source disks in this inf FILETOCOPY *FileList; // List of all files copied as part of this inf } LEGACY_INF; // Root structure for the whole tree typedef struct _PROCESS_INF_INFO { TCHAR szLegInfDir[_MAX_PATH]; // Directory where legacy infs are located TCHAR szNewInfDir[_MAX_PATH]; // Temp directory where new infs are generated TCHAR szSysInfDir[_MAX_PATH]; // Windows inf directory TCHAR szTemplate[_MAX_PATH]; // Template to search for LEGACY_INF *LegInfList; // List of all infs to be converted } PROCESS_INF_INFO; #if defined DEBUG || defined _DEBUG || defined DEBUG_RETAIL // Debugging routine to dump the contents of a LEGACY_INF list void DumpLegacyInfInfo(PROCESS_INF_INFO *pPII) { LEGACY_INF *pLI; LEGACY_DRIVER *pLD; for (pLI=pPII->LegInfList;pLI;pLI=pLI->pNext) { dlog1("Dumping legacy inf %s\n",pLI->szLegInfPath); dlog("Dump of legacy driver info:\n"); for (pLD=pLI->DriverList; pLD; pLD=pLD->pNext) { dlog1("DriverNode=0x%x", pLD); dlog1("\tszDevNameKey=%s", pLD->szDevNameKey); dlog1("\tszUserDevDrv=%s", pLD->szUserDevDrv); dlog1("\tszClasses=%s", pLD->szClasses); dlog1("\tszDesc=%s", pLD->szDesc); dlog1("\tszVxD=%s", pLD->szVxD); dlog1("\tszParams=%s", pLD->szParams); dlog1("\tszDependency=%s", pLD->szDependency); } } return; } #else #define DumpLegacyInfInfo() #endif // Function to remove a directory tree and all its subtrees void RemoveDirectoryTree(PTSTR szDirTree) { TCHAR PathBuffer[_MAX_PATH]; PTSTR CurrentFile; HANDLE FindHandle; WIN32_FIND_DATA FindData; PathBuffer[0] = '\0'; // Build a file spec to find all files in specified directory // (i.e., \*.INF) lstrcpyn(PathBuffer, szDirTree, ARRAYSIZE(PathBuffer)); catpath(PathBuffer,TEXT("\\*")); // Get a pointer to the end of the path part of the string // (minus the wildcard filename), so that we can append // each filename to it. CurrentFile = _tcsrchr(PathBuffer, TEXT('\\')) + 1; FindHandle = FindFirstFile(PathBuffer, &FindData); if (FindHandle == INVALID_HANDLE_VALUE) { return; } do { // Skip '.' and '..' files, or else we crash! if ( (!_tcsicmp(FindData.cFileName,TEXT("."))) || (!_tcsicmp(FindData.cFileName,TEXT(".."))) ) { continue; } // Build the full pathname. _tcscpy(CurrentFile, FindData.cFileName); if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { RemoveDirectoryTree(PathBuffer); } else { DeleteFile(PathBuffer); } } while (FindNextFile(FindHandle, &FindData)); // Remember to close the find handle FindClose(FindHandle); // Now remove the directory RemoveDirectory(szDirTree); return; } // Generic routine to free a list void FreeList(LISTNODE *pList) { LISTNODE *pNext; while (pList) { pNext = pList->pNext; LocalFree(pList); pList=pNext; } return; } // Routine to free all memory that is part of a PROCESS_INF_INFO struct void DestroyLegacyInfInfo(PROCESS_INF_INFO *pPII) { LEGACY_INF *pLIList, *pLINext; LEGACY_DRIVER *pLDList, *pLDNext; pLIList=pPII->LegInfList; while (pLIList) { pLINext = pLIList->pNext; pLDList = pLIList->DriverList; while (pLDList) { pLDNext = pLDList->pNext; // Free file copy lists FreeList((LISTNODE *)pLDList->UserCopyList); FreeList((LISTNODE *)pLDList->KernCopyList); // Free Driver node LocalFree(pLDList); pLDList = pLDNext; } // Free the source disk list FreeList((LISTNODE *)pLIList->SourceDiskList); // Free the file list FreeList((LISTNODE *)pLIList->FileList); // Free up the legacy inf structure LocalFree(pLIList); pLIList = pLINext; } // Free the pPII struct LocalFree(pPII); return; } // Searches a file list for a matching entry FILETOCOPY *FindFile(PTSTR szFileName, FILETOCOPY *pFileList) { FILETOCOPY *pFTC; for (pFTC=pFileList;pFTC;pFTC=pFTC->pNext) { if (!_tcsicmp(szFileName,pFTC->szFileName)) { return pFileList; } } return NULL; } // Generic function for adding a file to a copy list BOOL AddFileToFileList(PTSTR szFileName, int DiskId, FILETOCOPY **ppList) { FILETOCOPY *pFTC; // Only add the entry if another one doesn't already exist if (!FindFile(szFileName,*ppList)) { pFTC = (FILETOCOPY *)LocalAlloc(LPTR, sizeof(FILETOCOPY)); if (!pFTC) { dlogt(szLocalAllocFailMsg); return FALSE; } // Save the fields pFTC->DiskId=DiskId; _tcscpy(pFTC->szFileName,szFileName); // Put it in the list pFTC->pNext=(*ppList); (*ppList)=pFTC; } return TRUE; } // Add a file to both the global and driver-specific copy lists BOOL AddFileToCopyList(LEGACY_INF *pLI, LEGACY_DRIVER *pLD, TCHAR *szIdFile) { int DiskId; TCHAR *szFileName; // szFile has both a disk ID and a file name, e.g. "1:foo.drv" // Get the disk ID and file name from szFile DiskId = _ttol(szIdFile); szFileName = RemoveDiskId(szIdFile); // Add the file to the global list AddFileToFileList(szFileName,DiskId,&(pLI->FileList)); // Add the file to the correct driver-specific list if (IsFileKernelDriver(szFileName)) { AddFileToFileList(szFileName,DiskId,&(pLD->KernCopyList)); } else { AddFileToFileList(szFileName,DiskId,&(pLD->UserCopyList)); } return TRUE; } // Build the data structure associated with a legacy inf file // and return a pointer to it, or NULL if failure LEGACY_INF *CreateLegacyInf(IN PCTSTR szLegInfPath) { HINF hInf; // Handle to the legacy inf INFCONTEXT InfContext; // Inf context struct for parsing inf file LEGACY_INF *pLI; // Struct describing this inf LEGACY_DRIVER *pLDList; // ptrs to drivers in this inf LEGACY_DRIVER *pLD; TCHAR szIdFile[32]; // Holds : strings, e.g. "1:foo.drv" int MediaDescFieldId; // Open the inf file hInf = SetupOpenInfFile( szLegInfPath, NULL, INF_STYLE_OLDNT, NULL); if (hInf==INVALID_HANDLE_VALUE) { return NULL; } // Try to open the Installable.drivers32 or Installable.drivers section if (!SetupFindFirstLine( hInf,TEXT("Installable.drivers32"),NULL,&InfContext)) { if (!SetupFindFirstLine( hInf,TEXT("Installable.drivers"),NULL,&InfContext)) { SetupCloseInfFile(hInf); return NULL; } } // Allocate the LEGACY_INF struct which is the root of the data struct pLI = (LEGACY_INF *)LocalAlloc(LPTR, sizeof(LEGACY_INF)); if (!pLI) { dlogt(szLocalAllocFailMsg); SetupCloseInfFile(hInf); return NULL; } // Save off the path to the legacy inf _tcscpy(pLI->szLegInfPath, szLegInfPath); // Init all other fields to 'safe' values pLI->szNewInfPath[0]='\0'; pLI->DriverList=NULL; pLI->SourceDiskList=NULL; pLI->FileList=NULL; // Build legacy driver list pLDList = NULL; do { // Allocate a structure to hold info about this driver pLD = (LEGACY_DRIVER *)LocalAlloc(LPTR, sizeof(LEGACY_DRIVER)); if (!pLD) { dlogt(szLocalAllocFailMsg); break; } // Init fields pLD->UserCopyList=NULL; pLD->KernCopyList=NULL; // parse the driver installation line SetupGetStringField(&InfContext,0,pLD->szDevNameKey,tsizeof(pLD->szDevNameKey),NULL); // The user-level driver has a disk id prepended to it. Throw it away. SetupGetStringField(&InfContext,1,szIdFile ,tsizeof(szIdFile) ,NULL); _tcscpy(pLD->szUserDevDrv,RemoveDiskId(szIdFile)); SetupGetStringField(&InfContext,2,pLD->szClasses ,tsizeof(pLD->szClasses) ,NULL); SetupGetStringField(&InfContext,3,pLD->szDesc ,tsizeof(pLD->szDesc) ,NULL); SetupGetStringField(&InfContext,4,pLD->szVxD ,tsizeof(pLD->szVxD) ,NULL); SetupGetStringField(&InfContext,5,pLD->szParams ,tsizeof(pLD->szParams) ,NULL); SetupGetStringField(&InfContext,6,pLD->szDependency,tsizeof(pLD->szDependency),NULL); // Remember to also copy the user-level driver AddFileToCopyList(pLI,pLD,szIdFile); // Put it into the list pLD->pNext = pLDList; pLDList = pLD; } while (SetupFindNextLine(&InfContext,&InfContext)); // Status check- did we find any drivers? // If not, clean up and get out now! if (pLDList==NULL) { dlog1("CreateLegacyInf: Didn't find any drivers in inf %s\n",szLegInfPath); SetupCloseInfFile(hInf); LocalFree(pLI); return NULL; } // Save list in Legacy Inf structure pLI->DriverList = pLDList; // Generate file copy lists for (pLD=pLDList;pLD;pLD=pLD->pNext) { // Now add the other files into the list if (SetupFindFirstLine(hInf,pLD->szDevNameKey,NULL,&InfContext)) { do { SetupGetStringField(&InfContext,0,szIdFile,tsizeof(szIdFile),NULL); AddFileToCopyList(pLI,pLD,szIdFile); } while (SetupFindNextLine(&InfContext,&InfContext)); } } // Generate the SourceDiskList iff we find a section that lists them if (SetupFindFirstLine(hInf,TEXT("Source Media Descriptions"),NULL,&InfContext)) { MediaDescFieldId=1; } else if (SetupFindFirstLine(hInf,TEXT("disks"),NULL,&InfContext)) // Old style { MediaDescFieldId=2; } else if (SetupFindFirstLine(hInf,TEXT("disks"),NULL,&InfContext)) // Old style { MediaDescFieldId=2; } else { MediaDescFieldId=0; } if (MediaDescFieldId) { do { SOURCEDISK *pSD; TCHAR szDiskId[8]; pSD = (SOURCEDISK *)LocalAlloc(LPTR, sizeof(SOURCEDISK)); if (!pSD) { dlogt(szLocalAllocFailMsg); break; } // Read the disk ID and description SetupGetIntField(&InfContext,0,&pSD->DiskId); SetupGetStringField(&InfContext,MediaDescFieldId,pSD->szDiskName,tsizeof(pSD->szDiskName),NULL); // Put it in the list pSD->pNext = pLI->SourceDiskList; pLI->SourceDiskList = pSD; } while (SetupFindNextLine(&InfContext,&InfContext)); } SetupCloseInfFile(hInf); return pLI; } // Build a list containing information about all the legacy infs in the specified directory PROCESS_INF_INFO *BuildLegacyInfInfo(PTSTR szLegacyInfDir, BOOL bEnumSingleInf) { LEGACY_INF *pLegacyInf; PROCESS_INF_INFO *pPII; TCHAR PathBuffer[_MAX_PATH]; dlog1("ProcessLegacyInfDirectory processing directory %s\n",szLegacyInfDir); // Allocate a process inf info struct to hold params relating to the conversion process pPII = (PROCESS_INF_INFO *)LocalAlloc(LPTR, sizeof(PROCESS_INF_INFO)); if (!pPII) { dlogt(szLocalAllocFailMsg); return NULL; } // Get a path to the windows inf directory if (!GetWindowsDirectory(pPII->szSysInfDir,tsizeof(pPII->szSysInfDir))) { DestroyLegacyInfInfo(pPII); return NULL; } catpath(pPII->szSysInfDir,TEXT("\\INF")); // Create a temp dir for the new infs under the windows inf directory _tcscpy(pPII->szNewInfDir,pPII->szSysInfDir); catpath(pPII->szNewInfDir,TEXT("\\MEDIAINF")); // If the directory exists, delete it RemoveDirectoryTree(pPII->szNewInfDir); // Now create it. CreateDirectory(pPII->szNewInfDir,NULL); // Init list to NULL pPII->LegInfList=NULL; if (bEnumSingleInf) // If bEnumSingleInf true, szLegacyInfDir points to a single file { // Grab the path to the directory and store it in pPII->szLegInfDir _tcscpy(PathBuffer,szLegacyInfDir); _tcscpy(pPII->szLegInfDir,StripPathName(PathBuffer)); // Load all the information about the legacy inf pLegacyInf = CreateLegacyInf(szLegacyInfDir); // If no error, link it into the list if (pLegacyInf) { pLegacyInf->pNext = pPII->LegInfList; pPII->LegInfList = pLegacyInf; } } else // bEnumSingleInf false, szLegacyInfDir points to a directory { HANDLE FindHandle; WIN32_FIND_DATA FindData; PTSTR CurrentInfFile; // Save path to original infs _tcscpy(pPII->szLegInfDir,szLegacyInfDir); // Build a file spec to find all INFs in specified directory, i.e., "\*.INF" _tcscpy(PathBuffer, szLegacyInfDir); catpath(PathBuffer,TEXT("\\*.INF")); // Get a pointer to the end of the path part of the string // (minus the wildcard filename), so that we can append // each filename to it. CurrentInfFile = _tcsrchr(PathBuffer, TEXT('\\')) + 1; // Search for all the inf files in this directory FindHandle = FindFirstFile(PathBuffer, &FindData); if (FindHandle != INVALID_HANDLE_VALUE) { do { // Build the full pathname. _tcscpy(CurrentInfFile, FindData.cFileName); // Load all the information about the legacy inf pLegacyInf = CreateLegacyInf(PathBuffer); // If no error, link it into the list if (pLegacyInf) { pLegacyInf->pNext = pPII->LegInfList; pPII->LegInfList = pLegacyInf; } } while (FindNextFile(FindHandle, &FindData)); // Remember to close the find handle FindClose(FindHandle); } } // If we didn't find any drivers, just return NULL. if (pPII->LegInfList==NULL) { DestroyLegacyInfInfo(pPII); return NULL; } return pPII; } // Create a unique inf file in the temp directory // Files will have the name INFxxxx.INF, where xxxx is a value between 0 and 1000 HANDLE OpenUniqueInfFile(PTSTR szDir, PTSTR szNewPath) { HANDLE hInf; int Id; // Try up to 1000 values before giving up for (Id=0;Id<1000;Id++) { wsprintf(szNewPath,TEXT("%s\\INF%d.inf"),szDir,Id); // Setting CREATE_NEW flag will make call fail if file already exists hInf = CreateFile( szNewPath, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); // If we got back a valid handle, we can return if (hInf!=INVALID_HANDLE_VALUE) { return hInf; } } // Never found a valid handle. Give up. dlog("OpenUniqueInfFile: Couldn't create unique inf\n"); return INVALID_HANDLE_VALUE; } // Helper function to append one formatted line of text to an open inf void cdecl InfPrintf(HANDLE hInf, LPTSTR szFormat, ...) { TCHAR Buf[MAXSTRINGLEN]; int nChars; // format into buffer va_list va; va_start (va, szFormat); nChars = wvsprintf (Buf,szFormat,va); va_end (va); // Append cr-lf _tcscpy(&Buf[nChars],TEXT("\r\n")); nChars+=2; #ifdef UNICODE { int mbCount; char mbBuf[MAXSTRINGLEN]; // Need to converto to mbcs before writing to file mbCount = WideCharToMultiByte( GetACP(), // code page WC_NO_BEST_FIT_CHARS, // performance and mapping flags Buf, // address of wide-character string nChars, // number of characters in string mbBuf, // address of buffer for new string sizeof(mbBuf), // size of buffer NULL, // address of default for unmappable characters NULL // address of flag set when default char. used ); // Write line out to file WriteFile(hInf,mbBuf,mbCount,&mbCount,NULL); } #else WriteFile(hInf,Buf,nChars,&nChars,NULL); #endif return; } // Creates a new NT5-style inf file in the temporary directory. BOOL CreateNewInfFile(PROCESS_INF_INFO *pPII, LEGACY_INF *pLI) { SOURCEDISK *pSD; TCHAR szTmpKey[_MAX_PATH]; LEGACY_DRIVER *pLDList, *pLD; HANDLE hInf; FILETOCOPY *pFTC; // Get a pointer to the legacy driver list pLDList = pLI->DriverList; dlog1("Creating new inf file %s\n",pPII->szNewInfDir); hInf = OpenUniqueInfFile(pPII->szNewInfDir, pLI->szNewInfPath); if (hInf==INVALID_HANDLE_VALUE) { return FALSE; } // Write out version section InfPrintf(hInf,TEXT("[version]")); InfPrintf(hInf,TEXT("Signature=\"$WINDOWS NT$\"")); InfPrintf(hInf,TEXT("Class=MEDIA")); InfPrintf(hInf,TEXT("ClassGUID=\"{4d36e96c-e325-11ce-bfc1-08002be10318}\"")); InfPrintf(hInf,TEXT("Provider=Unknown")); // Write out Manufacturer section InfPrintf(hInf,TEXT("[Manufacturer]")); InfPrintf(hInf,TEXT("Unknown=OldDrvs")); // Write out OldDrvs section InfPrintf(hInf,TEXT("[OldDrvs]")); for (pLD=pLDList;pLD;pLD=pLD->pNext) { // Create an key to index into the strings section // This gives us something like: // %foo% = foo InfPrintf(hInf,TEXT("%%%s%%=%s"),pLD->szDevNameKey,pLD->szDevNameKey); } // Write out install section for each device for (pLD=pLDList;pLD;pLD=pLD->pNext) { // install section header, remember NT only InfPrintf(hInf,TEXT("[%s.NT]"),pLD->szDevNameKey); // DriverVer entry. Pick a date that's earlier than any NT5 infs InfPrintf(hInf,TEXT("DriverVer = 1/1/1998, 4.0.0.0")); // Addreg entry InfPrintf(hInf,TEXT("AddReg=%s.AddReg"),pLD->szDevNameKey); // CopyFiles entry InfPrintf(hInf,TEXT("CopyFiles=%s.CopyFiles.User,%s.CopyFiles.Kern"),pLD->szDevNameKey,pLD->szDevNameKey); // Reboot entry. Legacy drivers always require a reboot InfPrintf(hInf,TEXT("Reboot")); } // Write out the services section for each device // Legacy drivers have a stub services key for (pLD=pLDList;pLD;pLD=pLD->pNext) { InfPrintf(hInf,TEXT("[%s.NT.Services]"),pLD->szDevNameKey); #if GUESS_LEGACY_SERVICE_NAME // If we install a .sys file, assume that the service name is the same as the filename pFTC=pLD->KernCopyList; if (pFTC) { TCHAR szServiceName[_MAX_FNAME]; lsplitpath(pFTC->szFileName,NULL,NULL,szServiceName,NULL); InfPrintf(hInf,TEXT("AddService=%s,0x2,%s_Service_Inst"),szServiceName,szServiceName); InfPrintf(hInf,TEXT("[%s_Service_Inst]"),szServiceName); InfPrintf(hInf,TEXT("DisplayName = %%%s%%"),pLD->szDevNameKey); InfPrintf(hInf,TEXT("ServiceType = 1")); InfPrintf(hInf,TEXT("StartType = 1")); InfPrintf(hInf,TEXT("ErrorControl = 1")); InfPrintf(hInf,TEXT("ServiceBinary = %%12%%\\%s"),pFTC->szFileName); InfPrintf(hInf,TEXT("LoadOrderGroup = Base")); } else { InfPrintf(hInf,TEXT("AddService=,0x2")); } #else InfPrintf(hInf,TEXT("AddService=,0x2")); #endif } // Write out the AddReg section for each device for (pLD=pLDList;pLD;pLD=pLD->pNext) { int nClasses; TCHAR szClasses[_MAX_PATH]; TCHAR *pszState, *pszClass; // section header InfPrintf(hInf,TEXT("[%s.AddReg]"),pLD->szDevNameKey); InfPrintf(hInf,TEXT("HKR,Drivers,SubClasses,,\"%s\""),pLD->szClasses); // For safety, copy the string (mystrtok corrupts the original source string) _tcscpy(szClasses,pLD->szClasses); for ( pszClass = mystrtok(szClasses,NULL,&pszState); pszClass; pszClass = mystrtok(NULL,NULL,&pszState) ) { InfPrintf(hInf,TEXT("HKR,\"Drivers\\%s\\%s\", Driver,,%s"), pszClass,pLD->szUserDevDrv,pLD->szUserDevDrv); InfPrintf(hInf,TEXT("HKR,\"Drivers\\%s\\%s\", Description,,%%%s%%"),pszClass,pLD->szUserDevDrv,pLD->szDevNameKey); } } // Write out the CopyFiles section for each device for user files for (pLD=pLDList;pLD;pLD=pLD->pNext) { // section header InfPrintf(hInf,TEXT("[%s.CopyFiles.User]"),pLD->szDevNameKey); for (pFTC=pLD->UserCopyList;pFTC;pFTC=pFTC->pNext) { InfPrintf(hInf,TEXT("%s"),pFTC->szFileName); } } // Write out the CopyFiles section for each device for kern files for (pLD=pLDList;pLD;pLD=pLD->pNext) { // section header InfPrintf(hInf,TEXT("[%s.CopyFiles.Kern]"),pLD->szDevNameKey); for (pFTC=pLD->KernCopyList;pFTC;pFTC=pFTC->pNext) { InfPrintf(hInf,TEXT("%s"),pFTC->szFileName); } } // Write out DestinationDirs section InfPrintf(hInf,TEXT("[DestinationDirs]")); for (pLD=pLDList;pLD;pLD=pLD->pNext) { InfPrintf(hInf,TEXT("%s.CopyFiles.User = 11"),pLD->szDevNameKey); InfPrintf(hInf,TEXT("%s.CopyFiles.Kern = 12"),pLD->szDevNameKey); } // Write out the SourceDisksNames section InfPrintf(hInf,TEXT("[SourceDisksNames]")); for (pSD=pLI->SourceDiskList;pSD;pSD=pSD->pNext) { InfPrintf(hInf,TEXT("%d = \"%s\",\"\",1"),pSD->DiskId,pSD->szDiskName); } // Write out the SourceDisksFiles section InfPrintf(hInf,TEXT("[SourceDisksFiles]")); for (pFTC=pLI->FileList;pFTC;pFTC=pFTC->pNext) { InfPrintf(hInf,TEXT("%s=%d"),pFTC->szFileName,pFTC->DiskId); } // Write out Strings section InfPrintf(hInf,TEXT("[Strings]")); for (pLD=pLDList;pLD;pLD=pLD->pNext) { // Create the device description InfPrintf(hInf,TEXT("%s=\"%s\""),pLD->szDevNameKey,pLD->szDesc); } CloseHandle(hInf); return TRUE; } // Creates a PNF file in the temporary directory to go along with the inf // This allows us to have the inf file in one directory while the driver's // files are in a different directory. BOOL CreateNewPnfFile(PROCESS_INF_INFO *pPII, LEGACY_INF *pLI) { BOOL bSuccess; TCHAR szSysInfPath[_MAX_PATH]; TCHAR szSysPnfPath[_MAX_PATH]; TCHAR szTmpPnfPath[_MAX_PATH]; TCHAR szSysInfDrive[_MAX_DRIVE]; TCHAR szSysInfDir[_MAX_DIR]; TCHAR szSysInfFile[_MAX_FNAME]; TCHAR szNewInfDrive[_MAX_DRIVE]; TCHAR szNewInfDir[_MAX_DIR]; TCHAR szNewInfFile[_MAX_FNAME]; // Copy inf to inf directory to create pnf file bSuccess = SetupCopyOEMInf( pLI->szNewInfPath, // IN PCSTR SourceInfFileName, pPII->szLegInfDir, // IN PCSTR OEMSourceMediaLocation, OPTIONAL SPOST_PATH, // IN DWORD OEMSourceMediaType, 0, // IN DWORD CopyStyle, szSysInfPath, // OUT PSTR DestinationInfFileName, OPTIONAL tsizeof(szSysInfPath), // IN DWORD DestinationInfFileNameSize, NULL, // OUT PDWORD RequiredSize, OPTIONAL NULL // OUT PSTR *DestinationInfFileNameComponent OPTIONAL ); if (!bSuccess) { dlog1("CreateNewPnfFile: SetupCopyOEMInf failed for inf %s\n",pLI->szNewInfPath); return FALSE; } // Cut apart the directory names lsplitpath(szSysInfPath, szSysInfDrive, szSysInfDir, szSysInfFile, NULL); lsplitpath(pLI->szNewInfPath, szNewInfDrive, szNewInfDir, szNewInfFile, NULL); // Copy the pnf file back to the original directory wsprintf(szSysPnfPath,TEXT("%s%s%s.pnf"), szSysInfDrive, szSysInfDir, szSysInfFile); wsprintf(szTmpPnfPath,TEXT("%s%s%s.pnf"), szNewInfDrive, szNewInfDir, szNewInfFile); CopyFile(szSysPnfPath, szTmpPnfPath, FALSE); // Delete the inf and pnf file in the system inf directory DeleteFile(szSysInfPath); DeleteFile(szSysPnfPath); return TRUE; } // Create a new inf file for each legacy inf in the list BOOL ProcessLegacyInfInfo(PROCESS_INF_INFO *pPII) { LEGACY_INF *pLI; BOOL bSuccess; for (pLI=pPII->LegInfList;pLI;pLI=pLI->pNext) { bSuccess = CreateNewInfFile(pPII,pLI); if (bSuccess) { CreateNewPnfFile(pPII,pLI); } } return TRUE; } BOOL ConvertLegacyInfDir(PTSTR szLegacyDir, PTSTR szNewDir, BOOL bEnumSingleInf) { PROCESS_INF_INFO *pPII; // Couldn't find any NT5-style drivers. Try to find some legacy inf files. // Build the list pPII = BuildLegacyInfInfo(szLegacyDir, bEnumSingleInf); if (!pPII) { return FALSE; } // Process the list ProcessLegacyInfInfo(pPII); if (bEnumSingleInf) { // if bEnumSingleInf is true, we should return a path to the new inf // (there should be exactly one) _tcscpy(szNewDir,pPII->LegInfList->szNewInfPath); } else { // if bEnumSingleInf is false, we should return a path to the directory _tcscpy(szNewDir,pPII->szNewInfDir); } // Cleanup data structures DestroyLegacyInfInfo(pPII); return TRUE; } int CountDriverInfoList(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, IN DWORD DriverType ) { SP_DRVINFO_DATA DriverInfoData; SP_DRVINSTALL_PARAMS DriverInstallParams; int DriverCount = 0; int Count = 0; // Count the number of drivers in the list DriverInfoData.cbSize = sizeof(DriverInfoData); while (SetupDiEnumDriverInfo(DeviceInfoSet, DeviceInfoData, DriverType, Count, &DriverInfoData)) { // Only count drivers which don't have the DNF_BAD_DRIVER flag set DriverInstallParams.cbSize=sizeof(DriverInstallParams); if (SetupDiGetDriverInstallParams(DeviceInfoSet, DeviceInfoData, &DriverInfoData, &DriverInstallParams)) { if (!(DriverInstallParams.Flags & DNF_BAD_DRIVER)) { DriverCount++; } } Count++; } return DriverCount; } // Called to display a list of drivers to be installed DWORD Media_SelectDevice(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { BOOL bResult; SP_DEVINSTALL_PARAMS DeviceInstallParams; int DriverCount; // Undocumented: When user selects "Have Disk", setupapi only looks at the // class driver list. Therefore, we'll only work with that list DWORD DriverType = SPDIT_CLASSDRIVER; // Get the path to where the inf files are located DeviceInstallParams.cbSize = sizeof(DeviceInstallParams); bResult = SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams); if (!bResult) { return ERROR_DI_DO_DEFAULT; } // For safety, don't support append mode if (DeviceInstallParams.FlagsEx & DI_FLAGSEX_APPENDDRIVERLIST) { return ERROR_DI_DO_DEFAULT; } // If not going outside of inf directory, the DriverPath field will be an // empty string. In this case, don't do special processing. if (DeviceInstallParams.DriverPath[0]=='\0') { return ERROR_DI_DO_DEFAULT; } // We're going off to an OEM directory. // See if setup can find any NT5-compatible inf files // Try to build a driver info list in the current directory if (DeviceInfoSet) SetupDiDestroyDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType); SetupDiBuildDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType); // Filter out non NT inf files (e.g. Win9x inf files) if (DeviceInfoSet) FilterOutNonNTInfs(DeviceInfoSet,DeviceInfoData,DriverType); // Now count the number of drivers DriverCount = CountDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType); // If we found at least one NT5 driver for this device, just return if (DriverCount>0) { return ERROR_DI_DO_DEFAULT; } // Didn't find any NT5 drivers. // Destroy the existing list SetupDiDestroyDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType); //Retrieve the device install params prior to setting new INF path and update //any information DeviceInstallParams bResult = SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams); if (!bResult) { return ERROR_DI_DO_DEFAULT; } // Convert any legacy infs and get back ptr to temp directory for converted infs bResult = ConvertLegacyInfDir(DeviceInstallParams.DriverPath, DeviceInstallParams.DriverPath, (DeviceInstallParams.Flags & DI_ENUMSINGLEINF)); if (!bResult) { return ERROR_DI_DO_DEFAULT; // Didn't find any legacy infs } //Clean up this DI_FLAGSEX_FILTERSIMILARDRIVERS for old NT 4 driver installation. DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_FILTERSIMILARDRIVERS; // Save new driver path bResult = SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams); // Note: We don't have to call SetupDiBuildDriverInfoList; setupapi will do that for us // with the new path to the infs. return ERROR_DI_DO_DEFAULT; } BOOL CreateRootDevice( IN HDEVINFO DeviceInfoSet, IN PTSTR DeviceId, IN BOOL bInstallNow ) { BOOL bResult; SP_DEVINFO_DATA DeviceInfoData; SP_DRVINFO_DATA DriverInfoData; SP_DEVINSTALL_PARAMS DeviceInstallParams; TCHAR tmpBuffer[100]; DWORD bufferLen; DWORD Error; // Attempt to manufacture a new device information element for the root enumerated device _tcscpy(tmpBuffer,TEXT("ROOT\\MEDIA\\")); if ((lstrlen(tmpBuffer)+ lstrlen(DeviceId)) < ARRAYSIZE(tmpBuffer)) { _tcscat(tmpBuffer,DeviceId); } dlog2("CreateRootDevice: DeviceId = %s, Device = %s%",DeviceId,tmpBuffer); // Try to create the device info DeviceInfoData.cbSize = sizeof( DeviceInfoData ); bResult = SetupDiCreateDeviceInfo( DeviceInfoSet, tmpBuffer, (GUID *) &GUID_DEVCLASS_MEDIA, NULL, // PCTSTR DeviceDescription NULL, // HWND hwndParent 0, &DeviceInfoData ); if (!bResult) { Error = GetLastError(); dlog1("CreateRootDevice: SetupDiCreateDeviceInfo failed Error=%x",Error); return (Error == ERROR_DEVINST_ALREADY_EXISTS); } // Set the hardware ID. _tcscpy(tmpBuffer, DeviceId); bufferLen = _tcslen(tmpBuffer); // Get buffer len in chars tmpBuffer[bufferLen+1] = TEXT('\0'); // must terminate with an extra null (so we have two nulls) bufferLen = (bufferLen + 2) * sizeof(TCHAR); // Convert buffer length to bytes & add extra for two nulls bResult = SetupDiSetDeviceRegistryProperty( DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, (PBYTE)tmpBuffer, bufferLen ); if (!bResult) goto CreateRootDevice_err; // Setup some flags before building a driver list bResult = SetupDiGetDeviceInstallParams( DeviceInfoSet,&DeviceInfoData,&DeviceInstallParams); if (bResult) { _tcscpy( DeviceInstallParams.DriverPath, TEXT( "" ) ); DeviceInstallParams.FlagsEx |= DI_FLAGSEX_USECLASSFORCOMPAT; bResult = SetupDiSetDeviceInstallParams( DeviceInfoSet,&DeviceInfoData,&DeviceInstallParams); } // Build a compatible driver list for this new device... bResult = SetupDiBuildDriverInfoList( DeviceInfoSet, &DeviceInfoData, SPDIT_COMPATDRIVER); if (!bResult) goto CreateRootDevice_err; // Get the first driver on the list DriverInfoData.cbSize = sizeof (DriverInfoData); bResult = SetupDiEnumDriverInfo( DeviceInfoSet, &DeviceInfoData, SPDIT_COMPATDRIVER, 0, &DriverInfoData); if (!bResult) goto CreateRootDevice_err; // Save the device description bResult = SetupDiSetDeviceRegistryProperty( DeviceInfoSet, &DeviceInfoData, SPDRP_DEVICEDESC, (PBYTE) DriverInfoData.Description, (_tcslen( DriverInfoData.Description ) + 1) * sizeof( TCHAR ) ); if (!bResult) goto CreateRootDevice_err; // Set the selected driver bResult = SetupDiSetSelectedDriver( DeviceInfoSet, &DeviceInfoData, &DriverInfoData); if (!bResult) goto CreateRootDevice_err; // Register the device so it is not a phantom anymore bResult = SetupDiRegisterDeviceInfo( DeviceInfoSet, &DeviceInfoData, 0, NULL, NULL, NULL); if (!bResult) goto CreateRootDevice_err; return bResult; // Error, delete the device info and give up CreateRootDevice_err: SetupDiDeleteDeviceInfo (DeviceInfoSet, &DeviceInfoData); return FALSE; } DWORD Media_MigrateLegacy(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) { BOOL bInstallNow = TRUE; CreateRootDevice(DeviceInfoSet, TEXT("MS_MMMCI"), bInstallNow); CreateRootDevice(DeviceInfoSet, TEXT("MS_MMVID"), bInstallNow); CreateRootDevice(DeviceInfoSet, TEXT("MS_MMACM"), bInstallNow); CreateRootDevice(DeviceInfoSet, TEXT("MS_MMVCD"), bInstallNow); CreateRootDevice(DeviceInfoSet, TEXT("MS_MMDRV"), bInstallNow); return NO_ERROR; } int IsSpecialDriver(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData) { BOOL bResult; TCHAR HardwareId[32]; bResult = SetupDiGetDeviceRegistryProperty( DeviceInfoSet, DeviceInfoData, SPDRP_HARDWAREID, NULL, (PBYTE)HardwareId, sizeof(HardwareId), NULL ); if (!_tcscmp(HardwareId,TEXT("MS_MMMCI"))) return IS_MS_MMMCI; else if (!_tcscmp(HardwareId,TEXT("MS_MMVID"))) return IS_MS_MMVID; else if (!_tcscmp(HardwareId,TEXT("MS_MMACM"))) return IS_MS_MMACM; else if (!_tcscmp(HardwareId,TEXT("MS_MMVCD"))) return IS_MS_MMVCD; else if (!_tcscmp(HardwareId,TEXT("MS_MMDRV"))) return IS_MS_MMDRV; return 0; } BOOL IsPnPDriver(IN PTSTR szName) { LONG lRet; HKEY hkClass; int iDriverInst; TCHAR szDriverInst[32]; HKEY hkDriverInst; int iDriverType; TCHAR szDriverType[32]; HKEY hkDriverType; int iDriverName; TCHAR szDriverName[32]; // Open class key hkClass = SetupDiOpenClassRegKey((GUID *) &GUID_DEVCLASS_MEDIA, KEY_READ); if (hkClass == INVALID_HANDLE_VALUE) { return FALSE; } // enumerate each driver instances (e.g. 0000, 0001, etc.) for (iDriverInst = 0; !RegEnumKey(hkClass, iDriverInst, szDriverInst, sizeof(szDriverInst)/sizeof(TCHAR)); iDriverInst++) { // Open the Drivers subkey, (e.g. 0000\Drivers) if (lstrlen(szDriverInst) > 23) // 23 is the max length minus "\Drivers" plus a NULL { continue; } _tcscat(szDriverInst,TEXT("\\Drivers")); lRet = RegOpenKey(hkClass, szDriverInst, &hkDriverInst); if (lRet!=ERROR_SUCCESS) { continue; } // Enumerate each of the driver types (e.g. wave, midi, mixer, etc.) for (iDriverType = 0; !RegEnumKey(hkDriverInst, iDriverType, szDriverType, sizeof(szDriverType)/sizeof(TCHAR)); iDriverType++) { // Open the driver type subkey lRet = RegOpenKey(hkDriverInst, szDriverType, &hkDriverType); if (lRet!=ERROR_SUCCESS) { continue; } // Enumerate each of the driver names (e.g. foo.drv) for (iDriverName = 0; !RegEnumKey(hkDriverType, iDriverName, szDriverName, sizeof(szDriverName)/sizeof(TCHAR)); iDriverName++) { // Does this name match the one we were passed? if (!_tcsicmp(szName,szDriverName)) { RegCloseKey(hkDriverType); RegCloseKey(hkDriverInst); RegCloseKey(hkClass); return TRUE; } } RegCloseKey(hkDriverType); } RegCloseKey(hkDriverInst); } RegCloseKey(hkClass); return FALSE; }