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

  1. #include "mmcpl.h"
  2. #include <tchar.h>
  3. #include <initguid.h>
  4. #include <devguid.h>
  5. #include "drivers.h"
  6. #include "sulib.h"
  7. #include "trayvol.h"
  8. #include "debug.h"
  9. static PTSTR szLocalAllocFailMsg = TEXT("Failed memory allocation\n");
  10. #define GUESS_LEGACY_SERVICE_NAME 0
  11. #define tsizeof(s) (sizeof(s)/sizeof(TCHAR))
  12. // Generic listnode structure
  13. typedef struct _LISTNODE
  14. {
  15. struct _LISTNODE *pNext;
  16. } LISTNODE;
  17. // Structure describing a source disk entry
  18. typedef struct _SOURCEDISK
  19. {
  20. struct _SOURCEDISK *pNext; // Next source disk in list
  21. TCHAR szDiskName[_MAX_PATH]; // Description of this disk
  22. int DiskId;
  23. } SOURCEDISK;
  24. // Structure describing a file to copy
  25. // We keep a list of these files in two places:
  26. // 1. A global list of all files copied by the inf attached to the LEGACY_INF struct.
  27. // 2. A pair driver-specific lists (user & kernel) attached to the LEGACY_DRIVER struct.
  28. typedef struct _FILETOCOPY
  29. {
  30. struct _FILETOCOPY *pNext; // Next file to copy
  31. TCHAR szFileName[_MAX_FNAME]; // Name of file to copy
  32. int DiskId;
  33. } FILETOCOPY;
  34. // Structure representing a legacy driver's information
  35. typedef struct _LEGACY_DRIVER
  36. {
  37. struct _LEGACY_DRIVER *pNext;
  38. TCHAR szDevNameKey[32]; // Device name key
  39. TCHAR szUserDevDrv[32]; // User-level device driver
  40. TCHAR szClasses[128]; // List of device classes this driver supports
  41. TCHAR szDesc[128]; // Description of device
  42. TCHAR szVxD[32]; // Name of VxD driver (not supported)
  43. TCHAR szParams[128]; // Params (not supported)
  44. TCHAR szDependency[128]; // Dependent device (not supported)
  45. FILETOCOPY *UserCopyList; // List of all user files to copy
  46. FILETOCOPY *KernCopyList; // List of all kernel files to copy
  47. } LEGACY_DRIVER;
  48. // Structure representing a legacy inf
  49. typedef struct _LEGACY_INF
  50. {
  51. struct _LEGACY_INF *pNext;
  52. TCHAR szLegInfPath[_MAX_PATH]; // Path to original legacy inf
  53. TCHAR szNewInfPath[_MAX_PATH]; // Path to converted inf
  54. LEGACY_DRIVER *DriverList; // List of all drivers in this inf
  55. SOURCEDISK *SourceDiskList; // List of all source disks in this inf
  56. FILETOCOPY *FileList; // List of all files copied as part of this inf
  57. } LEGACY_INF;
  58. // Root structure for the whole tree
  59. typedef struct _PROCESS_INF_INFO
  60. {
  61. TCHAR szLegInfDir[_MAX_PATH]; // Directory where legacy infs are located
  62. TCHAR szNewInfDir[_MAX_PATH]; // Temp directory where new infs are generated
  63. TCHAR szSysInfDir[_MAX_PATH]; // Windows inf directory
  64. TCHAR szTemplate[_MAX_PATH]; // Template to search for
  65. LEGACY_INF *LegInfList; // List of all infs to be converted
  66. } PROCESS_INF_INFO;
  67. #if defined DEBUG || defined _DEBUG || defined DEBUG_RETAIL
  68. // Debugging routine to dump the contents of a LEGACY_INF list
  69. void DumpLegacyInfInfo(PROCESS_INF_INFO *pPII)
  70. {
  71. LEGACY_INF *pLI;
  72. LEGACY_DRIVER *pLD;
  73. for (pLI=pPII->LegInfList;pLI;pLI=pLI->pNext)
  74. {
  75. dlog1("Dumping legacy inf %s\n",pLI->szLegInfPath);
  76. dlog("Dump of legacy driver info:\n");
  77. for (pLD=pLI->DriverList; pLD; pLD=pLD->pNext)
  78. {
  79. dlog1("DriverNode=0x%x", pLD);
  80. dlog1("\tszDevNameKey=%s", pLD->szDevNameKey);
  81. dlog1("\tszUserDevDrv=%s", pLD->szUserDevDrv);
  82. dlog1("\tszClasses=%s", pLD->szClasses);
  83. dlog1("\tszDesc=%s", pLD->szDesc);
  84. dlog1("\tszVxD=%s", pLD->szVxD);
  85. dlog1("\tszParams=%s", pLD->szParams);
  86. dlog1("\tszDependency=%s", pLD->szDependency);
  87. }
  88. }
  89. return;
  90. }
  91. #else
  92. #define DumpLegacyInfInfo()
  93. #endif
  94. // Function to remove a directory tree and all its subtrees
  95. void RemoveDirectoryTree(PTSTR szDirTree)
  96. {
  97. TCHAR PathBuffer[_MAX_PATH];
  98. PTSTR CurrentFile;
  99. HANDLE FindHandle;
  100. WIN32_FIND_DATA FindData;
  101. PathBuffer[0] = '\0';
  102. // Build a file spec to find all files in specified directory
  103. // (i.e., <DirPath>\*.INF)
  104. _tcscpy(PathBuffer, szDirTree);
  105. catpath(PathBuffer,TEXT("\\*"));
  106. // Get a pointer to the end of the path part of the string
  107. // (minus the wildcard filename), so that we can append
  108. // each filename to it.
  109. CurrentFile = _tcsrchr(PathBuffer, TEXT('\\')) + 1;
  110. FindHandle = FindFirstFile(PathBuffer, &FindData);
  111. if (FindHandle == INVALID_HANDLE_VALUE)
  112. {
  113. return;
  114. }
  115. do
  116. {
  117. // Skip '.' and '..' files, or else we crash!
  118. if ( (!_tcsicmp(FindData.cFileName,TEXT("."))) ||
  119. (!_tcsicmp(FindData.cFileName,TEXT(".."))) )
  120. {
  121. continue;
  122. }
  123. // Build the full pathname.
  124. _tcscpy(CurrentFile, FindData.cFileName);
  125. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  126. {
  127. RemoveDirectoryTree(PathBuffer);
  128. }
  129. else
  130. {
  131. DeleteFile(PathBuffer);
  132. }
  133. } while (FindNextFile(FindHandle, &FindData));
  134. // Remember to close the find handle
  135. FindClose(FindHandle);
  136. // Now remove the directory
  137. RemoveDirectory(szDirTree);
  138. return;
  139. }
  140. // Generic routine to free a list
  141. void FreeList(LISTNODE *pList)
  142. {
  143. LISTNODE *pNext;
  144. while (pList)
  145. {
  146. pNext = pList->pNext;
  147. LocalFree(pList);
  148. pList=pNext;
  149. }
  150. return;
  151. }
  152. // Routine to free all memory that is part of a PROCESS_INF_INFO struct
  153. void DestroyLegacyInfInfo(PROCESS_INF_INFO *pPII)
  154. {
  155. LEGACY_INF *pLIList, *pLINext;
  156. LEGACY_DRIVER *pLDList, *pLDNext;
  157. pLIList=pPII->LegInfList;
  158. while (pLIList)
  159. {
  160. pLINext = pLIList->pNext;
  161. pLDList = pLIList->DriverList;
  162. while (pLDList)
  163. {
  164. pLDNext = pLDList->pNext;
  165. // Free file copy lists
  166. FreeList((LISTNODE *)pLDList->UserCopyList);
  167. FreeList((LISTNODE *)pLDList->KernCopyList);
  168. // Free Driver node
  169. LocalFree(pLDList);
  170. pLDList = pLDNext;
  171. }
  172. // Free the source disk list
  173. FreeList((LISTNODE *)pLIList->SourceDiskList);
  174. // Free the file list
  175. FreeList((LISTNODE *)pLIList->FileList);
  176. // Free up the legacy inf structure
  177. LocalFree(pLIList);
  178. pLIList = pLINext;
  179. }
  180. // Free the pPII struct
  181. LocalFree(pPII);
  182. return;
  183. }
  184. // Searches a file list for a matching entry
  185. FILETOCOPY *FindFile(PTSTR szFileName, FILETOCOPY *pFileList)
  186. {
  187. FILETOCOPY *pFTC;
  188. for (pFTC=pFileList;pFTC;pFTC=pFTC->pNext)
  189. {
  190. if (!_tcsicmp(szFileName,pFTC->szFileName))
  191. {
  192. return pFileList;
  193. }
  194. }
  195. return NULL;
  196. }
  197. // Generic function for adding a file to a copy list
  198. BOOL AddFileToFileList(PTSTR szFileName, int DiskId, FILETOCOPY **ppList)
  199. {
  200. FILETOCOPY *pFTC;
  201. // Only add the entry if another one doesn't already exist
  202. if (!FindFile(szFileName,*ppList))
  203. {
  204. pFTC = (FILETOCOPY *)LocalAlloc(LPTR, sizeof(FILETOCOPY));
  205. if (!pFTC)
  206. {
  207. dlogt(szLocalAllocFailMsg);
  208. return FALSE;
  209. }
  210. // Save the fields
  211. pFTC->DiskId=DiskId;
  212. _tcscpy(pFTC->szFileName,szFileName);
  213. // Put it in the list
  214. pFTC->pNext=(*ppList);
  215. (*ppList)=pFTC;
  216. }
  217. return TRUE;
  218. }
  219. // Add a file to both the global and driver-specific copy lists
  220. BOOL AddFileToCopyList(LEGACY_INF *pLI, LEGACY_DRIVER *pLD, TCHAR *szIdFile)
  221. {
  222. int DiskId;
  223. TCHAR *szFileName;
  224. // szFile has both a disk ID and a file name, e.g. "1:foo.drv"
  225. // Get the disk ID and file name from szFile
  226. DiskId = _ttol(szIdFile);
  227. szFileName = RemoveDiskId(szIdFile);
  228. // Add the file to the global list
  229. AddFileToFileList(szFileName,DiskId,&(pLI->FileList));
  230. // Add the file to the correct driver-specific list
  231. if (IsFileKernelDriver(szFileName))
  232. {
  233. AddFileToFileList(szFileName,DiskId,&(pLD->KernCopyList));
  234. }
  235. else
  236. {
  237. AddFileToFileList(szFileName,DiskId,&(pLD->UserCopyList));
  238. }
  239. return TRUE;
  240. }
  241. // Build the data structure associated with a legacy inf file
  242. // and return a pointer to it, or NULL if failure
  243. LEGACY_INF *CreateLegacyInf(IN PCTSTR szLegInfPath)
  244. {
  245. HINF hInf; // Handle to the legacy inf
  246. INFCONTEXT InfContext; // Inf context struct for parsing inf file
  247. LEGACY_INF *pLI; // Struct describing this inf
  248. LEGACY_DRIVER *pLDList; // ptrs to drivers in this inf
  249. LEGACY_DRIVER *pLD;
  250. TCHAR szIdFile[32]; // Holds <DiskId>:<File> strings, e.g. "1:foo.drv"
  251. int MediaDescFieldId;
  252. // Open the inf file
  253. hInf = SetupOpenInfFile( szLegInfPath, NULL, INF_STYLE_OLDNT, NULL);
  254. if (hInf==INVALID_HANDLE_VALUE)
  255. {
  256. return NULL;
  257. }
  258. // Try to open the Installable.drivers32 or Installable.drivers section
  259. if (!SetupFindFirstLine( hInf,TEXT("Installable.drivers32"),NULL,&InfContext))
  260. {
  261. if (!SetupFindFirstLine( hInf,TEXT("Installable.drivers"),NULL,&InfContext))
  262. {
  263. SetupCloseInfFile(hInf);
  264. return NULL;
  265. }
  266. }
  267. // Allocate the LEGACY_INF struct which is the root of the data struct
  268. pLI = (LEGACY_INF *)LocalAlloc(LPTR, sizeof(LEGACY_INF));
  269. if (!pLI)
  270. {
  271. dlogt(szLocalAllocFailMsg);
  272. SetupCloseInfFile(hInf);
  273. return NULL;
  274. }
  275. // Save off the path to the legacy inf
  276. _tcscpy(pLI->szLegInfPath, szLegInfPath);
  277. // Init all other fields to 'safe' values
  278. pLI->szNewInfPath[0]='\0';
  279. pLI->DriverList=NULL;
  280. pLI->SourceDiskList=NULL;
  281. pLI->FileList=NULL;
  282. // Build legacy driver list
  283. pLDList = NULL;
  284. do
  285. {
  286. // Allocate a structure to hold info about this driver
  287. pLD = (LEGACY_DRIVER *)LocalAlloc(LPTR, sizeof(LEGACY_DRIVER));
  288. if (!pLD)
  289. {
  290. dlogt(szLocalAllocFailMsg);
  291. break;
  292. }
  293. // Init fields
  294. pLD->UserCopyList=NULL;
  295. pLD->KernCopyList=NULL;
  296. // parse the driver installation line
  297. SetupGetStringField(&InfContext,0,pLD->szDevNameKey,tsizeof(pLD->szDevNameKey),NULL);
  298. // The user-level driver has a disk id prepended to it. Throw it away.
  299. SetupGetStringField(&InfContext,1,szIdFile ,tsizeof(szIdFile) ,NULL);
  300. _tcscpy(pLD->szUserDevDrv,RemoveDiskId(szIdFile));
  301. SetupGetStringField(&InfContext,2,pLD->szClasses ,tsizeof(pLD->szClasses) ,NULL);
  302. SetupGetStringField(&InfContext,3,pLD->szDesc ,tsizeof(pLD->szDesc) ,NULL);
  303. SetupGetStringField(&InfContext,4,pLD->szVxD ,tsizeof(pLD->szVxD) ,NULL);
  304. SetupGetStringField(&InfContext,5,pLD->szParams ,tsizeof(pLD->szParams) ,NULL);
  305. SetupGetStringField(&InfContext,6,pLD->szDependency,tsizeof(pLD->szDependency),NULL);
  306. // Remember to also copy the user-level driver
  307. AddFileToCopyList(pLI,pLD,szIdFile);
  308. // Put it into the list
  309. pLD->pNext = pLDList;
  310. pLDList = pLD;
  311. } while (SetupFindNextLine(&InfContext,&InfContext));
  312. // Status check- did we find any drivers?
  313. // If not, clean up and get out now!
  314. if (pLDList==NULL)
  315. {
  316. dlog1("CreateLegacyInf: Didn't find any drivers in inf %s\n",szLegInfPath);
  317. SetupCloseInfFile(hInf);
  318. LocalFree(pLI);
  319. return NULL;
  320. }
  321. // Save list in Legacy Inf structure
  322. pLI->DriverList = pLDList;
  323. // Generate file copy lists
  324. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  325. {
  326. // Now add the other files into the list
  327. if (SetupFindFirstLine(hInf,pLD->szDevNameKey,NULL,&InfContext))
  328. {
  329. do
  330. {
  331. SetupGetStringField(&InfContext,0,szIdFile,tsizeof(szIdFile),NULL);
  332. AddFileToCopyList(pLI,pLD,szIdFile);
  333. } while (SetupFindNextLine(&InfContext,&InfContext));
  334. }
  335. }
  336. // Generate the SourceDiskList iff we find a section that lists them
  337. if (SetupFindFirstLine(hInf,TEXT("Source Media Descriptions"),NULL,&InfContext))
  338. {
  339. MediaDescFieldId=1;
  340. }
  341. else if (SetupFindFirstLine(hInf,TEXT("disks"),NULL,&InfContext)) // Old style
  342. {
  343. MediaDescFieldId=2;
  344. }
  345. else if (SetupFindFirstLine(hInf,TEXT("disks"),NULL,&InfContext)) // Old style
  346. {
  347. MediaDescFieldId=2;
  348. }
  349. else
  350. {
  351. MediaDescFieldId=0;
  352. }
  353. if (MediaDescFieldId)
  354. {
  355. do
  356. {
  357. SOURCEDISK *pSD;
  358. TCHAR szDiskId[8];
  359. pSD = (SOURCEDISK *)LocalAlloc(LPTR, sizeof(SOURCEDISK));
  360. if (!pSD)
  361. {
  362. dlogt(szLocalAllocFailMsg);
  363. break;
  364. }
  365. // Read the disk ID and description
  366. SetupGetIntField(&InfContext,0,&pSD->DiskId);
  367. SetupGetStringField(&InfContext,MediaDescFieldId,pSD->szDiskName,tsizeof(pSD->szDiskName),NULL);
  368. // Put it in the list
  369. pSD->pNext = pLI->SourceDiskList;
  370. pLI->SourceDiskList = pSD;
  371. } while (SetupFindNextLine(&InfContext,&InfContext));
  372. }
  373. SetupCloseInfFile(hInf);
  374. return pLI;
  375. }
  376. // Build a list containing information about all the legacy infs in the specified directory
  377. PROCESS_INF_INFO *BuildLegacyInfInfo(PTSTR szLegacyInfDir, BOOL bEnumSingleInf)
  378. {
  379. LEGACY_INF *pLegacyInf;
  380. PROCESS_INF_INFO *pPII;
  381. TCHAR PathBuffer[_MAX_PATH];
  382. dlog1("ProcessLegacyInfDirectory processing directory %s\n",szLegacyInfDir);
  383. // Allocate a process inf info struct to hold params relating to the conversion process
  384. pPII = (PROCESS_INF_INFO *)LocalAlloc(LPTR, sizeof(PROCESS_INF_INFO));
  385. if (!pPII)
  386. {
  387. dlogt(szLocalAllocFailMsg);
  388. return NULL;
  389. }
  390. // Get a path to the windows inf directory
  391. if (!GetWindowsDirectory(pPII->szSysInfDir,tsizeof(pPII->szSysInfDir)))
  392. {
  393. DestroyLegacyInfInfo(pPII);
  394. return NULL;
  395. }
  396. catpath(pPII->szSysInfDir,TEXT("\\INF"));
  397. // Create a temp dir for the new infs under the windows inf directory
  398. _tcscpy(pPII->szNewInfDir,pPII->szSysInfDir);
  399. catpath(pPII->szNewInfDir,TEXT("\\MEDIAINF"));
  400. // If the directory exists, delete it
  401. RemoveDirectoryTree(pPII->szNewInfDir);
  402. // Now create it.
  403. CreateDirectory(pPII->szNewInfDir,NULL);
  404. // Init list to NULL
  405. pPII->LegInfList=NULL;
  406. if (bEnumSingleInf) // If bEnumSingleInf true, szLegacyInfDir points to a single file
  407. {
  408. // Grab the path to the directory and store it in pPII->szLegInfDir
  409. _tcscpy(PathBuffer,szLegacyInfDir);
  410. _tcscpy(pPII->szLegInfDir,StripPathName(PathBuffer));
  411. // Load all the information about the legacy inf
  412. pLegacyInf = CreateLegacyInf(szLegacyInfDir);
  413. // If no error, link it into the list
  414. if (pLegacyInf)
  415. {
  416. pLegacyInf->pNext = pPII->LegInfList;
  417. pPII->LegInfList = pLegacyInf;
  418. }
  419. }
  420. else // bEnumSingleInf false, szLegacyInfDir points to a directory
  421. {
  422. HANDLE FindHandle;
  423. WIN32_FIND_DATA FindData;
  424. PTSTR CurrentInfFile;
  425. // Save path to original infs
  426. _tcscpy(pPII->szLegInfDir,szLegacyInfDir);
  427. // Build a file spec to find all INFs in specified directory, i.e., "<DirPath>\*.INF"
  428. _tcscpy(PathBuffer, szLegacyInfDir);
  429. catpath(PathBuffer,TEXT("\\*.INF"));
  430. // Get a pointer to the end of the path part of the string
  431. // (minus the wildcard filename), so that we can append
  432. // each filename to it.
  433. CurrentInfFile = _tcsrchr(PathBuffer, TEXT('\\')) + 1;
  434. // Search for all the inf files in this directory
  435. FindHandle = FindFirstFile(PathBuffer, &FindData);
  436. if (FindHandle != INVALID_HANDLE_VALUE)
  437. {
  438. do
  439. {
  440. // Build the full pathname.
  441. _tcscpy(CurrentInfFile, FindData.cFileName);
  442. // Load all the information about the legacy inf
  443. pLegacyInf = CreateLegacyInf(PathBuffer);
  444. // If no error, link it into the list
  445. if (pLegacyInf)
  446. {
  447. pLegacyInf->pNext = pPII->LegInfList;
  448. pPII->LegInfList = pLegacyInf;
  449. }
  450. } while (FindNextFile(FindHandle, &FindData));
  451. // Remember to close the find handle
  452. FindClose(FindHandle);
  453. }
  454. }
  455. // If we didn't find any drivers, just return NULL.
  456. if (pPII->LegInfList==NULL)
  457. {
  458. DestroyLegacyInfInfo(pPII);
  459. return NULL;
  460. }
  461. return pPII;
  462. }
  463. // Create a unique inf file in the temp directory
  464. // Files will have the name INFxxxx.INF, where xxxx is a value between 0 and 1000
  465. HANDLE OpenUniqueInfFile(PTSTR szDir, PTSTR szNewPath)
  466. {
  467. HANDLE hInf;
  468. int Id;
  469. // Try up to 1000 values before giving up
  470. for (Id=0;Id<1000;Id++)
  471. {
  472. wsprintf(szNewPath,TEXT("%s\\INF%d.inf"),szDir,Id);
  473. // Setting CREATE_NEW flag will make call fail if file already exists
  474. hInf = CreateFile( szNewPath,
  475. GENERIC_WRITE|GENERIC_READ,
  476. 0,
  477. NULL,
  478. CREATE_NEW,
  479. FILE_ATTRIBUTE_NORMAL,
  480. 0);
  481. // If we got back a valid handle, we can return
  482. if (hInf!=INVALID_HANDLE_VALUE)
  483. {
  484. return hInf;
  485. }
  486. }
  487. // Never found a valid handle. Give up.
  488. dlog("OpenUniqueInfFile: Couldn't create unique inf\n");
  489. return INVALID_HANDLE_VALUE;
  490. }
  491. // Helper function to append one formatted line of text to an open inf
  492. void cdecl InfPrintf(HANDLE hInf, LPTSTR szFormat, ...)
  493. {
  494. TCHAR Buf[MAXSTRINGLEN];
  495. int nChars;
  496. // format into buffer
  497. va_list va;
  498. va_start (va, szFormat);
  499. nChars = wvsprintf (Buf,szFormat,va);
  500. va_end (va);
  501. // Append cr-lf
  502. _tcscpy(&Buf[nChars],TEXT("\r\n"));
  503. nChars+=2;
  504. #ifdef UNICODE
  505. {
  506. int mbCount;
  507. char mbBuf[MAXSTRINGLEN];
  508. // Need to converto to mbcs before writing to file
  509. mbCount = WideCharToMultiByte( GetACP(), // code page
  510. WC_NO_BEST_FIT_CHARS, // performance and mapping flags
  511. Buf, // address of wide-character string
  512. nChars, // number of characters in string
  513. mbBuf, // address of buffer for new string
  514. sizeof(mbBuf), // size of buffer
  515. NULL, // address of default for unmappable characters
  516. NULL // address of flag set when default char. used
  517. );
  518. // Write line out to file
  519. WriteFile(hInf,mbBuf,mbCount,&mbCount,NULL);
  520. }
  521. #else
  522. WriteFile(hInf,Buf,nChars,&nChars,NULL);
  523. #endif
  524. return;
  525. }
  526. // Creates a new NT5-style inf file in the temporary directory.
  527. BOOL CreateNewInfFile(PROCESS_INF_INFO *pPII, LEGACY_INF *pLI)
  528. {
  529. SOURCEDISK *pSD;
  530. TCHAR szTmpKey[_MAX_PATH];
  531. LEGACY_DRIVER *pLDList, *pLD;
  532. HANDLE hInf;
  533. FILETOCOPY *pFTC;
  534. // Get a pointer to the legacy driver list
  535. pLDList = pLI->DriverList;
  536. dlog1("Creating new inf file %s\n",pPII->szNewInfDir);
  537. hInf = OpenUniqueInfFile(pPII->szNewInfDir, pLI->szNewInfPath);
  538. if (hInf==INVALID_HANDLE_VALUE)
  539. {
  540. return FALSE;
  541. }
  542. // Write out version section
  543. InfPrintf(hInf,TEXT("[version]"));
  544. InfPrintf(hInf,TEXT("Signature=\"$WINDOWS NT$\""));
  545. InfPrintf(hInf,TEXT("Class=MEDIA"));
  546. InfPrintf(hInf,TEXT("ClassGUID=\"{4d36e96c-e325-11ce-bfc1-08002be10318}\""));
  547. InfPrintf(hInf,TEXT("Provider=Unknown"));
  548. // Write out Manufacturer section
  549. InfPrintf(hInf,TEXT("[Manufacturer]"));
  550. InfPrintf(hInf,TEXT("Unknown=OldDrvs"));
  551. // Write out OldDrvs section
  552. InfPrintf(hInf,TEXT("[OldDrvs]"));
  553. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  554. {
  555. // Create an key to index into the strings section
  556. // This gives us something like:
  557. // %foo% = foo
  558. InfPrintf(hInf,TEXT("%%%s%%=%s"),pLD->szDevNameKey,pLD->szDevNameKey);
  559. }
  560. // Write out install section for each device
  561. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  562. {
  563. // install section header, remember NT only
  564. InfPrintf(hInf,TEXT("[%s.NT]"),pLD->szDevNameKey);
  565. // DriverVer entry. Pick a date that's earlier than any NT5 infs
  566. InfPrintf(hInf,TEXT("DriverVer = 1/1/1998, 4.0.0.0"));
  567. // Addreg entry
  568. InfPrintf(hInf,TEXT("AddReg=%s.AddReg"),pLD->szDevNameKey);
  569. // CopyFiles entry
  570. InfPrintf(hInf,TEXT("CopyFiles=%s.CopyFiles.User,%s.CopyFiles.Kern"),pLD->szDevNameKey,pLD->szDevNameKey);
  571. // Reboot entry. Legacy drivers always require a reboot
  572. InfPrintf(hInf,TEXT("Reboot"));
  573. }
  574. // Write out the services section for each device
  575. // Legacy drivers have a stub services key
  576. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  577. {
  578. InfPrintf(hInf,TEXT("[%s.NT.Services]"),pLD->szDevNameKey);
  579. #if GUESS_LEGACY_SERVICE_NAME
  580. // If we install a .sys file, assume that the service name is the same as the filename
  581. pFTC=pLD->KernCopyList;
  582. if (pFTC)
  583. {
  584. TCHAR szServiceName[_MAX_FNAME];
  585. lsplitpath(pFTC->szFileName,NULL,NULL,szServiceName,NULL);
  586. InfPrintf(hInf,TEXT("AddService=%s,0x2,%s_Service_Inst"),szServiceName,szServiceName);
  587. InfPrintf(hInf,TEXT("[%s_Service_Inst]"),szServiceName);
  588. InfPrintf(hInf,TEXT("DisplayName = %%%s%%"),pLD->szDevNameKey);
  589. InfPrintf(hInf,TEXT("ServiceType = 1"));
  590. InfPrintf(hInf,TEXT("StartType = 1"));
  591. InfPrintf(hInf,TEXT("ErrorControl = 1"));
  592. InfPrintf(hInf,TEXT("ServiceBinary = %%12%%\\%s"),pFTC->szFileName);
  593. InfPrintf(hInf,TEXT("LoadOrderGroup = Base"));
  594. }
  595. else
  596. {
  597. InfPrintf(hInf,TEXT("AddService=,0x2"));
  598. }
  599. #else
  600. InfPrintf(hInf,TEXT("AddService=,0x2"));
  601. #endif
  602. }
  603. // Write out the AddReg section for each device
  604. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  605. {
  606. int nClasses;
  607. TCHAR szClasses[_MAX_PATH];
  608. TCHAR *pszState, *pszClass;
  609. // section header
  610. InfPrintf(hInf,TEXT("[%s.AddReg]"),pLD->szDevNameKey);
  611. InfPrintf(hInf,TEXT("HKR,Drivers,SubClasses,,\"%s\""),pLD->szClasses);
  612. // For safety, copy the string (mystrtok corrupts the original source string)
  613. _tcscpy(szClasses,pLD->szClasses);
  614. for (
  615. pszClass = mystrtok(szClasses,NULL,&pszState);
  616. pszClass;
  617. pszClass = mystrtok(NULL,NULL,&pszState)
  618. )
  619. {
  620. InfPrintf(hInf,TEXT("HKR,\"Drivers\\%s\\%s\", Driver,,%s"), pszClass,pLD->szUserDevDrv,pLD->szUserDevDrv);
  621. InfPrintf(hInf,TEXT("HKR,\"Drivers\\%s\\%s\", Description,,%%%s%%"),pszClass,pLD->szUserDevDrv,pLD->szDevNameKey);
  622. }
  623. }
  624. // Write out the CopyFiles section for each device for user files
  625. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  626. {
  627. // section header
  628. InfPrintf(hInf,TEXT("[%s.CopyFiles.User]"),pLD->szDevNameKey);
  629. for (pFTC=pLD->UserCopyList;pFTC;pFTC=pFTC->pNext)
  630. {
  631. InfPrintf(hInf,TEXT("%s"),pFTC->szFileName);
  632. }
  633. }
  634. // Write out the CopyFiles section for each device for kern files
  635. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  636. {
  637. // section header
  638. InfPrintf(hInf,TEXT("[%s.CopyFiles.Kern]"),pLD->szDevNameKey);
  639. for (pFTC=pLD->KernCopyList;pFTC;pFTC=pFTC->pNext)
  640. {
  641. InfPrintf(hInf,TEXT("%s"),pFTC->szFileName);
  642. }
  643. }
  644. // Write out DestinationDirs section
  645. InfPrintf(hInf,TEXT("[DestinationDirs]"));
  646. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  647. {
  648. InfPrintf(hInf,TEXT("%s.CopyFiles.User = 11"),pLD->szDevNameKey);
  649. InfPrintf(hInf,TEXT("%s.CopyFiles.Kern = 12"),pLD->szDevNameKey);
  650. }
  651. // Write out the SourceDisksNames section
  652. InfPrintf(hInf,TEXT("[SourceDisksNames]"));
  653. for (pSD=pLI->SourceDiskList;pSD;pSD=pSD->pNext)
  654. {
  655. InfPrintf(hInf,TEXT("%d = \"%s\",\"\",1"),pSD->DiskId,pSD->szDiskName);
  656. }
  657. // Write out the SourceDisksFiles section
  658. InfPrintf(hInf,TEXT("[SourceDisksFiles]"));
  659. for (pFTC=pLI->FileList;pFTC;pFTC=pFTC->pNext)
  660. {
  661. InfPrintf(hInf,TEXT("%s=%d"),pFTC->szFileName,pFTC->DiskId);
  662. }
  663. // Write out Strings section
  664. InfPrintf(hInf,TEXT("[Strings]"));
  665. for (pLD=pLDList;pLD;pLD=pLD->pNext)
  666. {
  667. // Create the device description
  668. InfPrintf(hInf,TEXT("%s=\"%s\""),pLD->szDevNameKey,pLD->szDesc);
  669. }
  670. CloseHandle(hInf);
  671. return TRUE;
  672. }
  673. // Creates a PNF file in the temporary directory to go along with the inf
  674. // This allows us to have the inf file in one directory while the driver's
  675. // files are in a different directory.
  676. BOOL CreateNewPnfFile(PROCESS_INF_INFO *pPII, LEGACY_INF *pLI)
  677. {
  678. BOOL bSuccess;
  679. TCHAR szSysInfPath[_MAX_PATH];
  680. TCHAR szSysPnfPath[_MAX_PATH];
  681. TCHAR szTmpPnfPath[_MAX_PATH];
  682. TCHAR szSysInfDrive[_MAX_DRIVE];
  683. TCHAR szSysInfDir[_MAX_DIR];
  684. TCHAR szSysInfFile[_MAX_FNAME];
  685. TCHAR szNewInfDrive[_MAX_DRIVE];
  686. TCHAR szNewInfDir[_MAX_DIR];
  687. TCHAR szNewInfFile[_MAX_FNAME];
  688. // Copy inf to inf directory to create pnf file
  689. bSuccess = SetupCopyOEMInf(
  690. pLI->szNewInfPath, // IN PCSTR SourceInfFileName,
  691. pPII->szLegInfDir, // IN PCSTR OEMSourceMediaLocation, OPTIONAL
  692. SPOST_PATH, // IN DWORD OEMSourceMediaType,
  693. 0, // IN DWORD CopyStyle,
  694. szSysInfPath, // OUT PSTR DestinationInfFileName, OPTIONAL
  695. tsizeof(szSysInfPath), // IN DWORD DestinationInfFileNameSize,
  696. NULL, // OUT PDWORD RequiredSize, OPTIONAL
  697. NULL // OUT PSTR *DestinationInfFileNameComponent OPTIONAL
  698. );
  699. if (!bSuccess)
  700. {
  701. dlog1("CreateNewPnfFile: SetupCopyOEMInf failed for inf %s\n",pLI->szNewInfPath);
  702. return FALSE;
  703. }
  704. // Cut apart the directory names
  705. lsplitpath(szSysInfPath, szSysInfDrive, szSysInfDir, szSysInfFile, NULL);
  706. lsplitpath(pLI->szNewInfPath, szNewInfDrive, szNewInfDir, szNewInfFile, NULL);
  707. // Copy the pnf file back to the original directory
  708. wsprintf(szSysPnfPath,TEXT("%s%s%s.pnf"), szSysInfDrive, szSysInfDir, szSysInfFile);
  709. wsprintf(szTmpPnfPath,TEXT("%s%s%s.pnf"), szNewInfDrive, szNewInfDir, szNewInfFile);
  710. CopyFile(szSysPnfPath, szTmpPnfPath, FALSE);
  711. // Delete the inf and pnf file in the system inf directory
  712. DeleteFile(szSysInfPath);
  713. DeleteFile(szSysPnfPath);
  714. return TRUE;
  715. }
  716. // Create a new inf file for each legacy inf in the list
  717. BOOL ProcessLegacyInfInfo(PROCESS_INF_INFO *pPII)
  718. {
  719. LEGACY_INF *pLI;
  720. BOOL bSuccess;
  721. for (pLI=pPII->LegInfList;pLI;pLI=pLI->pNext)
  722. {
  723. bSuccess = CreateNewInfFile(pPII,pLI);
  724. if (bSuccess)
  725. {
  726. CreateNewPnfFile(pPII,pLI);
  727. }
  728. }
  729. return TRUE;
  730. }
  731. BOOL ConvertLegacyInfDir(PTSTR szLegacyDir, PTSTR szNewDir, BOOL bEnumSingleInf)
  732. {
  733. PROCESS_INF_INFO *pPII;
  734. // Couldn't find any NT5-style drivers. Try to find some legacy inf files.
  735. // Build the list
  736. pPII = BuildLegacyInfInfo(szLegacyDir, bEnumSingleInf);
  737. if (!pPII)
  738. {
  739. return FALSE;
  740. }
  741. // Process the list
  742. ProcessLegacyInfInfo(pPII);
  743. if (bEnumSingleInf)
  744. {
  745. // if bEnumSingleInf is true, we should return a path to the new inf
  746. // (there should be exactly one)
  747. _tcscpy(szNewDir,pPII->LegInfList->szNewInfPath);
  748. }
  749. else
  750. {
  751. // if bEnumSingleInf is false, we should return a path to the directory
  752. _tcscpy(szNewDir,pPII->szNewInfDir);
  753. }
  754. // Cleanup data structures
  755. DestroyLegacyInfInfo(pPII);
  756. return TRUE;
  757. }
  758. int CountDriverInfoList(IN HDEVINFO DeviceInfoSet,
  759. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
  760. IN DWORD DriverType
  761. )
  762. {
  763. SP_DRVINFO_DATA DriverInfoData;
  764. SP_DRVINSTALL_PARAMS DriverInstallParams;
  765. int DriverCount = 0;
  766. int Count = 0;
  767. // Count the number of drivers in the list
  768. DriverInfoData.cbSize = sizeof(DriverInfoData);
  769. while (SetupDiEnumDriverInfo(DeviceInfoSet,
  770. DeviceInfoData,
  771. DriverType,
  772. Count,
  773. &DriverInfoData))
  774. {
  775. // Only count drivers which don't have the DNF_BAD_DRIVER flag set
  776. DriverInstallParams.cbSize=sizeof(DriverInstallParams);
  777. if (SetupDiGetDriverInstallParams(DeviceInfoSet, DeviceInfoData, &DriverInfoData, &DriverInstallParams))
  778. {
  779. if (!(DriverInstallParams.Flags & DNF_BAD_DRIVER))
  780. {
  781. DriverCount++;
  782. }
  783. }
  784. Count++;
  785. }
  786. return DriverCount;
  787. }
  788. // Called to display a list of drivers to be installed
  789. DWORD Media_SelectDevice(IN HDEVINFO DeviceInfoSet,
  790. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  791. )
  792. {
  793. BOOL bResult;
  794. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  795. int DriverCount;
  796. // Undocumented: When user selects "Have Disk", setupapi only looks at the
  797. // class driver list. Therefore, we'll only work with that list
  798. DWORD DriverType = SPDIT_CLASSDRIVER;
  799. // Get the path to where the inf files are located
  800. DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
  801. bResult = SetupDiGetDeviceInstallParams(DeviceInfoSet,
  802. DeviceInfoData,
  803. &DeviceInstallParams);
  804. if (!bResult)
  805. {
  806. return ERROR_DI_DO_DEFAULT;
  807. }
  808. // For safety, don't support append mode
  809. if (DeviceInstallParams.FlagsEx & DI_FLAGSEX_APPENDDRIVERLIST)
  810. {
  811. return ERROR_DI_DO_DEFAULT;
  812. }
  813. // If not going outside of inf directory, the DriverPath field will be an
  814. // empty string. In this case, don't do special processing.
  815. if (DeviceInstallParams.DriverPath[0]=='\0')
  816. {
  817. return ERROR_DI_DO_DEFAULT;
  818. }
  819. // We're going off to an OEM directory.
  820. // See if setup can find any NT5-compatible inf files
  821. // Try to build a driver info list in the current directory
  822. if (DeviceInfoSet) SetupDiDestroyDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType);
  823. SetupDiBuildDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType);
  824. // Filter out non NT inf files (e.g. Win9x inf files)
  825. if (DeviceInfoSet)
  826. FilterOutNonNTInfs(DeviceInfoSet,DeviceInfoData,DriverType);
  827. // Now count the number of drivers
  828. DriverCount = CountDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType);
  829. // If we found at least one NT5 driver for this device, just return
  830. if (DriverCount>0)
  831. {
  832. return ERROR_DI_DO_DEFAULT;
  833. }
  834. // Didn't find any NT5 drivers.
  835. // Destroy the existing list
  836. SetupDiDestroyDriverInfoList(DeviceInfoSet,DeviceInfoData,DriverType);
  837. //Retrieve the device install params prior to setting new INF path and update
  838. //any information DeviceInstallParams
  839. bResult = SetupDiGetDeviceInstallParams(DeviceInfoSet,
  840. DeviceInfoData,
  841. &DeviceInstallParams);
  842. if (!bResult)
  843. {
  844. return ERROR_DI_DO_DEFAULT;
  845. }
  846. // Convert any legacy infs and get back ptr to temp directory for converted infs
  847. bResult = ConvertLegacyInfDir(DeviceInstallParams.DriverPath, DeviceInstallParams.DriverPath, (DeviceInstallParams.Flags & DI_ENUMSINGLEINF));
  848. if (!bResult)
  849. {
  850. return ERROR_DI_DO_DEFAULT; // Didn't find any legacy infs
  851. }
  852. //Clean up this DI_FLAGSEX_FILTERSIMILARDRIVERS for old NT 4 driver installation.
  853. DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_FILTERSIMILARDRIVERS;
  854. // Save new driver path
  855. bResult = SetupDiSetDeviceInstallParams(DeviceInfoSet,
  856. DeviceInfoData,
  857. &DeviceInstallParams);
  858. // Note: We don't have to call SetupDiBuildDriverInfoList; setupapi will do that for us
  859. // with the new path to the infs.
  860. return ERROR_DI_DO_DEFAULT;
  861. }
  862. BOOL CreateRootDevice( IN HDEVINFO DeviceInfoSet,
  863. IN PTSTR DeviceId,
  864. IN BOOL bInstallNow
  865. )
  866. {
  867. BOOL bResult;
  868. SP_DEVINFO_DATA DeviceInfoData;
  869. SP_DRVINFO_DATA DriverInfoData;
  870. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  871. TCHAR tmpBuffer[100];
  872. DWORD bufferLen;
  873. DWORD Error;
  874. // Attempt to manufacture a new device information element for the root enumerated device
  875. _tcscpy(tmpBuffer,TEXT("ROOT\\MEDIA\\"));
  876. _tcscat(tmpBuffer,DeviceId);
  877. dlog2("CreateRootDevice: DeviceId = %s, Device = %s%",DeviceId,tmpBuffer);
  878. // Try to create the device info
  879. DeviceInfoData.cbSize = sizeof( DeviceInfoData );
  880. bResult = SetupDiCreateDeviceInfo( DeviceInfoSet,
  881. tmpBuffer,
  882. (GUID *) &GUID_DEVCLASS_MEDIA,
  883. NULL, // PCTSTR DeviceDescription
  884. NULL, // HWND hwndParent
  885. 0,
  886. &DeviceInfoData );
  887. if (!bResult)
  888. {
  889. Error = GetLastError();
  890. dlog1("CreateRootDevice: SetupDiCreateDeviceInfo failed Error=%x",Error);
  891. return (Error == ERROR_DEVINST_ALREADY_EXISTS);
  892. }
  893. // Set the hardware ID.
  894. _tcscpy(tmpBuffer, DeviceId);
  895. bufferLen = _tcslen(tmpBuffer); // Get buffer len in chars
  896. tmpBuffer[bufferLen+1] = TEXT('\0'); // must terminate with an extra null (so we have two nulls)
  897. bufferLen = (bufferLen + 2) * sizeof(TCHAR); // Convert buffer length to bytes & add extra for two nulls
  898. bResult = SetupDiSetDeviceRegistryProperty( DeviceInfoSet,
  899. &DeviceInfoData,
  900. SPDRP_HARDWAREID,
  901. (PBYTE)tmpBuffer,
  902. bufferLen );
  903. if (!bResult) goto CreateRootDevice_err;
  904. // Setup some flags before building a driver list
  905. bResult = SetupDiGetDeviceInstallParams( DeviceInfoSet,&DeviceInfoData,&DeviceInstallParams);
  906. if (bResult)
  907. {
  908. _tcscpy( DeviceInstallParams.DriverPath, TEXT( "" ) );
  909. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_USECLASSFORCOMPAT;
  910. bResult = SetupDiSetDeviceInstallParams( DeviceInfoSet,&DeviceInfoData,&DeviceInstallParams);
  911. }
  912. // Build a compatible driver list for this new device...
  913. bResult = SetupDiBuildDriverInfoList( DeviceInfoSet,
  914. &DeviceInfoData,
  915. SPDIT_COMPATDRIVER);
  916. if (!bResult) goto CreateRootDevice_err;
  917. // Get the first driver on the list
  918. DriverInfoData.cbSize = sizeof (DriverInfoData);
  919. bResult = SetupDiEnumDriverInfo( DeviceInfoSet,
  920. &DeviceInfoData,
  921. SPDIT_COMPATDRIVER,
  922. 0,
  923. &DriverInfoData);
  924. if (!bResult) goto CreateRootDevice_err;
  925. // Save the device description
  926. bResult = SetupDiSetDeviceRegistryProperty( DeviceInfoSet,
  927. &DeviceInfoData,
  928. SPDRP_DEVICEDESC,
  929. (PBYTE) DriverInfoData.Description,
  930. (_tcslen( DriverInfoData.Description ) + 1) * sizeof( TCHAR ) );
  931. if (!bResult) goto CreateRootDevice_err;
  932. // Set the selected driver
  933. bResult = SetupDiSetSelectedDriver( DeviceInfoSet,
  934. &DeviceInfoData,
  935. &DriverInfoData);
  936. if (!bResult) goto CreateRootDevice_err;
  937. // Register the device so it is not a phantom anymore
  938. bResult = SetupDiRegisterDeviceInfo( DeviceInfoSet,
  939. &DeviceInfoData,
  940. 0,
  941. NULL,
  942. NULL,
  943. NULL);
  944. if (!bResult) goto CreateRootDevice_err;
  945. return bResult;
  946. // Error, delete the device info and give up
  947. CreateRootDevice_err:
  948. SetupDiDeleteDeviceInfo (DeviceInfoSet, &DeviceInfoData);
  949. return FALSE;
  950. }
  951. DWORD Media_MigrateLegacy(IN HDEVINFO DeviceInfoSet,
  952. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  953. )
  954. {
  955. BOOL bInstallNow = TRUE;
  956. CreateRootDevice(DeviceInfoSet, TEXT("MS_MMMCI"), bInstallNow);
  957. CreateRootDevice(DeviceInfoSet, TEXT("MS_MMVID"), bInstallNow);
  958. CreateRootDevice(DeviceInfoSet, TEXT("MS_MMACM"), bInstallNow);
  959. CreateRootDevice(DeviceInfoSet, TEXT("MS_MMVCD"), bInstallNow);
  960. CreateRootDevice(DeviceInfoSet, TEXT("MS_MMDRV"), bInstallNow);
  961. return NO_ERROR;
  962. }
  963. int IsSpecialDriver(HDEVINFO DeviceInfoSet,
  964. PSP_DEVINFO_DATA DeviceInfoData)
  965. {
  966. BOOL bResult;
  967. TCHAR HardwareId[32];
  968. bResult = SetupDiGetDeviceRegistryProperty( DeviceInfoSet,
  969. DeviceInfoData,
  970. SPDRP_HARDWAREID,
  971. NULL,
  972. (PBYTE)HardwareId,
  973. sizeof(HardwareId),
  974. NULL );
  975. if (!_tcscmp(HardwareId,TEXT("MS_MMMCI")))
  976. return IS_MS_MMMCI;
  977. else if (!_tcscmp(HardwareId,TEXT("MS_MMVID")))
  978. return IS_MS_MMVID;
  979. else if (!_tcscmp(HardwareId,TEXT("MS_MMACM")))
  980. return IS_MS_MMACM;
  981. else if (!_tcscmp(HardwareId,TEXT("MS_MMVCD")))
  982. return IS_MS_MMVCD;
  983. else if (!_tcscmp(HardwareId,TEXT("MS_MMDRV")))
  984. return IS_MS_MMDRV;
  985. return 0;
  986. }
  987. BOOL IsPnPDriver(IN PTSTR szName)
  988. {
  989. LONG lRet;
  990. HKEY hkClass;
  991. int iDriverInst;
  992. TCHAR szDriverInst[32];
  993. HKEY hkDriverInst;
  994. int iDriverType;
  995. TCHAR szDriverType[32];
  996. HKEY hkDriverType;
  997. int iDriverName;
  998. TCHAR szDriverName[32];
  999. // Open class key
  1000. hkClass = SetupDiOpenClassRegKey((GUID *) &GUID_DEVCLASS_MEDIA, KEY_READ);
  1001. if (hkClass == INVALID_HANDLE_VALUE)
  1002. {
  1003. return FALSE;
  1004. }
  1005. // enumerate each driver instances (e.g. 0000, 0001, etc.)
  1006. for (iDriverInst = 0;
  1007. !RegEnumKey(hkClass, iDriverInst, szDriverInst, sizeof(szDriverInst)/sizeof(TCHAR));
  1008. iDriverInst++)
  1009. {
  1010. // Open the Drivers subkey, (e.g. 0000\Drivers)
  1011. if (lstrlen(szDriverInst) > 23) // 23 is the max length minus "\Drivers" plus a NULL
  1012. {
  1013. continue;
  1014. }
  1015. _tcscat(szDriverInst,TEXT("\\Drivers"));
  1016. lRet = RegOpenKey(hkClass, szDriverInst, &hkDriverInst);
  1017. if (lRet!=ERROR_SUCCESS)
  1018. {
  1019. continue;
  1020. }
  1021. // Enumerate each of the driver types (e.g. wave, midi, mixer, etc.)
  1022. for (iDriverType = 0;
  1023. !RegEnumKey(hkDriverInst, iDriverType, szDriverType, sizeof(szDriverType)/sizeof(TCHAR));
  1024. iDriverType++)
  1025. {
  1026. // Open the driver type subkey
  1027. lRet = RegOpenKey(hkDriverInst, szDriverType, &hkDriverType);
  1028. if (lRet!=ERROR_SUCCESS)
  1029. {
  1030. continue;
  1031. }
  1032. // Enumerate each of the driver names (e.g. foo.drv)
  1033. for (iDriverName = 0;
  1034. !RegEnumKey(hkDriverType, iDriverName, szDriverName, sizeof(szDriverName)/sizeof(TCHAR));
  1035. iDriverName++)
  1036. {
  1037. // Does this name match the one we were passed?
  1038. if (!_tcsicmp(szName,szDriverName))
  1039. {
  1040. RegCloseKey(hkDriverType);
  1041. RegCloseKey(hkDriverInst);
  1042. RegCloseKey(hkClass);
  1043. return TRUE;
  1044. }
  1045. }
  1046. RegCloseKey(hkDriverType);
  1047. }
  1048. RegCloseKey(hkDriverInst);
  1049. }
  1050. RegCloseKey(hkClass);
  1051. return FALSE;
  1052. }