|
|
#include "mmcpl.h"
#include <tchar.h>
#include <initguid.h>
#include <devguid.h>
#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., <DirPath>\*.INF)
_tcscpy(PathBuffer, szDirTree); 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 <DiskId>:<File> 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., "<DirPath>\*.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\\")); _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; }
|