mirror of https://github.com/tongzx/nt5src
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.
3059 lines
90 KiB
3059 lines
90 KiB
/*****************************************************************************\
|
|
* 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 <space> 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();
|
|
}
|