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.
1267 lines
42 KiB
1267 lines
42 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)
|
|
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 <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\\"));
|
|
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;
|
|
}
|
|
|