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
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;
|
|
}
|