/*****************************************************************************\ * MODULE: geninf.c * * The module contains routines for generating a setup INF file. * * * Needed Work * ----------- * 1) look at reducing the item-list size to contiguous buffers. * * * Copyright (C) 1996-1997 Microsoft Corporation * Copyright (C) 1996-1997 Hewlett Packard * * History: * 22-Nov-1996 HWP-Guys Created. * \*****************************************************************************/ #include "pch.h" /****************************************************************************** ** Defines ******************************************************************************/ /****************************************************************************** ** Define - INF_CAT_INCREMENT ** Description - The increment in size between cat file increments ******************************************************************************/ #if (!defined(INF_CAT_INCREMENT)) #define INF_CAT_INCREMENT 16 #endif /*****************************************************************************\ * inf_NextStr (Local Routine) * * Proceeds to the next string in a section-list. * \*****************************************************************************/ _inline LPTSTR inf_NextStr( LPTSTR lpszStr) { return (lpszStr + (lstrlen(lpszStr) + 1)); } /*****************************************************************************\ * inf_WriteInfSct (Local Routine) * * Writes a section to the 9x-generated-inf-file. * \*****************************************************************************/ _inline BOOL inf_WriteInfSct( HANDLE hFile, LPCSTR lpszSct) { DWORD cbWr; return WriteFile(hFile, (LPBYTE)lpszSct, lstrlenA(lpszSct), &cbWr, NULL); } /*****************************************************************************\ * inf_GetInfMfgKey (Local Routine) * * Returns the first word of the drvname which is used to denote mfg-section. * \*****************************************************************************/ LPSTR inf_GetInfMfgKey( LPCTSTR lpszDrvName) { LPTSTR lpszTmp; LPSTR lpszMfg = NULL; if (lpszTmp = genFindChar((LPTSTR)lpszDrvName, TEXT(' '))) { *lpszTmp = TEXT('\0'); lpszMfg = genMBFromTC(lpszDrvName); *lpszTmp = TEXT(' '); } else { lpszMfg = genMBFromTC(lpszDrvName); } return lpszMfg; } /*****************************************************************************\ * inf_WriteInfMfg (Local Routine) * * Writes the manufacturer section. * \*****************************************************************************/ _inline BOOL inf_WriteInfMfg( HANDLE hFile, LPCTSTR lpszDrvName) { DWORD cbWr; LPSTR lpszMfg; LPSTR lpszBuf; DWORD cbSize; DWORD cch; BOOL bRet = FALSE; if (lpszMfg = inf_GetInfMfgKey(lpszDrvName)) { cbSize = lstrlenA(g_szInfSctMfg) + lstrlenA(lpszMfg) + 1; if (lpszBuf = (LPSTR)genGAlloc(cbSize)) { cch = wsprintfA(lpszBuf, g_szInfSctMfg, lpszMfg); bRet = WriteFile(hFile, lpszBuf, cch, &cbWr, NULL); genGFree(lpszBuf, cbSize); } genGFree(lpszMfg, genGSize(lpszMfg)); } return bRet; } /*****************************************************************************\ * inf_WriteInfDrv (Local Routine) * * Writes the driver-section. * \*****************************************************************************/ _inline BOOL inf_WriteInfDrv( HANDLE hFile, LPCTSTR lpszDrvName, LPCTSTR lpszDrvPath) { DWORD cbWr; LPTSTR lpszTmp; LPSTR lpszName; LPSTR lpszFile; LPSTR lpszMfg; LPSTR lpszBuf; DWORD cbSize; DWORD cch; BOOL bRet = FALSE; if (lpszMfg = inf_GetInfMfgKey(lpszDrvName)) { if (lpszTmp = genFindRChar((LPTSTR)lpszDrvPath, TEXT('\\'))) { if (lpszFile = genMBFromTC(++lpszTmp)) { if (lpszName = genMBFromTC(lpszDrvName)) { cbSize = lstrlenA(g_szInfSctDrv) + lstrlenA(lpszName) + lstrlenA(lpszFile) + lstrlenA(lpszMfg) + 1; if (lpszBuf = (LPSTR)genGAlloc(cbSize)) { cch = wsprintfA(lpszBuf, g_szInfSctDrv, lpszMfg, lpszName, lpszFile); bRet = WriteFile(hFile, lpszBuf, cch, &cbWr, NULL); genGFree(lpszBuf, cbSize); } genGFree(lpszName, genGSize(lpszName)); } genGFree(lpszFile, genGSize(lpszFile)); } } genGFree(lpszMfg, genGSize(lpszMfg)); } return bRet; } /*****************************************************************************\ * inf_WriteInfIns (Local Routine) * * Writes the install-section. * \*****************************************************************************/ _inline BOOL inf_WriteInfIns( HANDLE hFile, LPCTSTR lpszDrvPath) { DWORD cbWr; LPTSTR lpszTmp; LPSTR lpszFile; LPSTR lpszBuf; DWORD cbSize; DWORD cch; BOOL bRet = FALSE; if (lpszTmp = genFindRChar((LPTSTR)lpszDrvPath, TEXT('\\'))) { if (lpszFile = genMBFromTC(++lpszTmp)) { cbSize = lstrlenA(g_szInfSctIns) + lstrlenA(lpszFile) + 1; if (lpszBuf = (LPSTR)genGAlloc(cbSize)) { cch = wsprintfA(lpszBuf, g_szInfSctIns, lpszFile); bRet = WriteFile(hFile, lpszBuf, cch, &cbWr, NULL); genGFree(lpszBuf, cbSize); } genGFree(lpszFile, genGSize(lpszFile)); } } return bRet; } /*****************************************************************************\ * inf_WrintInfDta (Local Routine) * * Writes the data-section. * \*****************************************************************************/ _inline BOOL inf_WriteInfDta( HANDLE hFile, LPTSTR lpszDtaFile, LPTSTR lpszHlpFile) { DWORD cbWr; LPTSTR lpszDta; LPTSTR lpszHlp; LPSTR lpszIns; LPSTR lpszDtaName; LPSTR lpszHlpName; DWORD cbSize; DWORD cch; BOOL bRet = FALSE; if (lpszDta = genFindRChar(lpszDtaFile, TEXT('\\'))) { if (lpszHlp = genFindRChar(lpszHlpFile, TEXT('\\'))) { if (lpszDtaName = genMBFromTC(++lpszDta)) { if (lpszHlpName = genMBFromTC(++lpszHlp)) { cbSize = lstrlenA(g_szInfSctIns) + lstrlenA(lpszDtaName) + lstrlenA(lpszHlpName) + 1; if (lpszIns = (LPSTR)genGAlloc(cbSize)) { cch = wsprintfA(lpszIns, g_szInfSctDta, lpszDtaName, lpszHlpName); bRet = WriteFile(hFile, lpszIns, cch, &cbWr, NULL); genGFree(lpszIns, genGSize(lpszIns)); } genGFree(lpszHlpName, genGSize(lpszHlpName)); } genGFree(lpszDtaName, genGSize(lpszDtaName)); } } } return bRet; } /*****************************************************************************\ * inf_WriteInfFiles (Local Routine) * * Writes the file-list section. * \*****************************************************************************/ BOOL inf_WriteInfFiles( HANDLE hFile, LPTSTR lpaszFiles) { LPTSTR lpszPtr; LPTSTR lpszFile; LPSTR lpszItm; DWORD cbWr; DWORD cch; CHAR szBuf[255]; BOOL bRet = FALSE; // Write out the CopyFiles Section. This will take the // dependent files list and alter it to delminate the // strings with commas. // if ((lpszPtr = lpaszFiles) && *lpszPtr) { WriteFile(hFile, g_szInfSctFil, lstrlenA(g_szInfSctFil), &cbWr, NULL); while (*lpszPtr) { if (lpszFile = genFindRChar(lpszPtr, TEXT('\\'))) { if (lpszItm = genMBFromTC(++lpszFile)) { cch = wsprintfA(szBuf, "%s\r\n", lpszItm); WriteFile(hFile, szBuf, cch, &cbWr, NULL); bRet = TRUE; genGFree(lpszItm, genGSize(lpszItm)); } } lpszPtr = inf_NextStr(lpszPtr); } } return bRet; } /*****************************************************************************\ * inf_WriteInfSDF (Local Routine) * * Writes the file-list section. * \*****************************************************************************/ BOOL inf_WriteInfSDF( HANDLE hFile, LPCTSTR lpaszFiles) { LPTSTR lpszPtr; LPTSTR lpszFile; LPSTR lpszItm; DWORD cbWr; DWORD cch; CHAR szBuf[255]; BOOL bRet = FALSE; // Write out the CopyFiles Section. This will take the // dependent files list and alter it to delminate the // strings with commas. // if ((lpszPtr = (LPTSTR)lpaszFiles) && *lpszPtr) { WriteFile(hFile, g_szInfSctSDF, lstrlenA(g_szInfSctSDF), &cbWr, NULL); while (*lpszPtr) { if (lpszFile = genFindRChar(lpszPtr, TEXT('\\'))) { if (lpszItm = genMBFromTC(++lpszFile)) { cch = wsprintfA(szBuf, "%hs = 1\r\n", lpszItm); WriteFile(hFile, szBuf, cch, &cbWr, NULL); bRet = TRUE; genGFree(lpszItm, genGSize(lpszItm)); } } lpszPtr = inf_NextStr(lpszPtr); } } return bRet; } /*****************************************************************************\ * inf_BuildW9XInf (Local Routine) * * \*****************************************************************************/ LPTSTR inf_BuildW9XInf( LPINFINFO lpInf, LPCTSTR lpszDrvName, LPDRIVER_INFO_3 lpdi3) { LPTSTR lpszInfFile; HANDLE hFile; LPTSTR lpszInfName = NULL; if (lpszInfFile = genBuildFileName(lpInf->lpszDstPath, lpInf->lpszDstName, g_szDotInf)) { hFile = CreateFile(lpszInfFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile && (hFile != INVALID_HANDLE_VALUE)) { inf_WriteInfSct(hFile, (LPCSTR)g_szInfSctVer); inf_WriteInfMfg(hFile, lpszDrvName); inf_WriteInfDrv(hFile, lpszDrvName, (LPCTSTR)lpdi3->pDriverPath); inf_WriteInfIns(hFile, (LPCTSTR)lpdi3->pDriverPath); inf_WriteInfDta(hFile, lpdi3->pDataFile, lpdi3->pHelpFile); inf_WriteInfSct(hFile, (LPSTR)g_szInfSctSDN); inf_WriteInfSDF(hFile, (LPCTSTR)lpdi3->pDependentFiles); inf_WriteInfFiles(hFile, lpdi3->pDependentFiles); inf_WriteInfSct(hFile, g_szInfSctStr); lpszInfName = lpszInfFile; CloseHandle(hFile); } else { infSetError(lpInf,GetLastError()); genGFree(lpszInfFile, genGSize(lpszInfFile)); } } return lpszInfName; } /*****************************************************************************\ * inf_GetW9XInfo (Local Routine) * * Retrieves the files (drivers) for a 9x client. This essentially takes the * files and calls a routine to build an INF that the client will use to * install the drivers. * \*****************************************************************************/ LPDRIVER_INFO_3 inf_GetW9XInfo( LPINFINFO lpInf, LPTSTR* ppszDrvName) { HANDLE hPrinter; DWORD cbBuf; DWORD cbNeed; LPDRIVER_INFO_1 lpdi1; LPDRIVER_INFO_3 lpdi3 = NULL; *ppszDrvName = NULL; if (OpenPrinter(lpInf->lpszFrnName, &hPrinter, NULL)) { // First let's see how big our buffer will need to // be in order to hold the printer-driver-name-information. // cbBuf = 0; GetPrinterDriver(hPrinter, (LPTSTR)g_szEnvW9X, 1, NULL, 0, &cbBuf); // Allocate storage for holding the driver-info structure. // if (cbBuf && (lpdi1 = (LPDRIVER_INFO_1)genGAlloc(cbBuf))) { if (GetPrinterDriver(hPrinter, (LPTSTR)g_szEnvW9X, 1, (LPBYTE)lpdi1, cbBuf, &cbNeed)) { // Get size to hold the printer-driver-files-information. // cbBuf = 0; GetPrinterDriver(hPrinter, (LPTSTR)g_szEnvW9X, 3, NULL, 0, &cbBuf); if (cbBuf && (lpdi3 = (LPDRIVER_INFO_3)genGAlloc(cbBuf))) { if (GetPrinterDriver(hPrinter, (LPTSTR)g_szEnvW9X, 3, (LPBYTE)lpdi3, cbBuf, &cbNeed)) { *ppszDrvName = genGAllocStr(lpdi1->pName); } else { genGFree(lpdi3, genGSize(lpdi3)); lpdi3 = NULL; } } } genGFree(lpdi1, genGSize(lpdi1)); } ClosePrinter(hPrinter); } if (lpdi3 == NULL) infSetError(lpInf,GetLastError()); return lpdi3; } /*****************************************************************************\ * inf_GetW9XInf (Local Routine) * * \*****************************************************************************/ LPTSTR inf_GetW9XInf( LPINFINFO lpInf) { LPDRIVER_INFO_3 lpdi3; LPTSTR lpszDrvName; LPTSTR lpszInfFile = NULL; if (lpdi3 = inf_GetW9XInfo(lpInf, &lpszDrvName)) { lpszInfFile = inf_BuildW9XInf(lpInf, lpszDrvName, lpdi3); genGFree(lpszDrvName, genGSize(lpszDrvName)); genGFree(lpdi3, genGSize(lpdi3)); } return lpszInfFile; } /*****************************************************************************\ * inf_GetIdx (Local Routine) * * Quick wrapper which returns the line in the INF file where the section/key * resides. * \*****************************************************************************/ _inline BOOL inf_GetIdx( LPCTSTR lpszSct, LPCTSTR lpszKey, HINF hInfObj, PINFCONTEXT pic) { return SetupFindFirstLine(hInfObj, lpszSct, lpszKey, pic); } /*****************************************************************************\ * inf_GetInfInfoFileName (Local Routine) * * Retreive the filename from the INF-INFO index. * \*****************************************************************************/ LPTSTR inf_GetInfInfoFileName( PSP_INF_INFORMATION pii, DWORD idx) { DWORD cbSize, dwBufferSize; LPTSTR lpszInfFile; if (SetupQueryInfFileInformation(pii, idx, NULL, 0, &cbSize)) { dwBufferSize = (cbSize + 1) * sizeof(TCHAR); if (lpszInfFile = (LPTSTR)genGAlloc(dwBufferSize)) { if (SetupQueryInfFileInformation(pii, idx, lpszInfFile, cbSize, NULL)) return lpszInfFile; genGFree(lpszInfFile, genGSize(lpszInfFile)); } } return NULL; } /*****************************************************************************\ * inf_GetInfInfo (Local Routine) * * Returns a pointer to an INF-INFO struct. * \*****************************************************************************/ PSP_INF_INFORMATION inf_GetInfInfo( HINF hInfObj) { DWORD cbSize; BOOL bRet; PSP_INF_INFORMATION pii; cbSize = 0; bRet = SetupGetInfInformation(hInfObj, INFINFO_INF_SPEC_IS_HINF, NULL, 0, &cbSize); if (bRet && cbSize && (pii = (PSP_INF_INFORMATION)genGAlloc(cbSize))) { bRet = SetupGetInfInformation(hInfObj, INFINFO_INF_SPEC_IS_HINF, pii, cbSize, NULL); if (bRet) return pii; genGFree(pii, genGSize(pii)); } return NULL; } /*****************************************************************************\ * inf_AddItem (Local Routine) * * Add an INF file-item to the list. If adding the new item exceeds the * available space, then reallocate the memory and return a pointer to the * new block. * \*****************************************************************************/ LPINFITEMINFO inf_AddItem( LPINFITEMINFO lpII, LPCTSTR lpszItmName, LPCTSTR lpszItmPath, BOOL bInfFile) { DWORD idx; DWORD dwOldSize; DWORD dwNewSize; LPINFITEMINFO lpNewII; idx = lpII->dwCount++; if ((lpII->dwCount % INF_ITEM_BLOCK) == 0) { dwOldSize = genGSize(lpII); dwNewSize = dwOldSize + (sizeof(INFITEM) * INF_ITEM_BLOCK); // If we can't realloc the memory, then we are going to free up // our existing block and return NULL. In our implementation, if // we can't add items, we need to fail-out. // lpNewII = (LPINFITEMINFO)genGRealloc(lpII, dwOldSize, dwNewSize); if (lpNewII == NULL) { genGFree(lpII, genGSize(lpII)); DBGMSG(DBG_ERROR, ("inf_AddItem : Out of memory")); return NULL; } lpII = lpNewII; } // Add the item to the list. The (szOrd) parameter is // filled in during the writing of the source-disk-files // section. The Ord indicates which directory the file // is located in the LAYOUT.INF. // lpII->aItems[idx].bInf = bInfFile; lstrcpyn(lpII->aItems[idx].szName, lpszItmName, INF_MIN_BUFFER); lstrcpyn(lpII->aItems[idx].szPath, lpszItmPath, MAX_PATH); // Set the SOURCE name to NULL by default, if we find a source that has a different name // to the target, we'll set it to the original name lpII->aItems[idx].szSource[0] = _TEXT('\0'); return lpII; } /*****************************************************************************\ * inf_GetTextLine (Local Routine) * * Quick wrapper which returns the text-value of the line specified in the * inf-object. * \*****************************************************************************/ LPTSTR inf_GetTextLine( HINF hInfObj, PINFCONTEXT pic) { BOOL bOK; DWORD cbSize; LPTSTR lpszTxt; cbSize = 0; if (SetupGetLineText(pic, hInfObj, NULL, NULL, NULL, 0, &cbSize)) { if (cbSize) { cbSize *= sizeof(TCHAR); if (lpszTxt = (LPTSTR)genGAlloc(cbSize)) { bOK = SetupGetLineText(pic, hInfObj, NULL, NULL, lpszTxt, cbSize, NULL); if (bOK) return lpszTxt; genGFree(lpszTxt, cbSize); } } } return NULL; } /*****************************************************************************\ * inf_GetText (Local Routine) * * Quick wrapper which returns the text-value of the line specified in the * inf-object. This only returns the first string if the line contains * a field-list. * \*****************************************************************************/ LPTSTR inf_GetText( HINF hInfObj, PINFCONTEXT pic) { DWORD cbSize; LPTSTR lpszTxt; cbSize = 0; if (SetupGetStringField(pic, 1, NULL, 0, &cbSize)) { if (cbSize) { cbSize *= sizeof(TCHAR); if (lpszTxt = (LPTSTR)genGAlloc(cbSize)) { if (SetupGetStringField(pic, 1, lpszTxt, cbSize, NULL)) return lpszTxt; genGFree(lpszTxt, cbSize); } } } return NULL; } /****************************************************************************************** ** inf_ScanSection (local routine) ** ** Run through all of the members of a section that match a particular Key (possibly NULL) ** Supply the callback routine we receive with the MultiString that we get from scanning ** the section. ******************************************************************************************/ BOOL inf_ScanSection(HINF hInf, // The handle to the inf file we are searching LPCTSTR lpszSection, // The section name we are scanning from LPCTSTR lpszKey, // The key to search the sections for LPVOID pCookie, // The data about the inf that we have picked up INFSCANPROC pFn // The enumeration function ) { ASSERT(pFn); DWORD dwFieldSize = MAX_PATH; LPTSTR pmszFields = (LPTSTR)genGAlloc(sizeof(TCHAR)*dwFieldSize); INFCONTEXT Context; // This is the search context we use BOOL bRet = pmszFields && SetupFindFirstLine(hInf, lpszSection, lpszKey , &Context); BOOL bScan = bRet; while(bScan) { DWORD dwRequiredSize; // Get the Scan Line from the context bScan = SetupGetMultiSzField( &Context, 1, pmszFields, dwFieldSize, &dwRequiredSize); if (!bScan && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { LPTSTR pmszTempFields = (LPTSTR)genGRealloc( pmszFields, sizeof(TCHAR) * dwFieldSize, sizeof(TCHAR) * dwRequiredSize ); if (pmszTempFields) { pmszFields = pmszTempFields; dwFieldSize = dwRequiredSize; bRet = bScan = SetupGetMultiSzField( &Context, 1, pmszFields, dwFieldSize, &dwRequiredSize ); } else bRet = bScan = FALSE; } // We find all the lpszKey Keys and then Pass the Fields through to the Enum Function if (bScan) bScan = bRet = (*pFn)( hInf, pmszFields, pCookie); if (bScan) bScan = SetupFindNextMatchLine( &Context, lpszKey, &Context ); } if (pmszFields) genGFree( pmszFields, dwFieldSize * sizeof(TCHAR) ); return bRet; } /****************************************************************************** ** Structure - ENUMMFGS ** ** This structure is used to pass info up to the enumerator function ** (inf_EnumMfgSections) and return the install sections *******************************************************************************/ typedef struct _EnumMfgs { LPCTSTR lpszDrv; // The driver to find LPTSTR lpszIns; // The install section in which it is found inline _EnumMfgs(LPCTSTR lpszDrv) : lpszDrv(lpszDrv), lpszIns(NULL) {} } ENUMMFGS; typedef ENUMMFGS *PENUMMFGS; /****************************************************************************** ** inf_EnumMfgSections ** ** This functions is called for every manufacturer install section in an inf ** file (there may be more than one). For each one it checks to see whether the ** required driver is inside the install section. If it is, it sets the return ** string to the install section for the driver. (Subsequent calls will be ignored). ******************************************************************************/ BOOL inf_EnumMfgSections(HINF hInf, LPCTSTR lpMfgSec, LPVOID pCookie) { ASSERT(pCookie); // Should not be NULL PENUMMFGS pMfgs = (PENUMMFGS)pCookie; if (lpMfgSec && pMfgs->lpszIns == NULL) { // No matching driver has been found yet INFCONTEXT Context; // This context is used to get the install section if ( inf_GetIdx( lpMfgSec, pMfgs->lpszDrv, hInf, &Context) ) { pMfgs->lpszIns = inf_GetText( hInf, &Context ); } } return TRUE; } /*****************************************************************************\ * inf_GetInsVal (Local Routine) * * Looks for the line indicated by section/key, and returns the text-string * for this line. This also returns an index to the line in the inf-file. * \*****************************************************************************/ LPTSTR inf_GetInsVal( LPCTSTR lpszMfg, LPCTSTR lpszDrv, HINF hInfObj) { ENUMMFGS EnumMfgs(lpszDrv); LPTSTR lpszIns = NULL; if (inf_ScanSection( hInfObj, g_szMfgName, lpszMfg, (LPVOID)&EnumMfgs, inf_EnumMfgSections) ) lpszIns = EnumMfgs.lpszIns; return lpszIns; } /*****************************************************************************\ * inf_RealSect (Local Routine) * * Looks for the real-section-mapping. Some sections could be [.platform] * specific, so we should be able to take in the section-name and * create a real key. * \*****************************************************************************/ LPTSTR inf_GetRealSect( LPINFINFO lpInf, LPCTSTR lpszKey) { BOOL bRet; DWORD cbSize; LPTSTR lpszSect; if (SetupSetPlatformPathOverride(genStrCliOverride(lpInf->idxPlt))) { cbSize = 0; bRet = SetupDiGetActualSectionToInstall(lpInf->hInfObj, lpszKey, NULL, 0, &cbSize, NULL); if (bRet && cbSize) { if (lpszSect = (LPTSTR)genGAlloc(cbSize)) { bRet = SetupDiGetActualSectionToInstall(lpInf->hInfObj, lpszKey, lpszSect, cbSize, NULL, NULL); if (bRet) { SetupSetPlatformPathOverride(NULL); return lpszSect; } genGFree(lpszSect, genGSize(lpszSect)); } } SetupSetPlatformPathOverride(NULL); } return NULL; } /*****************************************************************************\ * inf_GetInfFile (Local Routine) * * Return the name of the inf-file. This looks for the inf-file with the * identified (lpszSection)...if NULL is specified, the first (main) inf * file is returned. * \*****************************************************************************/ LPTSTR inf_GetInfFile( HINF hInfObj, LPCTSTR lpszSct) { PSP_INF_INFORMATION pii; INFCONTEXT ic; LPTSTR lpszInfFile = NULL; if (lpszSct) { if (inf_GetIdx(lpszSct, NULL, hInfObj, &ic)) lpszInfFile = inf_GetInfFile(ic.CurrentInf, NULL); } else { if (pii = inf_GetInfInfo(hInfObj)) { lpszInfFile = inf_GetInfInfoFileName(pii, 0); genGFree(pii, genGSize(pii)); } } return lpszInfFile; } /*****************************************************************************\ * inf_GetLayoutFile (Local Routine) * * Return the name of the Layout file. * \*****************************************************************************/ LPTSTR inf_GetLayoutFile( HINF hInf ) { LPTSTR lpszLayoutFile = NULL; INFCONTEXT INFContext; PINFCONTEXT pINFContext = &INFContext; DWORD dwBufferNeeded; // To get the source directories correct, we need to load all included INFs // separately. THen use their associated layout files. if ( SetupFindFirstLine( hInf, TEXT( "Version" ), TEXT( "LayoutFile" ), &INFContext ) ) { // Find each INF and load it & it's LAYOUT files DWORD dwINFs = SetupGetFieldCount( &INFContext ); if ( SetupGetStringField( &INFContext, 1, NULL, 0, &dwBufferNeeded ) ) { if (lpszLayoutFile = (LPTSTR)genGAlloc( ( dwBufferNeeded * sizeof(TCHAR) ) )) { if ( SetupGetStringField( &INFContext, 1, lpszLayoutFile, ( dwBufferNeeded * sizeof(TCHAR) ), &dwBufferNeeded ) ) return lpszLayoutFile; genGFree(lpszLayoutFile, genGSize(lpszLayoutFile)); } // Allocated pszINFName } // Got the Field from the INF Line } // Found a Layout File return NULL; } /*****************************************************************************\ * inf_GetSrcInf (Local Routine) * * Get the name of the src inf file given the printer friendly name. This * will return a name without the full-path to the inf-directory. * \*****************************************************************************/ LPTSTR inf_GetSrcInf( LPINFINFO lpInf) { LPTSTR lpszRet = NULL; HMODULE hLib; PSETUPCREATE pSCreate; PSETUPDESTROY pSDelete; PSETUPGET pSGet; LPWSTR lpszF; HDEVINFO hDevInfo; WCHAR szTmp[MAX_PATH]; DWORD cbSize = MAX_PATH; BOOL bGet; if (genIsWin9X(lpInf->idxPlt)) { lpszRet = inf_GetW9XInf(lpInf); } else { if (hLib = LoadLibraryFromSystem32(g_szNtPrintDll)) { if (pSCreate = (PSETUPCREATE)GetProcAddress(hLib, g_szSetupCreate)) { if (pSGet = (PSETUPGET)GetProcAddress(hLib, g_szSetupGet)) { if (pSDelete = (PSETUPDESTROY)GetProcAddress(hLib, g_szSetupDestroy)) { if (hDevInfo = (*pSCreate)(NULL)) { #ifdef UNICODE bGet = (*pSGet)(hDevInfo, lpInf->lpszFrnName, szTmp, &cbSize); if (bGet) lpszRet = genGAllocStr(szTmp); else infSetError(lpInf,GetLastError()); #else if (lpszF = genWCFromMB(lpInf->lpszFrnName)) { bGet = (*pSGet)(hDevInfo, lpszF, szTmp, &cbSize); if (bGet) lpszRet = genMBFromWC(szTmp); genGFree(lpszF, genGSize(lpszF)); } #endif (*pSDelete)(hDevInfo); } } } } FreeLibrary(hLib); } } return lpszRet; } /*****************************************************************************\ * inf_CopyAndRenameInf (Local Routine) * * Opens the inf (the installed, possibly renamed inf), and queries setup for the * original name. Copies the inf to our dest directory, renaming it to the * original name, if we have one. Also saves the orignal file info so that we * can rename the .cat file to the original name later. * \*****************************************************************************/ LPTSTR inf_CopyAndRenameInf( LPINFINFO lpInf, LPTSTR lpszSrcInf, LPTSTR lpszSrcInfName) { HINF hInf; PSP_INF_INFORMATION pii; LPTSTR lpszDstInf = NULL; LPTSTR lpszDstName; DWORD dwErr; // If this is a Win9x cab then simply return the passed in name if (genIsWin9X(lpInf->idxPlt)) { lpszDstInf = genGAllocStr(lpszSrcInf); } else { // Open the main-inf file. // hInf = SetupOpenInfFile(lpszSrcInf, g_szPrinterClass, INF_STYLE_WIN4, (PUINT)&dwErr); if ( hInf != INVALID_HANDLE_VALUE ) { if (pii = inf_GetInfInfo(hInf)) { // Set the dst name to default to the src name, just in case we don't // succeed in getting original file info from setup. // If we don't get original file info, we DON'T bail out, because even though // the verification will fail on the client, the user will be prompted as to whether // to install the unverified driver files, which is what we want - the user will // still be able to print. // lpszDstName = lpszSrcInfName; // Ask setupapi for the original names of the .inf and .cat file // lpInf->OriginalFileInfo.cbSize = sizeof(SP_ORIGINAL_FILE_INFO); lpInf->OriginalFileInfo.OriginalInfName[0] = TEXT('\0'); lpInf->OriginalFileInfo.OriginalCatalogName[0] = TEXT('\0'); if (SetupQueryInfOriginalFileInformation(pii, 0, NULL, &(lpInf->OriginalFileInfo))) { lpszDstName = (LPTSTR)&(lpInf->OriginalFileInfo.OriginalInfName); } // Build full-path to inf-file destination. This will be our // new inf-file in the .\cabinets directory. // lpszDstInf = genBuildFileName(lpInf->lpszDstPath, lpszDstName, NULL); if (lpszDstInf) { // Make a copy of our inf to the destination-directory, which will // effectively rename it if we were successful in getting original file info. // if ( !CopyFile(lpszSrcInf, lpszDstInf, FALSE) ) { infSetError(lpInf,GetLastError()); genGFree(lpszDstInf, genGSize(lpszDstInf)); lpszDstInf = NULL; } } else { infSetError(lpInf,GetLastError()); lpszDstInf = NULL; } genGFree(pii, genGSize(pii)); } // if (pii = ...) else infSetError(lpInf,GetLastError()); SetupCloseInfFile(hInf); hInf = NULL; } // if (hInf) else infSetError(lpInf,GetLastError()); } return lpszDstInf; } /*****************************************************************************\ * inf_GetInfObj (Local Routine) * * Get the INF file object handle. This utilizes fields from the lpInf * structure (lpszDstDir, lpszFriendly). * \*****************************************************************************/ HINF inf_GetInfObj( LPINFINFO lpInf) { DWORD dwErr; LPTSTR lpszLayName; LPTSTR lpszInfName; LPTSTR lpszDstInf; LPTSTR lpszSrcInf; LPTSTR lpszLayFile; LPTSTR lpszLaySrc; LPTSTR lpszTmp; HINF hInf = INVALID_HANDLE_VALUE; // Get main INF file and make a copy to our destination. // if (lpszTmp = inf_GetSrcInf(lpInf)) { // Save our inf-filename. // if (lpszSrcInf = genGAllocStr(lpszTmp)) { // Split up the SrcInf file to path and name. // lpszInfName = genFindRChar(lpszTmp, TEXT('\\')); if (lpszInfName != NULL) { *lpszInfName++ = TEXT('\0'); if (lpszDstInf = inf_CopyAndRenameInf(lpInf, lpszSrcInf, lpszInfName)) { // Open the main-inf file. // hInf = SetupOpenInfFile(lpszDstInf, g_szPrinterClass, INF_STYLE_WIN4, (PUINT)&dwErr); if ( hInf == INVALID_HANDLE_VALUE ) infSetError(lpInf,GetLastError()); genGFree(lpszDstInf, genGSize(lpszDstInf)); } // if (lpszDstInf) } // if (lpszInfName != NULL) else infSetError(lpInf, ERROR_PATH_NOT_FOUND); genGFree(lpszSrcInf, genGSize(lpszSrcInf)); } // if (lpszSrcInf) else infSetError(lpInf,GetLastError()); genGFree(lpszTmp, genGSize(lpszTmp)); } // if (lpszTmp) return hInf; } /*****************************************************************************\ * inf_GetInsLine (Local Routine) * * Returns the install-line to install. * \*****************************************************************************/ LPTSTR inf_GetInsLine( LPINFINFO lpInf, LPCTSTR lpszMfgName) { LPTSTR lpszSct; BOOL bRet; DWORD cbSize; LPTSTR lpszIns = NULL; // Retrieve the install-section (raw). // lpszSct = inf_GetInsVal(lpszMfgName, lpInf->lpszDrvName, lpInf->hInfObj); if (lpszSct) { // Set the platform override so that we may be specify // architecture section to install. // SetupSetPlatformPathOverride(genStrCliOverride(lpInf->idxPlt)); // Determine the size necessary to hold the install-section // string. // cbSize = 0; SetupDiGetActualSectionToInstall(lpInf->hInfObj, lpszSct, NULL, 0, &cbSize, NULL); // Get the true install section string. // cbSize *= sizeof(TCHAR); if (cbSize && (lpszIns = (LPTSTR)genGAlloc(cbSize))) { bRet = SetupDiGetActualSectionToInstall(lpInf->hInfObj, lpszSct, lpszIns, cbSize, NULL, NULL); // If we failed, for some reason, then // return NULL. // if (bRet == FALSE) { genGFree(lpszIns, cbSize); lpszIns = NULL; } } SetupSetPlatformPathOverride(NULL); genGFree(lpszSct, genGSize(lpszSct)); } return lpszIns; } /*****************************************************************************\ * inf_GetInfName (Local Routine) * * Returns the name of an inf-file. * \*****************************************************************************/ LPTSTR inf_GetInfName( LPINFINFO lpInf) { PSP_INF_INFORMATION pii; LPTSTR lpszFile; LPTSTR lpszPtr; LPTSTR lpszName = NULL; if (lpszFile = inf_GetInfFile(lpInf->hInfObj, NULL)) { // Seperate the path and file info. // if (lpszPtr = genFindRChar(lpszFile, TEXT('\\'))) lpszName = genGAllocStr(lpszPtr + 1); genGFree(lpszFile, genGSize(lpszFile)); } return lpszName; } /*****************************************************************************\ * inf_IsDrvSupported (Local Routine) * * Returns whether the driver-version is supported for the client-version. * \*****************************************************************************/ BOOL inf_IsDrvSupported( DWORD idxVerCli, DWORD idxVerSpl) { BOOL bSupported = FALSE; // If the client is less than NT 4.0, then we can't support any // drivers that are kernel-mode. // if ((idxVerCli < IDX_SPLVER_2) && (idxVerSpl >= IDX_SPLVER_2)) { bSupported = FALSE; } else { // Determine if the requesting client can handle the // driver-version installed for this printer. Typically, // we can support drivers if they're within one major-version // from each other. // if (abs((int)idxVerCli - (int)idxVerSpl) <= 1) bSupported = TRUE; } return bSupported; } /*****************************************************************************\ * inf_GetDrvPath (Local Routine) * * Returns a string representing the requested driverpath. * \*****************************************************************************/ LPTSTR inf_GetDrvPath( LPCTSTR lpszDrvName, DWORD idxPlt, DWORD idxVer) { BOOL bGet; DWORD cbNeed; DWORD cbSize; LPCTSTR lpszEnv; LPTSTR lpszPath = NULL; #if 1 LPDRIVER_INFO_2 lpdi; LPDRIVER_INFO_2 lpdiItem; DWORD cRet; DWORD idx; BOOL bMatch = FALSE; DWORD idxSpl; LPTSTR lpszEnd; if (lpszEnv = genStrCliEnvironment(idxPlt)) { cbSize = 0; EnumPrinterDrivers(NULL, (LPTSTR)lpszEnv, 2, NULL, 0, &cbSize, &cRet); if (cbSize && (lpdi = (LPDRIVER_INFO_2)genGAlloc(cbSize))) { cRet = 0; bGet = EnumPrinterDrivers(NULL, (LPTSTR)lpszEnv, 2, (LPBYTE)lpdi, cbSize, &cbNeed, &cRet); if (bGet && cRet) { // The goal here is to search for the driver-version // that matches the printer-name, then look to see if // this version will work on the requested client. Typically, // clients can support driver-versions that are (n) to (n-1) // for (idx = 0; idx < cRet; idx++) { lpdiItem = (lpdi + idx); // Potential match? // if (lstrcmpi(lpdiItem->pName, lpszDrvName) == 0) { if (lpszPath = genGAllocStr(lpdiItem->pDriverPath)) { if (lpszEnd = genFindRChar(lpszPath, TEXT('\\'))) { *lpszEnd = TEXT('\0'); bMatch = FALSE; // Find the version-directory-string. // if (lpszEnd = genFindRChar(lpszPath, TEXT('\\'))) { // Get the index for the driver-version. // if ((idxSpl = genIdxFromStrVersion(lpszEnd)) != IDX_UNKNOWN) { bMatch = inf_IsDrvSupported(idxVer, idxSpl); } } } // If we're not a supported driver for the // client, then don't use this path. // if (bMatch == FALSE) { genGFree(lpszPath, genGSize(lpszPath)); lpszPath = NULL; continue; } } break; } } // Chek top see if we found a compatible driver if ( (idx == cRet) && (bMatch == FALSE) ) // We went though the whole list without finding a match SetLastError(ERROR_DRIVER_NOT_FOUND); } genGFree(lpdi, cbSize); } else if ( cbSize == 0 ) SetLastError(ERROR_DRIVER_NOT_FOUND); } return lpszPath; #else DWORD cbVer; LPCTSTR lpszVer; if (lpszEnv = genStrCliEnvironment(idxPlt)) { if (lpszVer = genStrCliVersion(idxVer)) { // Get the required size for storing the full-directory name. // cbSize = 0; GetPrinterDriverDirectory(NULL, (LPTSTR)lpszEnv, 1, NULL, 0, &cbSize); cbVer = (lstrlen(lpszVer) * sizeof(TCHAR)); // Allocate buffer for holding the string and version directory. // if (cbSize && (lpszPath = (LPTSTR)genGAlloc(cbSize + cbVer))) { bGet = GetPrinterDriverDirectory(NULL, (LPTSTR)lpszEnv, 1, (LPBYTE)lpszPath, cbSize + cbVer, &cbNeed); if (bGet) { lstrcat(lpszPath, lpszVer); return lpszPath; } genGFree(lpszPath, cbSize + cbVer); } } } return NULL; #endif } /*****************************************************************************\ * inf_GetPrcPath (Local Routine) * * Returns a string representing the print-processor path. * \*****************************************************************************/ LPTSTR inf_GetPrcPath( DWORD idxPlt) { BOOL bGet; DWORD cbNeed; DWORD cbSize; LPCTSTR lpszEnv; LPTSTR lpszPath; if (lpszEnv = genStrCliEnvironment(idxPlt)) { // Get the required size for storing the full-directory name. // cbSize = 0; GetPrintProcessorDirectory(NULL, (LPTSTR)lpszEnv, 1, NULL, 0, &cbSize); // Allocate buffer for holding the string. // if (cbSize && (lpszPath = (LPTSTR)genGAlloc(cbSize))) { bGet = GetPrintProcessorDirectory(NULL, (LPTSTR)lpszEnv, 1, (LPBYTE)lpszPath, cbSize, &cbNeed); if (bGet) return lpszPath; genGFree(lpszPath, cbSize); } } return NULL; } /*****************************************************************************\ * inf_GetIcmPath (Local Routine) * * Returns a string representing the ICM color path. * \*****************************************************************************/ LPTSTR inf_GetIcmPath( DWORD idxPlt) { DWORD cbSize; LPTSTR lpszPath; // Get the required size for storing the full-directory name. // cbSize = 0; GetColorDirectory(NULL, NULL, &cbSize); // Allocate buffer for holding the string. // if (cbSize && (lpszPath = (LPTSTR)genGAlloc(cbSize))) { if (GetColorDirectory(NULL, lpszPath, &cbSize)) return lpszPath; genGFree(lpszPath, cbSize); } return NULL; } /*****************************************************************************\ * inf_GetSysPath (Local Routine) * * Returns a string representing the system directory. * \*****************************************************************************/ LPTSTR inf_GetSysPath( DWORD idxPlt) { DWORD cbSize; LPTSTR lpszPath; cbSize = (MAX_PATH * sizeof(TCHAR)); // Allocate buffer for holding the string. // if (lpszPath = (LPTSTR)genGAlloc(cbSize)) { if (GetSystemDirectory(lpszPath, MAX_PATH)) return lpszPath; genGFree(lpszPath, cbSize); } return NULL; } /*****************************************************************************\ * inf_AllocStrings (Local Routine) * * Initializes the fields relating to the string-fields. * \*****************************************************************************/ BOOL inf_AllocStrings( LPINFINFO lpInf, LPINFGENPARM lpParm) { // Initialize the driver-name field. // if (lpInf->lpszDrvPath = inf_GetDrvPath(lpParm->lpszDrvName, lpInf->idxPlt, lpInf->idxVer)) { if (lpInf->lpszDrvName = genGAllocStr(lpParm->lpszDrvName)) { if (lpInf->lpszDstName = genGAllocStr(lpParm->lpszDstName)) { if (lpInf->lpszDstPath = genGAllocStr(lpParm->lpszDstPath)) { if (lpInf->lpszPrtName = genGAllocStr(lpParm->lpszPortName)) { if (lpInf->lpszShrName = genGAllocStr(lpParm->lpszShareName)) { if (lpInf->lpszFrnName = genGAllocStr(lpParm->lpszFriendlyName)) return TRUE; genGFree(lpInf->lpszShrName, genGSize(lpInf->lpszShrName)); } genGFree(lpInf->lpszPrtName, genGSize(lpInf->lpszPrtName)); } genGFree(lpInf->lpszDstPath, genGSize(lpInf->lpszDstPath)); } genGFree(lpInf->lpszDstName, genGSize(lpInf->lpszDstName)); } genGFree(lpInf->lpszDrvName, genGSize(lpInf->lpszDrvName)); } genGFree(lpInf->lpszDrvPath, genGSize(lpInf->lpszDrvPath)); } return FALSE; } /*****************************************************************************\ * inf_AddInfFile (Local Routine) * * Adds the inf-file to the list. If this fails, then the (lpII) object * is deleted. This keeps this consistent with the inf_AddItem() routine. * \*****************************************************************************/ LPINFITEMINFO inf_AddInfFile( LPINFINFO lpInf, LPINFITEMINFO lpII) { LPTSTR lpszInfFile; LPTSTR lpszFile; LPINFITEMINFO lpIIRet = NULL; if (lpszInfFile = inf_GetInfFile(lpInf->hInfObj, NULL)) { // Seperate the path and file info, and add to the list. // if (lpszFile = genFindRChar(lpszInfFile, TEXT('\\'))) { *lpszFile = TEXT('\0'); lpIIRet = inf_AddItem(lpII, ++lpszFile, lpszInfFile, TRUE); } genGFree(lpszInfFile, genGSize(lpszInfFile)); } return lpIIRet; } /*****************************************************************************\ * inf_AddCATToCountArray (Local Routine) * * Takes a CAT filename, and adds it to our count array (if a new one), or increments * the count if it already is in our array. * \*****************************************************************************/ BOOL inf_AddCATToCountArray(LPWSTR lpszCATName, LPCATCOUNTARRAY lpCatCountArray) { BOOL bReturn = TRUE; BOOL bFound = FALSE; UINT i; // Alloc or realloc for more memory if needed. We alloc INF_CAT_INCREMENT items at a time, as needed. // // When we start there is no Next Available item defined if (!lpCatCountArray->uNextAvailable) { if (lpCatCountArray->lpArray = (LPCATCOUNT)genGAlloc(sizeof(CATCOUNT) * INF_CAT_INCREMENT) ) { lpCatCountArray->uNextAvailable = INF_CAT_INCREMENT; lpCatCountArray->uItems = 0; } else goto CATCOUNTFAIL; } // See if we have already encountered this CAT file name. If so, increment the count // for this CAT. If not, add this CAT to our array. // for (i=0; i < lpCatCountArray->uItems; i++) { if (!lstrcmp(lpszCATName, lpCatCountArray->lpArray[i].lpszCATName)) { lpCatCountArray->lpArray[i].uCount++; bFound = TRUE; break; } } if (!bFound) { // We might need to reallocate the array, we need to do this if the new position // becomes equal to the next available item UINT uItem = lpCatCountArray->uItems; if (uItem >= lpCatCountArray->uNextAvailable) { LPCATCOUNT lpNewArray = (LPCATCOUNT)genGRealloc((LPVOID)lpCatCountArray->lpArray, sizeof(CATCOUNT) * lpCatCountArray->uNextAvailable, sizeof(CATCOUNT) * (uItem + INF_CAT_INCREMENT) ); if (lpNewArray) { lpCatCountArray->lpArray = lpNewArray; lpCatCountArray->uNextAvailable = uItem + INF_CAT_INCREMENT; } else goto CATCOUNTFAIL; } lpCatCountArray->lpArray[uItem].uCount = 1; lpCatCountArray->lpArray[uItem].lpszCATName = genGAllocWStr(lpszCATName); if (lpCatCountArray->lpArray[uItem].lpszCATName) lpCatCountArray->uItems = uItem + 1; else goto CATCOUNTFAIL; } return TRUE; CATCOUNTFAIL: return FALSE; } /****************************************************************************** * inf_IsIndividuallySigned (Local Routine) * * Returns TRUE if a driver file is individually signed * *******************************************************************************/ BOOL inf_IsIndividuallySigned( LPCTSTR lpszDriverFileName) { GUID gSubject; SIP_DISPATCH_INFO SipDispatch; SIP_SUBJECTINFO SubjectInfo; DWORD cbData = 0; BOOL bRet = FALSE; DWORD dwEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; ASSERT(lpszDriverFileName); if (!CryptSIPRetrieveSubjectGuid( // This GUID is used for passing to CryptSIPLoad lpszDriverFileName, // which verifies the sig on the file NULL, &gSubject)) goto Failure; ZeroMemory( &SipDispatch, sizeof(SipDispatch) ); SipDispatch.cbSize = sizeof(SipDispatch); if (!CryptSIPLoad( &gSubject, 0, &SipDispatch)) goto Failure; // Now that we have the SIP Dispatch, fill out the subject info ZeroMemory( &SubjectInfo, sizeof(SubjectInfo) ); SubjectInfo.cbSize = sizeof(SubjectInfo); SubjectInfo.pgSubjectType = (GUID *)&gSubject; SubjectInfo.hFile = INVALID_HANDLE_VALUE; SubjectInfo.pwsFileName = lpszDriverFileName; SubjectInfo.dwEncodingType = dwEncodingType; if (!SipDispatch.pfGet( &SubjectInfo, &dwEncodingType, 0, &cbData, NULL)) goto Failure; if (cbData != 0) bRet = TRUE; Failure: return bRet; } /*****************************************************************************\ * inf_CATCountProc (Local Routine) * * Callback used to count up all references to CAT files by the driver files. * \*****************************************************************************/ BOOL CALLBACK inf_CATCountProc(LPCTSTR lpszName, LPCTSTR lpszPath, BOOL bInf, LPVOID lpData) { BOOL bReturn = TRUE; LPCATCOUNTARRAY lpCatCountArray = (LPCATCOUNTARRAY)(lpData); HCATADMIN hCatAdmin = lpCatCountArray->hCatAdmin; LPTSTR lpszDriverFileName; HCATINFO hCatInfo = NULL; HCATINFO hCatInfoPrev = NULL; CATALOG_INFO CatalogInfo; BYTE * pbHash; DWORD dwBytes; WIN32_FIND_DATA ffd; PFILEITEM pFileItem; HANDLE hFind, hFile; LPTSTR pFullPath, pPath, pName; // Find the catalog file associated with this file. // If we can't find one, that's OK, it's not an error, just a file // with no associated .cat file. The user can decide on the client-end // whether or not he wants to install without the verification a .cat file // would provide... // if (INVALID_HANDLE_VALUE != (HANDLE)hCatAdmin) { if (lpszDriverFileName = genBuildFileName(lpszPath, lpszName, NULL)) { hFind = FindFirstFile(lpszDriverFileName, &ffd); if (hFind && (hFind != INVALID_HANDLE_VALUE)) { FindClose(hFind); // The first thing we need to determine is whether the file is individually // signed, if it is we don't look for a cat and up the individually signed // count if ( inf_IsIndividuallySigned(lpszDriverFileName) ) { lpCatCountArray->dwIndivSigned++; } else { // Open the file in order to hash it. // if (INVALID_HANDLE_VALUE != (hFile = CreateFile(lpszDriverFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))) { // Determine how many bytes we need for the hash // dwBytes = 0; pbHash = NULL; CryptCATAdminCalcHashFromFileHandle(hFile, &dwBytes, pbHash, 0); if (NULL != (pbHash = (BYTE *)genGAlloc(dwBytes))) { // Compute the hash for this file // if (CryptCATAdminCalcHashFromFileHandle(hFile, &dwBytes, pbHash, 0)) { // Get the catalog file(s) associated with this file hash // hCatInfo = NULL; do { hCatInfoPrev = hCatInfo; hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, pbHash, dwBytes, 0, &hCatInfoPrev); if (NULL != hCatInfo) { CatalogInfo.cbStruct = sizeof(CATALOG_INFO); if (CryptCATCatalogInfoFromContext(hCatInfo, &CatalogInfo, 0)) { if (!inf_AddCATToCountArray(CatalogInfo.wszCatalogFile, lpCatCountArray)) { bReturn = FALSE; hCatInfo = NULL; // fail out of loop } } } } while (NULL != hCatInfo); } // if (CryptCATAdminCalcHashFromFileHandle(hFile, &dwBytes, pbHash, 0)) { genGFree(pbHash, dwBytes); } // if (NULL != (pbHash = (BYTE *)genGAlloc(dwBytes))) { CloseHandle(hFile); } // if (INVALID_HANDLE_VALUE != (hFile = CreateFile(lpszDriverFileName, } // if ( inf_IsIndividuallySigned(hFile, lpszDriverFileName) ) } // if (hFind && (hFind != INVALID_HANDLE_VALUE)) { genGFree(lpszDriverFileName, genGSize(lpszDriverFileName)); } // if (lpszDriverFileName = genBuildFileName(lpszPath, lpszName, NULL)) { } // if (INVALID_HANDLE_VALUE != (HANDLE)hCatAdmin) { return bReturn; } /*****************************************************************************\ * inf_AddCATFile (Local Routine) * * Adds the cat-file to the list (if any). * \*****************************************************************************/ BOOL inf_AddCATFile( LPINFINFO lpInf) { LPTSTR lpszInfFile; LPTSTR lpszFile; LPTSTR lpszDstCAT; LPTSTR lpszDstName; LPTSTR lpszInstalledCATFileName; LPINFITEMINFO lpIIRet; // We initialize return to TRUE because we want to NOT fail out of the cab generation process // at this point, even if we fail to find a CAT file. This will at least still return the driver cab // package to the client and let the user accept or decline the package when it fails to // verify. // BOOL bReturn = TRUE; CATCOUNTARRAY CatCountArray; CatCountArray.dwIndivSigned = 0; // The number of individually signed files CatCountArray.uItems = 0; CatCountArray.uNextAvailable = 0; CatCountArray.lpArray = NULL; // Initialize the catalog admin context handle // if (FALSE == CryptCATAdminAcquireContext(&(CatCountArray.hCatAdmin), NULL, 0)) { CatCountArray.hCatAdmin = (HCATADMIN)INVALID_HANDLE_VALUE; infSetError(lpInf,GetLastError()); return FALSE; } // Enumerate all the items in the inf. The enumeration callback (inf_CATCountProc) // will count the number of references for each unique CAT file that is referenced by // one of our driver files. We will add to the CAB file, the CAT file that is referenced // the most times by the driver files - this CAT file SHOULD be referenced by ALL of the // driver files, or there is no point in adding the CAT to the CAB, since the driver verification // will fail on the client if not all files are verified by the CAT. // if (infEnumItems((HANDLE)lpInf, inf_CATCountProc, (LPVOID)&CatCountArray )) { if (CatCountArray.uItems > 0) { UINT uIndex; // Search our CAT file array to find the CAT file that was referenced more than the others. // This is the CAT file we want to package into the CAB. // UINT uIndexOfMostCommonCAT = 0; for (uIndex=0; uIndex < CatCountArray.uItems; uIndex++) { if (CatCountArray.lpArray[uIndexOfMostCommonCAT].uCount < CatCountArray.lpArray[uIndex].uCount) uIndexOfMostCommonCAT = uIndex; } // Make sure that every file referenced this CAT file - if they all didn't, // then it will fail verification on client - so no sense in sending the CAT // to the CAB package // if (CatCountArray.lpArray[uIndexOfMostCommonCAT].uCount + CatCountArray.dwIndivSigned >= (lpInf->lpInfItems->dwCount)) { lpszInstalledCATFileName = CatCountArray.lpArray[uIndexOfMostCommonCAT].lpszCATName; // If we have an original .cat file name, use it for the dest name, // otherwise, just use the current (installed) name // if (lpInf->OriginalFileInfo.OriginalCatalogName[0] != TEXT('\0')) { lpszDstName = (LPTSTR)&(lpInf->OriginalFileInfo.OriginalCatalogName); } else { // Find the filename portion of the current (installed) .cat file name. lpszDstName = genFindRChar(lpszInstalledCATFileName, TEXT('\\')); lpszDstName++; } if (lpszDstCAT = genBuildFileName(lpInf->lpszDstPath, lpszDstName, NULL)) { // Copy the CAT file into our directory, renaming it to the original name. // if ( CopyFile(lpszInstalledCATFileName, lpszDstCAT, FALSE) ) { // Add this (renamed) file to our file list to be added to the cab. // lpIIRet = inf_AddItem(lpInf->lpInfItems, lpszDstName, lpInf->lpszDstPath, TRUE); if (lpIIRet == NULL) { infSetError(lpInf,GetLastError()); bReturn = FALSE; } lpInf->lpInfItems = lpIIRet; } else { infSetError(lpInf,GetLastError()); genGFree(lpInf->lpInfItems, genGSize(lpInf->lpInfItems)); lpInf->lpInfItems = NULL; bReturn = FALSE; } genGFree(lpszDstCAT, genGSize(lpszDstCAT)); } } } else { DBGMSG(DBG_INFO, ("geninf: No CAT Files found for driver package.\n")); } } // Free all our CAT array items here // if (CatCountArray.lpArray) { UINT uItem = 0; for (uItem = 0; uItem < CatCountArray.uItems; uItem++) { genGFree(CatCountArray.lpArray[uItem].lpszCATName, genGSize(CatCountArray.lpArray[uItem].lpszCATName)); } genGFree(CatCountArray.lpArray, genGSize(CatCountArray.lpArray)); } // Release the Catalog Admin context handle, if we have one // if (INVALID_HANDLE_VALUE != (HANDLE)(CatCountArray.hCatAdmin)) { CryptCATAdminReleaseContext(CatCountArray.hCatAdmin, 0); } return bReturn; } /*****************************************************************************\ * inf_SetDefDirIds (Local Routine) * * Sets the Default DRID values for the setup-process. * \*****************************************************************************/ BOOL inf_SetDefDirIds( LPINFINFO lpInf) { LPTSTR lpszDrv; LPTSTR lpszPrc; LPTSTR lpszSys; LPTSTR lpszIcm; BOOL bRet = FALSE; if (lpszDrv = lpInf->lpszDrvPath) { if (lpszPrc = inf_GetPrcPath(lpInf->idxPlt)) { if (lpszSys = inf_GetSysPath(lpInf->idxPlt)) { if (lpszIcm = inf_GetIcmPath(lpInf->idxPlt)) { if (SetupSetDirectoryId(lpInf->hInfObj, INF_DRV_DRID, lpszDrv) && SetupSetDirectoryId(lpInf->hInfObj, INF_PRC_DRID, lpszPrc) && SetupSetDirectoryId(lpInf->hInfObj, INF_SYS_DRID, lpszSys) && SetupSetDirectoryId(lpInf->hInfObj, INF_ICM_DRID, lpszIcm)) { bRet = TRUE; } genGFree(lpszIcm, genGSize(lpszIcm)); } genGFree(lpszSys, genGSize(lpszSys)); } genGFree(lpszPrc, genGSize(lpszPrc)); } } return bRet; } /*****************************************************************************\ * inf_SetDirIds (Local Routine) * * Sets the DRID values for the setup-process. * \*****************************************************************************/ BOOL inf_SetDirIds( LPINFINFO lpInf) { INFCONTEXT ic; DWORD idx; DWORD dwCount; WORD wEnvCli; WORD wEnvSrv; DWORD dwDRID; LPTSTR lpszDir; BOOL bRet = FALSE; // Initialize the default directories for DRID values. // inf_SetDefDirIds(lpInf); // Look through the INF-File for any overriding DRID values and // set these. // if ((dwCount = SetupGetLineCount(lpInf->hInfObj, g_szDestDirs)) != (DWORD)-1) { for (idx = 0, bRet = TRUE; (idx < dwCount) && bRet; idx++) { if (bRet = SetupGetLineByIndex(lpInf->hInfObj, g_szDestDirs, idx, &ic)) { if (bRet = SetupGetIntField(&ic, 1, (PINT)&dwDRID)) { if (dwDRID < DIRID_USER) continue; switch (dwDRID) { case INF_DRV_DRID: bRet = SetupSetDirectoryId(lpInf->hInfObj, dwDRID, lpInf->lpszDrvPath); continue; #if 1 // We don't necessarily need to copy the procesor and system32 files // since they are architecture specific. In this case we will let the // files default to the skip-dir. // // NOTE: if do not include these files, we might need to modify the INF // so that they are not referenced during client-side install. // case INF_PRC_DRID: wEnvCli = genValCliArchitecture(lpInf->idxPlt); wEnvSrv = genValSvrArchitecture(); if (wEnvCli == wEnvSrv) { lpszDir = inf_GetPrcPath(lpInf->idxPlt); } else { lpszDir = genGAllocStr(g_szSkipDir); } break; case INF_SYS_DRID: wEnvCli = genValCliArchitecture(lpInf->idxPlt); wEnvSrv = genValSvrArchitecture(); if (wEnvCli == wEnvSrv) { lpszDir = inf_GetSysPath(lpInf->idxPlt); } else { lpszDir = genGAllocStr(g_szSkipDir); } break; #endif case INF_ICM_DRID: lpszDir = inf_GetIcmPath(lpInf->idxPlt); break; default: lpszDir = genGAllocStr(g_szSkipDir); } if (lpszDir) { bRet = SetupSetDirectoryId(lpInf->hInfObj, dwDRID, lpszDir); genGFree(lpszDir, genGSize(lpszDir)); } else { bRet = FALSE; } } } } } return bRet; } /*****************************************************************************\ * inf_ScanFiles (Local Routine) * * Callback routine which returns the items in a copyfiles list. * \*****************************************************************************/ UINT CALLBACK inf_ScanFiles( LPVOID lpCtxt, UINT uNotify, UINT_PTR Parm1, UINT_PTR Parm2) { LPINFSCAN lpScan; LPTSTR lpszPath; LPTSTR lpszFile; if ((lpScan = (LPINFSCAN)lpCtxt) && (lpszPath = (LPTSTR)Parm1)) { if (lpszFile = genFindRChar(lpszPath, TEXT('\\'))) { *lpszFile = TEXT('\0'); // If this is a skip-dir item then do not add to our // list. This can happen for files that are not stored // in platform-specific directories. For example, files // stored in the SYSTEM32 directory have no architecture // counter-part. We do not want to download the incorrect // file for a different architecture. // if (lstrcmpi(lpszPath, g_szSkipDir) != 0) { lpScan->lpII = inf_AddItem(lpScan->lpII, lpszFile + 1, lpszPath, FALSE); } *lpszFile = TEXT('\\'); return (lpScan->lpII ? 0 : 1); } } return 1; } /*****************************************************************************\ * inf_BuildW9XList (Local Routine) * * This enumerates the W9X dependent files and adds them to our list. * \*****************************************************************************/ LPINFITEMINFO inf_BuildW9XList( LPINFINFO lpInf, LPINFSCAN lpis) { LPDRIVER_INFO_3 lpdi3; LPTSTR lpszDrvName; LPTSTR lpszItm; BOOL bRet = FALSE; if (lpdi3 = inf_GetW9XInfo(lpInf, &lpszDrvName)) { if (lpszItm = lpdi3->pDependentFiles) { bRet = TRUE; while (*lpszItm) { if (inf_ScanFiles(lpis, 0, (UINT_PTR)lpszItm, 0) != 0) break; lpszItm = inf_NextStr(lpszItm); } } genGFree(lpszDrvName, genGSize(lpszDrvName)); genGFree(lpdi3, genGSize(lpdi3)); } if (bRet == FALSE) { genGFree(lpis->lpII, genGSize(lpis->lpII)); lpis->lpII = NULL; } return lpis->lpII; } /******************************************************************************************* ** inf_ScanSourceTarget (local routine) ** ** Get the source and target, and then run through all the inf files if there is a source ** and find the target file that matches and add the source to the database ** *******************************************************************************************/ BOOL CALLBACK inf_ScanSourceTarget(HINF hInf, LPCTSTR pmszFields, LPVOID pCookie) { ASSERT(pmszFields); // Should never be NULL, we allocate it ASSERT(pCookie); // Should never be NULL, we pass it in after check LPINFSCAN lpis = (LPINFSCAN)pCookie; LPINFITEMINFO lpII = lpis->lpII; LPCTSTR szTarget = pmszFields; BOOL bRet = lpII != NULL; if (*szTarget && bRet) { // There is a target file (non NULL) LPCTSTR szSource = &pmszFields[ lstrlen(szTarget) + 1 ]; if (*szSource) { DWORD dwIdx; DWORD dwCount; // We don't need to do anything if source and target name are the same, even // if they are expressly listed in the inf file if ( lstrcmpi ( szTarget, szSource) ) { dwCount = lpII->dwCount; for(dwIdx = 0; dwIdx < dwCount; ++dwIdx) { if (!lstrcmpi( lpII->aItems[dwIdx].szName, szTarget)) // Targets match, write the source file name into the structure lstrcpyn( lpII->aItems[dwIdx].szSource, szSource, INF_MIN_BUFFER ); } } } } return bRet; } /****************************************************************************************** ** inf_ScanCopyFields (local routine) ** ** Run through the Copy Fields supplied by inf_ScanSection and Scan through those sections ** for Source and Destination Pairs ** ******************************************************************************************/ BOOL CALLBACK inf_ScanCopyFields(HINF hInf, LPCTSTR pmszFields, LPVOID pCookie) { ASSERT(pmszFields); BOOL bRet = TRUE; while(*pmszFields && bRet) { if (*pmszFields != TEXT('@')) // Check for an individual file install bRet = inf_ScanSection( hInf, pmszFields, NULL, pCookie, inf_ScanSourceTarget); pmszFields += lstrlen(pmszFields) + 1; } return bRet; } /*****************************************************************************\ * inf_BuildWNTList (Local Routine) * * This builds our list from the NT scan-file-queue of an inf-parser. * \*****************************************************************************/ LPINFITEMINFO inf_BuildWNTList( LPINFINFO lpInf, LPCTSTR lpszMfgName, LPINFSCAN lpis) { LPTSTR lpszIns; HSPFILEQ hFQ; DWORD dwRet; BOOL bRet = FALSE; if (lpszIns = inf_GetInsLine(lpInf, lpszMfgName)) { SetupSetPlatformPathOverride(genStrCliOverride(lpInf->idxPlt)); hFQ = SetupOpenFileQueue(); if (hFQ != INVALID_HANDLE_VALUE) { inf_SetDirIds(lpInf); bRet = SetupInstallFilesFromInfSection(lpInf->hInfObj, NULL, hFQ, lpszIns, NULL, 0); if (bRet) { // Setup the user-defined data passed to the // enum-callback. // dwRet = 0; bRet = SetupScanFileQueue(hFQ, SPQ_SCAN_USE_CALLBACK, 0, inf_ScanFiles, (LPVOID)lpis, &dwRet); } SetupCloseFileQueue(hFQ); // Now that we have all of the files, we run through the inf file to see what the // original file names where. If they are different, we insert them into // the inf file if (bRet) bRet = inf_ScanSection(lpInf->hInfObj, lpszIns, g_szCopyFiles, (PVOID)lpis, inf_ScanCopyFields ); } SetupSetPlatformPathOverride(NULL); genGFree(lpszIns, genGSize(lpszIns)); } if (bRet == FALSE) { genGFree(lpis->lpII, genGSize(lpis->lpII)); lpis->lpII = NULL; } return lpis->lpII; } /*****************************************************************************\ * inf_GetItemList (Local Routine) * * Get the items from the INF file and build our array of files from this * search. This does quite a bit of work. * \*****************************************************************************/ LPINFITEMINFO inf_GetItemList( LPINFINFO lpInf, LPCTSTR lpszMfgName) { INFSCAN is; DWORD cbSize; BOOL bRet; // Initialize a default-block to contain our inf-items. // cbSize = sizeof(INFITEMINFO) + (sizeof(INFITEM) * INF_ITEM_BLOCK); // Setup a structure which will be utilized by either the // setup-scan-file-queue, or our own routine to process W9X // items. // if (is.lpII = (LPINFITEMINFO)genGAlloc(cbSize)) { is.lpInf = lpInf; // Add the inf-files to the list. // if (is.lpII = inf_AddInfFile(lpInf, is.lpII)) { if (genIsWin9X(lpInf->idxPlt)) { is.lpII = inf_BuildW9XList(lpInf, &is); } else { is.lpII = inf_BuildWNTList(lpInf, lpszMfgName, &is); } } } return is.lpII; } /*****************************************************************************\ * inf_GetSection (Local Routine) * * Allocate a buffer which stores either all section-names or the list of * items specified by (lpszSection) in an INF file. Currently, we attempt * a realloc if the buffer is not big enough. * \*****************************************************************************/ LPTSTR inf_GetSection( LPINFINFO lpInf, LPCTSTR lpszSct) { LPTSTR lpszInfFile; DWORD dwCnt; DWORD cch; DWORD dwSize; DWORD dwLimit; LPTSTR lpszNames = NULL; // Get the inf-file-name whith contains the specified section. // if (lpszInfFile = inf_GetInfFile(lpInf->hInfObj, lpszSct)) { dwSize = 0; dwLimit = 0; while (dwLimit < INF_SECTION_LIMIT) { // We'll start this allocation with an assumed max-size. Upon // successive tries, this buffer is increased each time by the // original buffer allocation. // dwSize += (INF_SECTION_BLOCK * sizeof(TCHAR)); dwLimit++; // Alloc the buffer and attempt to get the names. // if (lpszNames = (LPTSTR)genGAlloc(dwSize)) { // If a section-name is profided, use that. Otherwise, // enumerate all section-names. // cch = dwSize / sizeof(TCHAR); if (lpszSct) { dwCnt = GetPrivateProfileSection(lpszSct, lpszNames, cch, lpszInfFile); } else { dwCnt = GetPrivateProfileSectionNames(lpszNames, cch, lpszInfFile); } // If the call says the buffer was OK, then we can // assume the names are retrieved. According to spec's, // if the return-count is equal to size-2, then buffer // isn't quite big-enough (two NULL chars). // if (dwCnt < (cch - 2)) goto GetSectDone; genGFree(lpszNames, dwSize); lpszNames = NULL; } } GetSectDone: SPLASSERT((dwLimit < INF_SECTION_LIMIT)); genGFree(lpszInfFile, genGSize(lpszInfFile)); } return lpszNames; } /*****************************************************************************\ * inf_GetMfgName (Local Routine) * * Get the manufacture-name from the driver-name. Some drivers do not really * begin with the manufacture-name. These will have to be special-cased * to determine their cooresponding manufacturer-name. * \*****************************************************************************/ LPTSTR inf_GetMfgNameExe( LPINFINFO lpInf) { INFCONTEXT ic; BOOL bFind; LPTSTR lpszNames; LPTSTR lpszDrvCpy; LPTSTR lpszPtr; LPTSTR lpszMfgName = NULL; // Make a copy for us to muck with. // if (lpszDrvCpy = genGAllocStr(lpInf->lpszDrvName)) { // Let's assume the best-case and the model-name's first word // is the Manufacturer. All we need in this case is to find // the first in the driver-name. // // Find the first word to use in locating the manufacturer. // if (lpszPtr = genFindChar(lpszDrvCpy, TEXT(' '))) *lpszPtr = TEXT('\0'); // Take the first-word and try to get a manufacture out // of it. // if (lpszMfgName = genGAllocStr(lpszDrvCpy)) { // Look for the module-name in the manufacturers section. This // will return us an index into the inf-file. // bFind = inf_GetIdx(lpszMfgName, lpInf->lpszDrvName, lpInf->hInfObj, &ic); // If the model-manufacturer lookup failed, then we // need to look at other model-manufacturer mappings. // if (bFind == FALSE) { // Free the existing string used for this test. Since, // we could conceptually come up with another manufacturer // name for this model. // genGFree(lpszMfgName, genGSize(lpszMfgName)); lpszMfgName = NULL; // Since we were not able to find the model-name through // conventional means, we are going to look through every // section-name in the Inf for the model-name. // if (lpszNames = inf_GetSection(lpInf, NULL)) { lpszPtr = lpszNames; while (*lpszPtr != TEXT('\0')) { bFind = inf_GetIdx(lpszPtr, lpInf->lpszDrvName, lpInf->hInfObj, &ic); // See if we found a match. If so, break out // of our loop. // if (bFind) { lpszMfgName = genGAllocStr(lpszPtr); break; } // Goto the next section. // lpszPtr = inf_NextStr(lpszPtr); } genGFree(lpszNames, genGSize(lpszNames)); } } } genGFree(lpszDrvCpy, genGSize(lpszDrvCpy)); } return lpszMfgName; } /*****************************************************************************\ * inf_GetMfgName (Local Routine) * * Get the manufacture-name from the driver-name. Some drivers do not really * begin with the manufacture-name. These will have to be special-cased * to determine their cooresponding manufacturer-name. * \*****************************************************************************/ LPTSTR inf_GetMfgName( LPINFINFO lpInf) { HANDLE hPrinter; LPTSTR lpszMfgName = NULL; if (OpenPrinter(lpInf->lpszFrnName, &hPrinter, NULL)) { DWORD cbNeeded = 0; LPTSTR lpszClientEnvironment = (LPTSTR)genStrCliEnvironment(lpInf->idxPlt); GetPrinterDriver( hPrinter, lpszClientEnvironment, 6, NULL, 0, &cbNeeded ); if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { LPBYTE pData; DWORD dwSize = cbNeeded; if ( pData = (LPBYTE) genGAlloc(cbNeeded) ) { if (GetPrinterDriver( hPrinter, lpszClientEnvironment, 6, pData, dwSize, &cbNeeded) ) { PDRIVER_INFO_6 pDriverInfo = (PDRIVER_INFO_6) pData; if (pDriverInfo->pszMfgName) lpszMfgName = genGAllocStr(pDriverInfo->pszMfgName); else SetLastError(ERROR_BAD_ENVIRONMENT); } genGFree( pData, dwSize ); } } ClosePrinter(hPrinter); } if (NULL == lpszMfgName) lpszMfgName = inf_GetMfgNameExe(lpInf); return lpszMfgName; } /*****************************************************************************\ * inf_BuildItems (Local Routine) * * This routine builds a file-list of items that the INF setup requires. * \*****************************************************************************/ LPINFITEMINFO inf_BuildItems( LPINFINFO lpInf) { LPTSTR lpszMfgName; LPINFITEMINFO lpItems = NULL; // Get the manufacturer-name that we will be dealing with. If // we can't find the matching name that cooresponds with our driver, // then no need to proceed. // if (lpszMfgName = inf_GetMfgName(lpInf)) { // Build the item-list. If successful, then rewrite our new // inf-files for a flat-install. // lpItems = inf_GetItemList(lpInf, lpszMfgName); genGFree(lpszMfgName, genGSize(lpszMfgName)); } return lpItems; } /*****************************************************************************\ * infCreate * * Creates an INF object. * \*****************************************************************************/ HANDLE infCreate( LPINFGENPARM lpParm) { LPINFINFO lpInf; if (lpInf = (LPINFINFO)genGAlloc(sizeof(INFINFO))) { lpInf->dwCliInfo = lpParm->dwCliInfo; lpInf->idxPlt = lpParm->idxPlt; lpInf->idxVer = lpParm->idxVer; // Allocate our parameter-strings. // if ( inf_AllocStrings(lpInf, lpParm) ) return (HANDLE)lpInf; // Since the allocate Strings failed free up the Object genGFree(lpInf, sizeof(INFINFO)); } return NULL; } /*****************************************************************************\ * infProcess * * Uses INF object to prepare for CAB. * \*****************************************************************************/ BOOL infProcess( HANDLE hInf) { LPINFINFO lpInf = (LPINFINFO) hInf; // Create handle to setup-inf-object. This requires // strings in lpInf to be allocated and correct. // lpInf->hInfObj = inf_GetInfObj(lpInf); if ( lpInf->hInfObj != INVALID_HANDLE_VALUE ) { // Retrieve the inf-name from the inf-object. // if (lpInf->lpszInfName = inf_GetInfName(lpInf)) { // Build our file object-list. // if (lpInf->lpInfItems = inf_BuildItems(lpInf)) { // Next, use the item list to determine the cat file and add it // to the list. This can't be done any earlier (like in inf_BuildItems() ) // because it uses the infEnumItems callback, and so it relies on the // item list being setup already. // if (genIsWin9X(lpInf->idxPlt)) { // Do something different here for 9X? // The server isn't caching the CAT files for 9X drivers, so // we don't have access to them anyway. // return TRUE; } else { if (inf_AddCATFile(lpInf)) { return TRUE; } } } } // Some Type of failure... infSetError(lpInf,GetLastError()); } return FALSE; } /*****************************************************************************\ * infDestroy * * Destroys the INF object and all resources allocated on its behalf. * \*****************************************************************************/ BOOL infDestroy( HANDLE hInf) { LPINFINFO lpInf; BOOL bFree = FALSE; if (lpInf = (LPINFINFO)hInf) { if (lpInf->hInfObj != INVALID_HANDLE_VALUE) SetupCloseInfFile(lpInf->hInfObj); if (lpInf->lpszInfName) genGFree(lpInf->lpszInfName, genGSize(lpInf->lpszInfName)); if (lpInf->lpszFrnName) genGFree(lpInf->lpszFrnName, genGSize(lpInf->lpszFrnName)); if (lpInf->lpszDrvName) genGFree(lpInf->lpszDrvName, genGSize(lpInf->lpszDrvName)); if (lpInf->lpszDrvPath) genGFree(lpInf->lpszDrvPath, genGSize(lpInf->lpszDrvPath)); if (lpInf->lpszDstName) genGFree(lpInf->lpszDstName, genGSize(lpInf->lpszDstName)); if (lpInf->lpszDstPath) genGFree(lpInf->lpszDstPath, genGSize(lpInf->lpszDstPath)); if (lpInf->lpszPrtName) genGFree(lpInf->lpszPrtName, genGSize(lpInf->lpszPrtName)); if (lpInf->lpszShrName) genGFree(lpInf->lpszShrName, genGSize(lpInf->lpszShrName)); if (lpInf->lpInfItems) genGFree(lpInf->lpInfItems, genGSize(lpInf->lpInfItems)); bFree = genGFree(lpInf, sizeof(INFINFO)); } return bFree; } /*****************************************************************************\ * infEnumItems * * Enumerates the file-items in the INF object. Enumeration will stop if the * user-callback returns FALSE. Otherwise, it will exhaust all files in the * list. * \*****************************************************************************/ BOOL infEnumItems( HANDLE hInf, INFENUMPROC pfnEnum, LPVOID lpvData) { LPINFINFO lpInf; LPINFITEMINFO lpII; DWORD dwItems; DWORD idx; BOOL bRet = FALSE; if ((lpInf = (LPINFINFO)hInf) && (dwItems = lpInf->lpInfItems->dwCount)) { for (idx = 0, lpII = lpInf->lpInfItems; idx < dwItems; idx++) { bRet = (*pfnEnum)(lpII->aItems[idx].szName, lpII->aItems[idx].szPath, lpII->aItems[idx].bInf, lpvData); if (bRet == FALSE) return FALSE; } } return bRet; } /*****************************************************************************\ * infGetEnvArch * * Returns the platform/environment type identifier. * \*****************************************************************************/ WORD infGetEnvArch( HANDLE hInf) { LPINFINFO lpInf; WORD wType = PROCESSOR_ARCHITECTURE_UNKNOWN; if (lpInf = (LPINFINFO)hInf) wType = genValCliArchitecture(lpInf->idxPlt); return wType; } /*****************************************************************************\ * infGetEnvArchCurr * * Returns the platform/environment type for the current-architecture. * \*****************************************************************************/ WORD infGetEnvArchCurr( HANDLE hInf) { return genValSvrArchitecture(); }