Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2388 lines
70 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
All rights reserved.
Module Name:
getdata.c
Abstract:
PostScript helper functions for OEM plugins
HGetGlobalAttribute
HGetFeatureAttribute
HGetOptionAttribute
HEnumFeaturesOrOptions
Author:
Feng Yue (fengy)
8/24/2000 fengy Completed with support of both PPD and driver features.
5/22/2000 fengy Created it with function framework.
--*/
#include "lib.h"
#include "ppd.h"
#include "pslib.h"
//
// PS driver's helper functions for OEM plugins
//
//
// global attribute names
//
const CHAR kstrCenterReg[] = "CenterRegistered";
const CHAR kstrColorDevice[] = "ColorDevice";
const CHAR kstrExtensions[] = "Extensions";
const CHAR kstrFileVersion[] = "FileVersion";
const CHAR kstrFreeVM[] = "FreeVM";
const CHAR kstrLSOrientation[] = "LandscapeOrientation";
const CHAR kstrLangEncoding[] = "LanguageEncoding";
const CHAR kstrLangLevel[] = "LanguageLevel";
const CHAR kstrNickName[] = "NickName";
const CHAR kstrPPDAdobe[] = "PPD-Adobe";
const CHAR kstrPrintError[] = "PrintPSErrors";
const CHAR kstrProduct[] = "Product";
const CHAR kstrProtocols[] = "Protocols";
const CHAR kstrPSVersion[] = "PSVersion";
const CHAR kstrJobTimeout[] = "SuggestedJobTimeout";
const CHAR kstrWaitTimeout[] = "SuggestedWaitTimeout";
const CHAR kstrThroughput[] = "Throughput";
const CHAR kstrTTRasterizer[] = "TTRasterizer";
//
// feature attribute names
//
const CHAR kstrDisplayName[] = "DisplayName";
const CHAR kstrDefOption[] = "DefaultOption";
const CHAR kstrOpenUIType[] = "OpenUIType";
const CHAR kstrOpenGroupType[] = "OpenGroupType";
const CHAR kstrOrderDepValue[] = "OrderDependencyValue";
const CHAR kstrOrderDepSect[] = "OrderDependencySection";
//
// option keyword names, option attribute names
//
const CHAR kstrInvocation[] = "Invocation";
const CHAR kstrInputSlot[] = "InputSlot";
const CHAR kstrReqPageRgn[] = "RequiresPageRegion";
const CHAR kstrOutputBin[] = "OutputBin";
const CHAR kstrOutOrderRev[] = "OutputOrderReversed";
const CHAR kstrPageSize[] = "PageSize";
const CHAR kstrPaperDim[] = "PaperDimension";
const CHAR kstrImgArea[] = "ImageableArea";
const CHAR kstrCustomPS[] = "CustomPageSize";
const CHAR kstrParamCustomPS[] = "ParamCustomPageSize";
const CHAR kstrHWMargins[] = "HWMargins";
const CHAR kstrMaxMWidth[] = "MaxMediaWidth";
const CHAR kstrMaxMHeight[] = "MaxMediaHeight";
const CHAR kstrInstalledMem[] = "InstalledMemory";
const CHAR kstrVMOption[] = "VMOption";
const CHAR kstrFCacheSize[] = "FCacheSize";
//
// enumeration of data region where an attribute is stored
//
typedef enum _EATTRIBUTE_DATAREGION {
kADR_UIINFO, // attribute is stored in UIINFO structure
kADR_PPDDATA, // attribute is stored in PPDDATA structure
} EATTRIBUTE_DATAREGION;
/*++
Routine Name:
HGetSingleData
Routine Description:
copy source data to specified output buffer and set the output data type
Arguments:
pSrcData - pointer to source data buffer
dwSrcDataType - source data type
cbSrcSize - source data buffer size in bytes
pdwOutDataType - pointer to DWORD to store output data type
pbOutData - pointer to output data buffer
cbOutSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds
E_OUTOFMEMORY if output data buffer size is not big enough
Last Error:
None
--*/
HRESULT
HGetSingleData(
IN PVOID pSrcData,
IN DWORD dwSrcDataType,
IN DWORD cbSrcSize,
OUT PDWORD pdwOutDataType,
OUT PBYTE pbOutData,
IN DWORD cbOutSize,
OUT PDWORD pcbNeeded
)
{
//
// Either pSrcData is NULL and cbSrcSize is 0,
// or pSrcData is non-NULL and cbSrcSize is non-0.
//
ASSERT((pSrcData != NULL) || (cbSrcSize == 0));
ASSERT((cbSrcSize != 0) || (pSrcData == NULL));
if (pdwOutDataType)
{
*pdwOutDataType = dwSrcDataType;
}
if (pcbNeeded)
{
*pcbNeeded = cbSrcSize;
}
if (cbSrcSize)
{
//
// We do have data for output.
//
if (!pbOutData || cbOutSize < cbSrcSize)
{
return E_OUTOFMEMORY;
}
CopyMemory(pbOutData, pSrcData, cbSrcSize);
}
return S_OK;
}
/*++
Routine Name:
HGetGABool
Routine Description:
get global boolean attribute
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute Get operation
pszAttribute - name of the global attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
E_INVALIDARG if the global attribute is not recognized
S_OK
E_OUTOFMEMORY see function HGetSingleData
Last Error:
None
--*/
HRESULT
HGetGABool(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef struct _GA_BOOL_ENTRY {
PCSTR pszAttributeName; // attribute name
EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
DWORD cbOffset; // byte offset to the DWORD data
DWORD dwFlagBit; // bit flag in the DWORD
} GA_BOOL_ENTRY, *PGA_BOOL_ENTRY;
static const GA_BOOL_ENTRY kGABoolTable[] =
{
{kstrCenterReg, kADR_PPDDATA, offsetof(PPDDATA, dwCustomSizeFlags), CUSTOMSIZE_CENTERREG},
{kstrColorDevice, kADR_UIINFO, offsetof(UIINFO, dwFlags), FLAG_COLOR_DEVICE},
{kstrPrintError, kADR_PPDDATA, offsetof(PPDDATA, dwFlags), PPDFLAG_PRINTPSERROR},
};
PUIINFO pUIInfo;
PPPDDATA pPpdData;
DWORD cIndex;
DWORD cTableEntry = sizeof(kGABoolTable) / sizeof(GA_BOOL_ENTRY);
PGA_BOOL_ENTRY pEntry;
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
pEntry = (PGA_BOOL_ENTRY)(&kGABoolTable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
(strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
{
//
// attribute name matches
//
DWORD dwValue;
BOOL bValue;
if (pEntry->eADR == kADR_UIINFO)
{
dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
}
else if (pEntry->eADR == kADR_PPDDATA)
{
dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
}
else
{
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGABool: unknown eADR %d\n", pEntry->eADR));
return E_FAIL;
}
//
// map the bit flag to boolean value
//
bValue = (dwValue & pEntry->dwFlagBit) ? TRUE : FALSE;
return HGetSingleData((PVOID)&bValue, kADT_BOOL, sizeof(BOOL),
pdwDataType, pbData, cbSize, pcbNeeded);
}
}
//
// can't find the attribute
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGABool: unknown attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
/*++
Routine Name:
HGetGAInvocation
Routine Description:
get global invocation attribute
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute Get operation
pszAttribute - name of the global attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
E_INVALIDARG if the global attribute is not recognized
S_OK
E_OUTOFMEMORY see function HGetSingleData
Last Error:
None
--*/
HRESULT
HGetGAInvocation(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef struct _GA_INVOC_ENTRY {
PCSTR pszAttributeName; // attribute name
EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
DWORD cbOffset; // byte offset to INVOCATION structure
} GA_INVOC_ENTRY, *PGA_INVOC_ENTRY;
static const GA_INVOC_ENTRY kGAInvocTable[] =
{
{kstrProduct, kADR_PPDDATA, offsetof(PPDDATA, Product)},
{kstrPSVersion, kADR_PPDDATA, offsetof(PPDDATA, PSVersion)},
};
PUIINFO pUIInfo;
PPPDDATA pPpdData;
DWORD cIndex;
DWORD cTableEntry = sizeof(kGAInvocTable) / sizeof(GA_INVOC_ENTRY);
PGA_INVOC_ENTRY pEntry;
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
pEntry = (PGA_INVOC_ENTRY)(&kGAInvocTable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
(strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
{
//
// attribute name matches
//
PINVOCATION pInvoc;
if (pEntry->eADR == kADR_UIINFO)
{
pInvoc = (PINVOCATION)((PBYTE)pUIInfo + pEntry->cbOffset);
}
else if (pEntry->eADR == kADR_PPDDATA)
{
pInvoc = (PINVOCATION)((PBYTE)pPpdData + pEntry->cbOffset);
}
else
{
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGAInvocation: unknown eADR %d\n", pEntry->eADR));
return E_FAIL;
}
return HGetSingleData(OFFSET_TO_POINTER(pInfoHeader, pInvoc->loOffset),
kADT_BINARY, pInvoc->dwCount,
pdwDataType, pbData, cbSize, pcbNeeded);
}
}
//
// can't find the attribute
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGAInvocation: unknown attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
/*++
Routine Name:
HGetGAString
Routine Description:
get global ASCII string attribute
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute Get operation
pszAttribute - name of the global attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds
E_OUTOFMEMORY if output data buffer size is not big enough
Last Error:
None
--*/
HRESULT
HGetGAString(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef struct _GA_STRING_ENTRY {
PCSTR pszAttributeName; // attribute name
EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
DWORD cbOffset; // byte offset to the DWORD data
BOOL bCheckDWord; // TRUE to check the whole DWORD
// FALSE to check a bit in the DWORD
// (If bCheckDWord is TRUE, table look
// up will stop when first match is found.)
BOOL bCheckBitSet; // TRUE to check if the bit is set
// FALSE to check if the bit is cleared
// (this is ignored if bCheckDWord is TRUE)
DWORD dwFlag; // flag value
PCSTR pszValue; // registered value string
} GA_STRING_ENTRY, *PGA_STRING_ENTRY;
static const GA_STRING_ENTRY kGAStringTable[] =
{
{kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_DPS, "DPS"},
{kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_CMYK, "CMYK"},
{kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_COMPOSITE, "Composite"},
{kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_FILESYSTEM, "FileSystem"},
{kstrLSOrientation, kADR_UIINFO, offsetof(UIINFO, dwFlags), FALSE, TRUE, FLAG_ROTATE90, "Plus90"},
{kstrLSOrientation, kADR_UIINFO, offsetof(UIINFO, dwFlags), FALSE, FALSE, FLAG_ROTATE90, "Minus90"},
{kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_ISOLATIN1, "ISOLatin1"},
{kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_UNICODE, "Unicode"},
{kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_JIS83_RKSJ, "JIS83-RKSJ"},
{kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_NONE, "None"},
{kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_BCP, "BCP"},
{kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_PJL, "PJL"},
{kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_TBCP, "TBCP"},
{kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_SIC, "SIC"},
{kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_NONE, "None"},
{kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_ACCEPT68K, "Accept68K"},
{kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_TYPE42, "Type42"},
{kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_TRUEIMAGE, "TrueImage"},
};
PUIINFO pUIInfo;
PPPDDATA pPpdData;
PGA_STRING_ENTRY pEntry;
DWORD cTableEntry = sizeof(kGAStringTable) / sizeof(GA_STRING_ENTRY);
PSTR pCurrentOut;
DWORD cbNeeded, cIndex;
INT cbRemain;
if (pdwDataType)
{
*pdwDataType = kADT_ASCII;
}
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
pCurrentOut = (PSTR)pbData;
cbNeeded = 0;
cbRemain = (INT)cbSize;
pEntry = (PGA_STRING_ENTRY)(&kGAStringTable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
(strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
{
//
// attribute name matches
//
DWORD dwValue;
BOOL bMatch;
if (pEntry->eADR == kADR_UIINFO)
{
dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
}
else if (pEntry->eADR == kADR_PPDDATA)
{
dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
}
else
{
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGAString: unknown eADR %d\n", pEntry->eADR));
return E_FAIL;
}
if (pEntry->bCheckDWord)
{
//
// check the whole DWORD
//
bMatch = (dwValue == pEntry->dwFlag) ? TRUE : FALSE;
}
else
{
BOOL bBitIsSet;
//
// check the one bit in the DWORD
//
bBitIsSet = (dwValue & pEntry->dwFlag) ? TRUE : FALSE;
bMatch = (bBitIsSet == pEntry->bCheckBitSet ) ? TRUE : FALSE;
}
if (bMatch)
{
DWORD cbNameSize;
//
// count in the NUL delimiter
//
cbNameSize = strlen(pEntry->pszValue) + 1;
if (pCurrentOut && cbRemain >= (INT)cbNameSize)
{
CopyMemory(pCurrentOut, pEntry->pszValue, cbNameSize);
pCurrentOut += cbNameSize;
}
cbRemain -= cbNameSize;
cbNeeded += cbNameSize;
if (pEntry->bCheckDWord)
{
//
// stop table look up when first match is found if we are
// checking the whole DWORD instead of bits in the DWORD.
//
break;
}
}
}
}
//
// remember the the last NUL terminator for the MULTI_SZ output string
//
cbRemain--;
cbNeeded++;
if (pcbNeeded)
{
*pcbNeeded = cbNeeded;
}
if (!pCurrentOut || cbRemain < 0)
{
return E_OUTOFMEMORY;
}
*pCurrentOut = NUL;
return S_OK;
}
/*++
Routine Name:
HGetGADWord
Routine Description:
get global DWORD attribute
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute Get operation
pszAttribute - name of the global attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
E_INVALIDARG if the global attribute is not recognized
S_OK
E_OUTOFMEMORY see function HGetSingleData
Last Error:
None
--*/
HRESULT
HGetGADWord(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef struct _GA_DWORD_ENTRY {
PCSTR pszAttributeName; // attribute name
EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
DWORD cbOffset; // byte offset to the DWORD data
} GA_DWORD_ENTRY, *PGA_DWORD_ENTRY;
static const GA_DWORD_ENTRY kGADWordTable[] =
{
{kstrFileVersion, kADR_PPDDATA, offsetof(PPDDATA, dwPpdFilever)},
{kstrFreeVM, kADR_UIINFO, offsetof(UIINFO, dwFreeMem)},
{kstrLangLevel, kADR_UIINFO, offsetof(UIINFO, dwLangLevel)},
{kstrPPDAdobe, kADR_UIINFO, offsetof(UIINFO, dwSpecVersion)},
{kstrJobTimeout, kADR_UIINFO, offsetof(UIINFO, dwJobTimeout)},
{kstrWaitTimeout, kADR_UIINFO, offsetof(UIINFO, dwWaitTimeout)},
{kstrThroughput, kADR_UIINFO, offsetof(UIINFO, dwPrintRate)},
};
PUIINFO pUIInfo;
PPPDDATA pPpdData;
DWORD cIndex;
DWORD cTableEntry = sizeof(kGADWordTable) / sizeof(GA_DWORD_ENTRY);
PGA_DWORD_ENTRY pEntry;
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
pEntry = (PGA_DWORD_ENTRY)(&kGADWordTable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
(strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
{
//
// attribute name matches
//
DWORD dwValue;
if (pEntry->eADR == kADR_UIINFO)
{
dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
}
else if (pEntry->eADR == kADR_PPDDATA)
{
dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
}
else
{
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGADWord: unknown eADR %d\n", pEntry->eADR));
return E_FAIL;
}
return HGetSingleData((PVOID)&dwValue, kADT_DWORD, sizeof(DWORD),
pdwDataType, pbData, cbSize, pcbNeeded);
}
}
//
// can't find the attribute
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGADWord: unknown attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
/*++
Routine Name:
HGetGAUnicode
Routine Description:
get global Unicode string attribute
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute Get operation
pszAttribute - name of the global attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
E_INVALIDARG if the global attribute is not recognized
S_OK
E_OUTOFMEMORY see function HGetSingleData
Last Error:
None
--*/
HRESULT
HGetGAUnicode(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef struct _GA_UNICODE_ENTRY {
PCSTR pszAttributeName; // attribute name
EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
DWORD cbOffset; // byte offset to DWORD specifying
// offset to the UNICODE string
} GA_UNICODE_ENTRY, *PGA_UNICODE_ENTRY;
static const GA_UNICODE_ENTRY kGAUnicodeTable[] =
{
{kstrNickName, kADR_UIINFO, offsetof(UIINFO, loNickName)},
};
PUIINFO pUIInfo;
PPPDDATA pPpdData;
DWORD cIndex;
DWORD cTableEntry = sizeof(kGAUnicodeTable) / sizeof(GA_UNICODE_ENTRY);
PGA_UNICODE_ENTRY pEntry;
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
pEntry = (PGA_UNICODE_ENTRY)(&kGAUnicodeTable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
(strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
{
//
// attribute name matches
//
PTSTR ptstrString;
DWORD cbOffset;
if (pEntry->eADR == kADR_UIINFO)
{
cbOffset = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
}
else if (pEntry->eADR == kADR_PPDDATA)
{
cbOffset = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
}
else
{
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGAUnicode: unknown eADR %d\n", pEntry->eADR));
return E_FAIL;
}
ptstrString = OFFSET_TO_POINTER(pInfoHeader, cbOffset);
if (ptstrString == NULL)
{
return E_FAIL;
}
return HGetSingleData((PVOID)ptstrString, kADT_UNICODE, SIZE_OF_STRING(ptstrString),
pdwDataType, pbData, cbSize, pcbNeeded);
}
}
//
// can't find the attribute
//
// This shouldn't happen. It's here to catch our coding error.
//
RIP(("HGetGAUnicode: unknown attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
/*++
Routine Name:
HGetGlobalAttribute
Routine Description:
get PPD global attribute
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute get operation
pszAttribute - name of the global attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds
E_OUTOFMEMORY if output data buffer size is not big enough
E_INVALIDARG if the global attribute name is not recognized
Last Error:
None
--*/
HRESULT
HGetGlobalAttribute(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef HRESULT (*_HGET_GA_PROC)(
IN PINFOHEADER,
IN DWORD,
IN PCSTR,
OUT PDWORD,
OUT PBYTE,
IN DWORD,
OUT PDWORD);
typedef struct _GA_PROCESS_ENTRY {
PCSTR pszAttributeName; // attribute name
_HGET_GA_PROC pfnGetGAProc; // attribute handling proc
} GA_PROCESS_ENTRY, *PGA_PROCESS_ENTRY;
static const GA_PROCESS_ENTRY kGAProcTable[] =
{
{kstrCenterReg, HGetGABool},
{kstrColorDevice, HGetGABool},
{kstrExtensions, HGetGAString},
{kstrFileVersion, HGetGADWord},
{kstrFreeVM, HGetGADWord},
{kstrLSOrientation, HGetGAString},
{kstrLangEncoding, HGetGAString},
{kstrLangLevel, HGetGADWord},
{kstrNickName, HGetGAUnicode},
{kstrPPDAdobe, HGetGADWord},
{kstrPrintError, HGetGABool},
{kstrProduct, HGetGAInvocation},
{kstrProtocols, HGetGAString},
{kstrPSVersion, HGetGAInvocation},
{kstrJobTimeout, HGetGADWord},
{kstrWaitTimeout, HGetGADWord},
{kstrThroughput, HGetGADWord},
{kstrTTRasterizer, HGetGAString},
};
DWORD cIndex;
DWORD cTableEntry = sizeof(kGAProcTable) / sizeof(GA_PROCESS_ENTRY);
PGA_PROCESS_ENTRY pEntry;
if (!pszAttribute)
{
//
// Client is asking for the full list of supported global attribute names
//
PSTR pCurrentOut;
DWORD cbNeeded;
INT cbRemain;
if (pdwDataType)
{
*pdwDataType = kADT_ASCII;
}
pCurrentOut = (PSTR)pbData;
cbNeeded = 0;
cbRemain = (INT)cbSize;
pEntry = (PGA_PROCESS_ENTRY)(&kGAProcTable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
DWORD cbNameSize;
//
// count in the NUL between attribute keywords
//
cbNameSize = strlen(pEntry->pszAttributeName) + 1;
if (pCurrentOut && cbRemain >= (INT)cbNameSize)
{
CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize);
pCurrentOut += cbNameSize;
}
cbRemain -= cbNameSize;
cbNeeded += cbNameSize;
}
//
// remember the last NUL terminator for the MULTI_SZ output string
//
cbRemain--;
cbNeeded++;
if (pcbNeeded)
{
*pcbNeeded = cbNeeded;
}
if (!pCurrentOut || cbRemain < 0)
{
return E_OUTOFMEMORY;
}
*pCurrentOut = NUL;
return S_OK;
}
//
// Client does provide the global attribute name
//
pEntry = (PGA_PROCESS_ENTRY)(&kGAProcTable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
(strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
{
//
// attribute name matches
//
ASSERT(pEntry->pfnGetGAProc);
return (pEntry->pfnGetGAProc)(pInfoHeader,
dwFlags,
pszAttribute,
pdwDataType,
pbData,
cbSize,
pcbNeeded);
}
}
TERSE(("HGetGlobalAttribute: unknown global attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
/*++
Routine Name:
PGetOrderDepNode
Routine Description:
get the ORDERDEPEND strucutre associated with the specific feature/option
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
pPpdData - pointer to driver's PPDDATA structure
dwFeatureIndex - feature index
dwOptionIndex - option index (this could be OPTION_INDEX_ANY)
Return Value:
pointer to the ORDERDEPEND structure if succeeds
NULL otherwise
Last Error:
None
--*/
PORDERDEPEND
PGetOrderDepNode(
IN PINFOHEADER pInfoHeader,
IN PPPDDATA pPpdData,
IN DWORD dwFeatureIndex,
IN DWORD dwOptionIndex
)
{
PORDERDEPEND pOrder;
DWORD cIndex;
pOrder = (PORDERDEPEND)OFFSET_TO_POINTER(&(pInfoHeader->RawData),
pPpdData->OrderDeps.loOffset);
ASSERT(pOrder != NULL || pPpdData->OrderDeps.dwCount == 0);
if (pOrder == NULL)
{
return NULL;
}
for (cIndex = 0; cIndex < pPpdData->OrderDeps.dwCount; cIndex++, pOrder++)
{
if (pOrder->dwSection == SECTION_UNASSIGNED)
continue;
if (pOrder->dwFeatureIndex == dwFeatureIndex &&
pOrder->dwOptionIndex == dwOptionIndex)
{
return pOrder;
}
}
return NULL;
}
/*++
Routine Name:
HGetOrderDepSection
Routine Description:
get order dependency section name
Arguments:
pOrder - pointer to the ORDERDEPEND structure
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK
E_OUTOFMEMORY see function HGetSingleData
Last Error:
None
--*/
HRESULT
HGetOrderDepSection(
IN PORDERDEPEND pOrder,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
static const CHAR kpstrSections[][20] =
{
"DocumentSetup",
"PageSetup",
"Prolog",
"ExitServer",
"JCLSetup",
"AnySetup"
};
DWORD dwSectIndex;
ASSERT(pOrder);
switch (pOrder->dwPPDSection)
{
case SECTION_DOCSETUP:
dwSectIndex = 0;
break;
case SECTION_PAGESETUP:
dwSectIndex = 1;
break;
case SECTION_PROLOG:
dwSectIndex = 2;
break;
case SECTION_EXITSERVER:
dwSectIndex = 3;
break;
case SECTION_JCLSETUP:
dwSectIndex = 4;
break;
case SECTION_ANYSETUP:
default:
dwSectIndex = 5;
break;
}
return HGetSingleData((PVOID)kpstrSections[dwSectIndex], kADT_ASCII,
strlen(kpstrSections[dwSectIndex]) + 1,
pdwDataType, pbData, cbSize, pcbNeeded);
}
/*++
Routine Name:
HGetFeatureAttribute
Routine Description:
get PPD feature attribute
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute get operation
pszFeatureKeyword - PPD feature keyword name
pszAttribute - name of the feature attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds
E_OUTOFMEMORY if output data buffer size is not big enough
E_INVALIDARG if feature keyword name or attribute name is not recognized
Last Error:
None
--*/
HRESULT
HGetFeatureAttribute(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszFeatureKeyword,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef struct _FA_ENTRY {
PCSTR pszAttributeName; // feature attribute name
BOOL bNeedOrderDepNode; // TRUE if the attribute only exist
// when the feature has an *OrderDependency
// entry in PPD, FALSE otherwise.
} FA_ENTRY, *PFA_ENTRY;
static const FA_ENTRY kFATable[] =
{
{kstrDisplayName, FALSE},
{kstrDefOption, FALSE},
{kstrOpenUIType, FALSE},
{kstrOpenGroupType, FALSE},
{kstrOrderDepValue, TRUE},
{kstrOrderDepSect, TRUE},
};
PUIINFO pUIInfo;
PPPDDATA pPpdData;
PFEATURE pFeature;
PORDERDEPEND pOrder;
DWORD dwFeatureIndex;
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
if (!pszFeatureKeyword ||
(pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL)
{
ERR(("HGetFeatureAttribute: invalid feature\n"));
return E_INVALIDARG;
}
pOrder = PGetOrderDepNode(pInfoHeader, pPpdData, dwFeatureIndex, OPTION_INDEX_ANY);
if (!pszAttribute)
{
//
// Client is asking for the full list of supported feature attribute names
//
PFA_ENTRY pEntry;
DWORD cIndex;
DWORD cTableEntry = sizeof(kFATable) / sizeof(FA_ENTRY);
PSTR pCurrentOut;
DWORD cbNeeded;
INT cbRemain;
if (pdwDataType)
{
*pdwDataType = kADT_ASCII;
}
pCurrentOut = (PSTR)pbData;
cbNeeded = 0;
cbRemain = (INT)cbSize;
pEntry = (PFA_ENTRY)(&kFATable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
DWORD cbNameSize;
//
// If the attribute only exist when the feature has an *OrderDependency entry in PPD,
// but we didn't find the feature's pOrder node, skip it.
//
if (pEntry->bNeedOrderDepNode && !pOrder)
continue;
//
// count in the NUL between attribute keywords
//
cbNameSize = strlen(pEntry->pszAttributeName) + 1;
if (pCurrentOut && cbRemain >= (INT)cbNameSize)
{
CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize);
pCurrentOut += cbNameSize;
}
cbRemain -= cbNameSize;
cbNeeded += cbNameSize;
}
//
// remember the last NUL terminator for the MULTI_SZ output string
//
cbRemain--;
cbNeeded++;
if (pcbNeeded)
{
*pcbNeeded = cbNeeded;
}
if (!pCurrentOut || cbRemain < 0)
{
return E_OUTOFMEMORY;
}
*pCurrentOut = NUL;
return S_OK;
}
//
// Client does provide the feature attribute name
//
if ((*pszAttribute == kstrDisplayName[0]) &&
(strcmp(pszAttribute, kstrDisplayName) == EQUAL_STRING))
{
PTSTR ptstrDispName;
ptstrDispName = OFFSET_TO_POINTER(pInfoHeader, pFeature->loDisplayName);
if (ptstrDispName == NULL)
{
return E_FAIL;
}
return HGetSingleData((PVOID)ptstrDispName, kADT_UNICODE, SIZE_OF_STRING(ptstrDispName),
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrDefOption[0]) &&
(strcmp(pszAttribute, kstrDefOption) == EQUAL_STRING))
{
POPTION pOption;
PSTR pstrKeywordName;
pOption = PGetIndexedOption(pUIInfo, pFeature, pFeature->dwDefaultOptIndex);
if (!pOption)
{
ERR(("HGetFeatureAttribute: can't find default option. Use the first one.\n"));
pOption = PGetIndexedOption(pUIInfo, pFeature, 0);
if (!pOption)
{
return E_FAIL;
}
}
pstrKeywordName = OFFSET_TO_POINTER(pInfoHeader, pOption->loKeywordName);
return HGetSingleData((PVOID)pstrKeywordName, kADT_ASCII, strlen(pstrKeywordName) + 1,
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrOpenUIType[0]) &&
(strcmp(pszAttribute, kstrOpenUIType) == EQUAL_STRING))
{
static const CHAR pstrUITypes[][10] =
{
"PickOne",
"PickMany",
"Boolean"
};
DWORD dwType = pFeature->dwUIType;
if (dwType > UITYPE_BOOLEAN)
{
RIP(("HGetFeatureAttribute: invalid UIType %d\n", dwType));
dwType = 0;
}
return HGetSingleData((PVOID)pstrUITypes[dwType], kADT_ASCII,
strlen(pstrUITypes[dwType]) + 1,
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrOpenGroupType[0]) &&
(strcmp(pszAttribute, kstrOpenGroupType) == EQUAL_STRING))
{
static const CHAR pstrGroupTypes[][30] =
{
"InstallableOptions",
""
};
DWORD dwType;
dwType = (pFeature->dwFeatureType == FEATURETYPE_PRINTERPROPERTY) ? 0 : 1;
return HGetSingleData((PVOID)pstrGroupTypes[dwType], kADT_ASCII,
strlen(pstrGroupTypes[dwType]) + 1,
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrOrderDepValue[0]) &&
(strcmp(pszAttribute, kstrOrderDepValue) == EQUAL_STRING))
{
if (!pOrder)
{
TERSE(("HGetFeatureAttribute: attribute %s not available\n", pszAttribute));
return E_INVALIDARG;
}
return HGetSingleData((PVOID)&(pOrder->lOrder), kADT_LONG, sizeof(LONG),
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrOrderDepSect[0]) &&
(strcmp(pszAttribute, kstrOrderDepSect) == EQUAL_STRING))
{
if (!pOrder)
{
TERSE(("HGetFeatureAttribute: attribute %s not available\n", pszAttribute));
return E_INVALIDARG;
}
return HGetOrderDepSection(pOrder, pdwDataType, pbData, cbSize, pcbNeeded);
}
else
{
TERSE(("HGetFeatureAttribute: unknown feature attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
}
/*++
Routine Name:
HGetOptionAttribute
Routine Description:
get option attribute of a PPD feature
Arguments:
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the attribute get operation
pszFeatureKeyword - PPD feature keyword name
pszOptionKeyword - option keyword name of the PPD feature
pszAttribute - name of the feature attribute
pdwDataType - pointer to DWORD to store output data type
pbData - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds
E_OUTOFMEMORY if output data buffer size is not big enough
E_INVALIDARG if feature keyword name, or option keyword name,
or attribute name is not recognized
Last Error:
None
--*/
HRESULT
HGetOptionAttribute(
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszFeatureKeyword,
IN PCSTR pszOptionKeyword,
IN PCSTR pszAttribute,
OUT PDWORD pdwDataType,
OUT PBYTE pbData,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
typedef struct _OA_ENTRY {
PCSTR pszFeatureKeyword; // feature keyword name
// (NULL for non-feature specific attributes)
PCSTR pszOptionKeyword; // option keyword name
// (NULL for non-option specific attributes)
PCSTR pszAttributeName; // option attribute name (this field must be
// unique across the table)
BOOL bNeedOrderDepNode; // TRUE if the attribute only exist
// when the option has an *OrderDependency
// entry in PPD, FALSE otherwise.
BOOL bSpecialHandle; // TRUE if the attribute needs special handling.
// If TRUE, following table fields are not used.
DWORD dwDataType; // data type of the attribute value
DWORD cbNeeded; // byte count of the attribute value
DWORD cbOffset; // byte offset to the attribute value, starting
// from the beginning of OPTION structure
} OA_ENTRY, *POA_ENTRY;
static const OA_ENTRY kOATable[] =
{
{NULL, NULL, kstrDisplayName, FALSE, TRUE, 0, 0, 0},
{NULL, NULL, kstrInvocation, FALSE, TRUE, 0, 0, 0},
{NULL, NULL, kstrOrderDepValue, TRUE, TRUE, 0, 0, 0},
{NULL, NULL, kstrOrderDepSect, TRUE, TRUE, 0, 0, 0},
{kstrInputSlot, NULL, kstrReqPageRgn, FALSE, TRUE, 0, 0, 0},
{kstrOutputBin, NULL, kstrOutOrderRev, FALSE, FALSE, kADT_BOOL, sizeof(BOOL), offsetof(OUTPUTBIN, bOutputOrderReversed)},
{kstrPageSize, NULL, kstrPaperDim, FALSE, FALSE, kADT_SIZE, sizeof(SIZE), offsetof(PAGESIZE, szPaperSize)},
{kstrPageSize, NULL, kstrImgArea, FALSE, TRUE, 0, 0, 0},
{kstrPageSize, kstrCustomPS, kstrParamCustomPS, FALSE, TRUE, 0, 0, 0},
{kstrPageSize, kstrCustomPS, kstrHWMargins, FALSE, FALSE, kADT_RECT, sizeof(RECT), offsetof(PAGESIZE, rcImgArea)},
{kstrPageSize, kstrCustomPS, kstrMaxMWidth, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(PAGESIZE, szPaperSize) + offsetof(SIZE, cx)},
{kstrPageSize, kstrCustomPS, kstrMaxMHeight, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(PAGESIZE, szPaperSize) + offsetof(SIZE, cy)},
{kstrInstalledMem, NULL, kstrVMOption, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(MEMOPTION, dwInstalledMem)},
{kstrInstalledMem, NULL, kstrFCacheSize, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(MEMOPTION, dwFreeFontMem)},
};
PUIINFO pUIInfo;
PPPDDATA pPpdData;
PFEATURE pFeature;
POPTION pOption;
PORDERDEPEND pOrder;
DWORD dwFeatureIndex, dwOptionIndex, cIndex;
DWORD cTableEntry = sizeof(kOATable) / sizeof(OA_ENTRY);
POA_ENTRY pEntry;
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
if (!pszFeatureKeyword ||
(pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL)
{
ERR(("HGetOptionAttribute: invalid feature\n"));
return E_INVALIDARG;
}
if (!pszOptionKeyword ||
(pOption = PGetNamedOption(pUIInfo, pFeature, pszOptionKeyword, &dwOptionIndex)) == NULL)
{
ERR(("HGetOptionAttribute: invalid option\n"));
return E_INVALIDARG;
}
pOrder = PGetOrderDepNode(pInfoHeader, pPpdData, dwFeatureIndex, dwOptionIndex);
if (!pszAttribute)
{
//
// Client is asking for the full list of supported option attribute names
//
PSTR pCurrentOut;
DWORD cbNeeded;
INT cbRemain;
if (pdwDataType)
{
*pdwDataType = kADT_ASCII;
}
pCurrentOut = (PSTR)pbData;
cbNeeded = 0;
cbRemain = (INT)cbSize;
pEntry = (POA_ENTRY)(&kOATable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
DWORD cbNameSize;
//
// If the attribute is specific to a certain feature, check the feature keyword match.
//
if (pEntry->pszFeatureKeyword &&
(strcmp(pEntry->pszFeatureKeyword, pszFeatureKeyword) != EQUAL_STRING))
continue;
//
// If the attribute is specific to a certain option, check the option keyword match.
//
if (pEntry->pszOptionKeyword &&
(strcmp(pEntry->pszOptionKeyword, pszOptionKeyword) != EQUAL_STRING))
continue;
//
// special case: For PageSize's CustomPageSize option, we need to skip attributes
// that are only available to PageSize's all non-CustomPageSize options.
//
if (pEntry->pszFeatureKeyword &&
!pEntry->pszOptionKeyword &&
(pFeature->dwFeatureID == GID_PAGESIZE) &&
(((PPAGESIZE)pOption)->dwPaperSizeID == DMPAPER_CUSTOMSIZE))
continue;
//
// If the attribute only exist when the option has an *OrderDependency entry in PPD,
// but we didn't find the option's pOrder node, skip it.
//
if (pEntry->bNeedOrderDepNode && !pOrder)
continue;
//
// count in the NUL between attribute keywords
//
cbNameSize = strlen(pEntry->pszAttributeName) + 1;
if (pCurrentOut && cbRemain >= (INT)cbNameSize)
{
CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize);
pCurrentOut += cbNameSize;
}
cbRemain -= cbNameSize;
cbNeeded += cbNameSize;
}
//
// remember the last NUL terminator for the MULTI_SZ output string.
//
cbRemain--;
cbNeeded++;
if (pcbNeeded)
{
*pcbNeeded = cbNeeded;
}
if (!pCurrentOut || cbRemain < 0)
{
return E_OUTOFMEMORY;
}
*pCurrentOut = NUL;
return S_OK;
}
//
// Client does provide the option attribute name
//
//
// First handle a few special cases (bSpecialHandle == TRUE in the table).
// Generic case handling is in the last else-part.
//
if ((*pszAttribute == kstrDisplayName[0]) &&
(strcmp(pszAttribute, kstrDisplayName) == EQUAL_STRING))
{
//
// "DisplayName"
//
PTSTR ptstrDispName;
ptstrDispName = OFFSET_TO_POINTER(pInfoHeader, pOption->loDisplayName);
if (ptstrDispName == NULL)
{
return E_FAIL;
}
return HGetSingleData((PVOID)ptstrDispName, kADT_UNICODE, SIZE_OF_STRING(ptstrDispName),
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrInvocation[0]) &&
(strcmp(pszAttribute, kstrInvocation) == EQUAL_STRING))
{
//
// "Invocation"
//
return HGetSingleData(OFFSET_TO_POINTER(pInfoHeader, pOption->Invocation.loOffset),
kADT_BINARY, pOption->Invocation.dwCount,
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrOrderDepValue[0]) &&
(strcmp(pszAttribute, kstrOrderDepValue) == EQUAL_STRING))
{
//
// "OrderDependencyValue"
//
if (!pOrder)
{
TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
return E_INVALIDARG;
}
return HGetSingleData((PVOID)&(pOrder->lOrder), kADT_LONG, sizeof(LONG),
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrOrderDepSect[0]) &&
(strcmp(pszAttribute, kstrOrderDepSect) == EQUAL_STRING))
{
//
// "OrderDependencySection"
//
if (!pOrder)
{
TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
return E_INVALIDARG;
}
return HGetOrderDepSection(pOrder, pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrReqPageRgn[0]) &&
(strcmp(pszAttribute, kstrReqPageRgn) == EQUAL_STRING))
{
//
// "RequiresPageRegion"
//
PINPUTSLOT pInputSlot = (PINPUTSLOT)pOption;
BOOL bValue;
//
// This attribute is only available to *InputSlot options, excluding the first
// one "*UseFormTrayTable", which is synthesized by PPD parser.
//
if (pFeature->dwFeatureID != GID_INPUTSLOT ||
(dwOptionIndex == 0 && pInputSlot->dwPaperSourceID == DMBIN_FORMSOURCE))
{
TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
return E_INVALIDARG;
}
bValue = (pInputSlot->dwFlags & INPUTSLOT_REQ_PAGERGN) ? TRUE : FALSE;
return HGetSingleData((PVOID)&bValue, kADT_BOOL, sizeof(BOOL),
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrImgArea[0]) &&
(strcmp(pszAttribute, kstrImgArea) == EQUAL_STRING))
{
//
// "ImageableArea"
//
PPAGESIZE pPageSize = (PPAGESIZE)pOption;
RECT rcImgArea;
//
// This attribute is only available to *PageSize options, excluding CustomPageSize option.
//
if (pFeature->dwFeatureID != GID_PAGESIZE || pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE)
{
TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
return E_INVALIDARG;
}
//
// convert GDI coordinate system back to PS coordinate system
// (see VPackPrinterFeatures() case GID_PAGESIZE)
//
rcImgArea.left = pPageSize->rcImgArea.left;
rcImgArea.right = pPageSize->rcImgArea.right;
rcImgArea.top = pPageSize->szPaperSize.cy - pPageSize->rcImgArea.top;
rcImgArea.bottom = pPageSize->szPaperSize.cy - pPageSize->rcImgArea.bottom;
return HGetSingleData((PVOID)&rcImgArea, kADT_RECT, sizeof(RECT),
pdwDataType, pbData, cbSize, pcbNeeded);
}
else if ((*pszAttribute == kstrParamCustomPS[0]) &&
(strcmp(pszAttribute, kstrParamCustomPS) == EQUAL_STRING))
{
//
// "ParamCustomPageSize"
//
PPAGESIZE pPageSize = (PPAGESIZE)pOption;
//
// This attribute is only available to *PageSize feature's CustomPageSize option.
//
if (pFeature->dwFeatureID != GID_PAGESIZE || pPageSize->dwPaperSizeID != DMPAPER_CUSTOMSIZE)
{
TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
return E_INVALIDARG;
}
return HGetSingleData((PVOID)(pPpdData->CustomSizeParams),
kADT_CUSTOMSIZEPARAMS, sizeof(pPpdData->CustomSizeParams),
pdwDataType, pbData, cbSize, pcbNeeded);
}
else
{
//
// generic case handling
//
pEntry = (POA_ENTRY)(&kOATable[0]);
for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
{
//
// skip any entry that has already been specially handled
//
if (pEntry->bSpecialHandle)
continue;
ASSERT(pEntry->bNeedOrderDepNode == FALSE);
if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
(strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
{
//
// Attribute name matches. We still need to verify feature/option keyword match.
//
if (pEntry->pszFeatureKeyword &&
strcmp(pEntry->pszFeatureKeyword, pszFeatureKeyword) != EQUAL_STRING)
{
TERSE(("HGetOptionAttribute: feature keyword mismatch for attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
if (pEntry->pszOptionKeyword &&
(strcmp(pEntry->pszOptionKeyword, pszOptionKeyword) != EQUAL_STRING))
{
TERSE(("HGetOptionAttribute: option keyword mismatch for attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
//
// special case: For PageSize's CustomPageSize option, we need to skip attributes
// that are only available to PageSize's all non-CustomPageSize options.
//
if (pEntry->pszFeatureKeyword &&
!pEntry->pszOptionKeyword &&
(pFeature->dwFeatureID == GID_PAGESIZE) &&
(((PPAGESIZE)pOption)->dwPaperSizeID == DMPAPER_CUSTOMSIZE))
continue;
return HGetSingleData((PVOID)((PBYTE)pOption + pEntry->cbOffset),
pEntry->dwDataType, pEntry->cbNeeded,
pdwDataType, pbData, cbSize, pcbNeeded);
}
}
TERSE(("HGetOptionAttribute: unknown option attribute %s\n", pszAttribute));
return E_INVALIDARG;
}
}
/*++
Routine Name:
BIsSupported_PSF
Routine Description:
determine if the PS driver synthesized feature is supported or not
Arguments:
pszFeature - name of the PS driver synthesized feature
pUIInfo - pointer to driver's UIINFO structure
pPpdData - pointer to driver's PPDDATA structure
bEMFSpooling - whether spooler EMF spooling is enabled or not
Return Value:
TRUE if the feature is currently supported
FALSE otherwise
Last Error:
None
--*/
BOOL
BIsSupported_PSF(
IN PCSTR pszFeature,
IN PUIINFO pUIInfo,
IN PPPDDATA pPpdData,
IN BOOL bEMFSpooling
)
{
#ifdef WINNT_40
//
// On NT4, bEMFSpooling should always be FALSE.
//
ASSERT(!bEMFSpooling);
#endif // WINNT_40
//
// Note that the first character is always the % prefix.
//
if ((pszFeature[1] == kstrPSFAddEuro[1]) &&
(strcmp(pszFeature, kstrPSFAddEuro) == EQUAL_STRING))
{
//
// AddEuro is only supported for Level 2+ printers.
//
return(pUIInfo->dwLangLevel >= 2);
}
else if ((pszFeature[1] == kstrPSFEMF[1]) &&
(strcmp(pszFeature, kstrPSFEMF) == EQUAL_STRING))
{
//
// Driver EMF is always supported on NT4, and only supported
// when spooler EMF is enabled on Win2K+.
//
#ifndef WINNT_40
return bEMFSpooling;
#else
return TRUE;
#endif // !WINNT_40
}
else if ((pszFeature[1] == kstrPSFNegative[1]) &&
(strcmp(pszFeature, kstrPSFNegative) == EQUAL_STRING))
{
//
// Negative is only supported for b/w printers.
//
return(IS_COLOR_DEVICE(pUIInfo) ? FALSE : TRUE);
}
else if ((pszFeature[1] == kstrPSFPageOrder[1]) &&
(strcmp(pszFeature, kstrPSFPageOrder) == EQUAL_STRING))
{
//
// PageOrder is not supported on NT4, and is only supported
// when spooler EMF is enabled on Win2K+.
//
return bEMFSpooling;
}
else
{
return TRUE;
}
}
/*++
Routine Name:
HEnumFeaturesOrOptions
Routine Description:
enumerate the feature or option keyword name list
Arguments:
hPrinter - printer handle
pInfoHeader - pointer to driver's INFOHEADER structure
dwFlags - flags for the enumeration operation
pszFeatureKeyword - feature keyword name. This should be NULL
for feature enumeration and non-NULL for
option enumeration.
pmszOutputList - pointer to output data buffer
cbSize - output data buffer size in bytes
pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds
E_OUTOFMEMORY if output data buffer size is not big enough
E_INVALIDARG if for option enumeration, feature keyword name is
not recognized
E_NOTIMPL if being called to enumerate options of PS driver
synthesized feature that is not currently supported or
whose options are not enumerable
E_FAIL if other internal failures are encountered
Last Error:
None
--*/
HRESULT
HEnumFeaturesOrOptions(
IN HANDLE hPrinter,
IN PINFOHEADER pInfoHeader,
IN DWORD dwFlags,
IN PCSTR pszFeatureKeyword,
OUT PSTR pmszOutputList,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
{
PUIINFO pUIInfo;
PPPDDATA pPpdData;
PFEATURE pFeature;
POPTION pOption;
DWORD cIndex, cPPDFeaturesOrOptions;
BOOL bEnumFeatures, bEnumPPDOptions;
PSTR pCurrentOut;
DWORD cbNeeded;
INT cbRemain;
BOOL bEMFSpooling;
PPSFEATURE_ENTRY pEntry;
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pUIInfo == NULL || pPpdData == NULL)
{
return E_FAIL;
}
pCurrentOut = pmszOutputList;
cbNeeded = 0;
cbRemain = (INT)cbSize;
bEnumFeatures = pszFeatureKeyword ? FALSE : TRUE;
bEnumPPDOptions = TRUE;
if (bEnumFeatures)
{
//
// Enumerate driver synthersized features first.
//
VGetSpoolerEmfCaps(hPrinter, NULL, &bEMFSpooling, 0, NULL);
pEntry = (PPSFEATURE_ENTRY)(&kPSFeatureTable[0]);
while (pEntry->pszPSFeatureName)
{
if (BIsSupported_PSF(pEntry->pszPSFeatureName, pUIInfo, pPpdData, bEMFSpooling))
{
DWORD cbNameLen;
cbNameLen = strlen(pEntry->pszPSFeatureName) + 1;
if (pCurrentOut && cbRemain >= (INT)cbNameLen)
{
CopyMemory(pCurrentOut, pEntry->pszPSFeatureName, cbNameLen);
pCurrentOut += cbNameLen;
}
cbRemain -= cbNameLen;
cbNeeded += cbNameLen;
}
pEntry++;
}
}
else
{
if (*pszFeatureKeyword == PSFEATURE_PREFIX)
{
bEnumPPDOptions = FALSE;
VGetSpoolerEmfCaps(hPrinter, NULL, &bEMFSpooling, 0, NULL);
if (!BIsSupported_PSF(pszFeatureKeyword, pUIInfo, pPpdData, bEMFSpooling))
{
WARNING(("HEnumFeaturesOrOptions: feature %s is not supported\n", pszFeatureKeyword));
return E_NOTIMPL;
}
}
}
if (bEnumFeatures)
{
cPPDFeaturesOrOptions = pUIInfo->dwDocumentFeatures + pUIInfo->dwPrinterFeatures;
pFeature = OFFSET_TO_POINTER(pInfoHeader, pUIInfo->loFeatureList);
ASSERT(cPPDFeaturesOrOptions == 0 || pFeature != NULL);
if (pFeature == NULL)
{
return E_FAIL;
}
}
else if (bEnumPPDOptions)
{
DWORD dwFeatureIndex;
pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex);
if (!pFeature)
{
ERR(("HEnumFeaturesOrOptions: unrecognized feature %s\n", pszFeatureKeyword));
return E_INVALIDARG;
}
cPPDFeaturesOrOptions = pFeature->Options.dwCount;
pOption = OFFSET_TO_POINTER(pInfoHeader, pFeature->Options.loOffset);
ASSERT(cPPDFeaturesOrOptions == 0 || pOption != NULL);
if (pOption == NULL)
{
return E_FAIL;
}
}
else
{
//
// Enum driver synthersized feature's options.
//
pEntry = (PPSFEATURE_ENTRY)(&kPSFeatureTable[0]);
while (pEntry->pszPSFeatureName)
{
if ((*pszFeatureKeyword == *(pEntry->pszPSFeatureName)) &&
strcmp(pszFeatureKeyword, pEntry->pszPSFeatureName) == EQUAL_STRING)
{
if (!pEntry->bEnumerableOptions)
{
//
// This driver feature doesn't support option enumeration.
//
WARNING(("HEnumFeaturesOrOptions: enum options not supported for %s\n", pszFeatureKeyword));
return E_NOTIMPL;
}
if (pEntry->bBooleanOptions)
{
//
// This driver feature has True/False boolean options.
//
DWORD cbKwdTrueSize, cbKwdFalseSize;
cbKwdTrueSize = strlen(kstrKwdTrue) + 1;
cbKwdFalseSize = strlen(kstrKwdFalse) + 1;
if (pCurrentOut && (cbRemain >= (INT)(cbKwdTrueSize + cbKwdFalseSize)))
{
CopyMemory(pCurrentOut, kstrKwdTrue, cbKwdTrueSize);
pCurrentOut += cbKwdTrueSize;
CopyMemory(pCurrentOut, kstrKwdFalse, cbKwdFalseSize);
pCurrentOut += cbKwdFalseSize;
}
cbRemain -= (cbKwdTrueSize + cbKwdFalseSize);
cbNeeded += cbKwdTrueSize + cbKwdFalseSize;
}
else
{
//
// This driver feature needs special handler to enumerate its options.
//
if (pEntry->pfnPSProc)
{
DWORD cbPSFOptionsSize;
BOOL bResult;
bResult = (pEntry->pfnPSProc)(hPrinter,
pUIInfo,
pPpdData,
NULL,
NULL,
pszFeatureKeyword,
NULL,
pCurrentOut,
cbRemain,
&cbPSFOptionsSize,
PSFPROC_ENUMOPTION_MODE);
if (bResult)
{
pCurrentOut += cbPSFOptionsSize;
}
else
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
ERR(("HEnumFeaturesOrOptions: enum options failed for %s\n", pszFeatureKeyword));
return E_FAIL;
}
}
cbRemain -= cbPSFOptionsSize;
cbNeeded += cbPSFOptionsSize;
}
else
{
RIP(("HEnumFeaturesOrOptions: %%-feature handle is NULL for %s\n", pszFeatureKeyword));
return E_FAIL;
}
}
break;
}
pEntry++;
}
if (pEntry->pszPSFeatureName == NULL)
{
ERR(("HEnumFeaturesOrOptions: unrecognized feature %s\n", pszFeatureKeyword));
return E_INVALIDARG;
}
cPPDFeaturesOrOptions = 0;
}
for (cIndex = 0; cIndex < cPPDFeaturesOrOptions; cIndex++)
{
//
// Now enumerate PPD features/options.
//
PSTR pszKeyword;
DWORD cbKeySize;
if (bEnumFeatures)
{
pszKeyword = OFFSET_TO_POINTER(pInfoHeader, pFeature->loKeywordName);
}
else
{
pszKeyword = OFFSET_TO_POINTER(pInfoHeader, pOption->loKeywordName);
}
if (pszKeyword == NULL)
{
ASSERT(pszKeyword != NULL);
return E_FAIL;
}
//
// count in the NUL character between feature/option keywords
//
cbKeySize = strlen(pszKeyword) + 1;
if (pCurrentOut && cbRemain >= (INT)cbKeySize)
{
CopyMemory(pCurrentOut, pszKeyword, cbKeySize);
pCurrentOut += cbKeySize;
}
cbRemain -= cbKeySize;
cbNeeded += cbKeySize;
if (bEnumFeatures)
{
pFeature++;
}
else
{
pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize);
}
}
//
// remember the last NUL terminator for the MULTI_SZ output string
//
cbRemain--;
cbNeeded++;
if (pcbNeeded)
{
*pcbNeeded = cbNeeded;
}
if (!pCurrentOut || cbRemain < 0)
{
return E_OUTOFMEMORY;
}
*pCurrentOut = NUL;
return S_OK;
}