Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1264 lines
40 KiB

#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;
}