520 lines
13 KiB
C
520 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
quryprnt.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file handles the DrvQueryPrintEx spooler API
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Win32 subsystem, DriverUI module, user mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
02/13/97 -davidx-
|
|||
|
Implement OEM plugin support.
|
|||
|
|
|||
|
02/08/97 -davidx-
|
|||
|
Rewrote it to use common data management functions.
|
|||
|
|
|||
|
02/04/97 -davidx-
|
|||
|
Reorganize driver UI to separate ps and uni DLLs.
|
|||
|
|
|||
|
07/17/96 -amandan-
|
|||
|
Created it.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Forward declaration of local functions
|
|||
|
//
|
|||
|
|
|||
|
BOOL BFormatDQPMessage(PDEVQUERYPRINT_INFO, INT, ...);
|
|||
|
BOOL BQueryPrintDevmode(PDEVQUERYPRINT_INFO, PCOMMONINFO);
|
|||
|
BOOL BQueryPrintForm(PDEVQUERYPRINT_INFO, PCOMMONINFO);
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DevQueryPrintEx(
|
|||
|
PDEVQUERYPRINT_INFO pDQPInfo
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function checks whether the job can be printed with
|
|||
|
DEVMODE passed in. This function will use the following
|
|||
|
criterias to determine whether the job is printable:
|
|||
|
- get basic printer information
|
|||
|
- verify input devmode
|
|||
|
- verify resolution is supported
|
|||
|
- verify there is no conflicts between printer feature selections
|
|||
|
- verify form-to-tray assignment
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the job can be printed with the given DEVMODE, otherwise FALSE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCOMMONINFO pci;
|
|||
|
BOOL bResult;
|
|||
|
|
|||
|
if (pDQPInfo == NULL || pDQPInfo->hPrinter == NULL)
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_PARAM);
|
|||
|
|
|||
|
if (pDQPInfo->pDevMode == NULL)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
if ((pci = PLoadCommonInfo(pDQPInfo->hPrinter, NULL, 0)) == NULL)
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_COMMONINFO);
|
|||
|
|
|||
|
bResult = BQueryPrintDevmode(pDQPInfo, pci) &&
|
|||
|
BQueryPrintForm(pDQPInfo, pci);
|
|||
|
|
|||
|
if (bResult)
|
|||
|
{
|
|||
|
PFN_OEMDevQueryPrintEx pfnOEMDevQueryPrintEx;
|
|||
|
|
|||
|
//
|
|||
|
// call OEMDevQueryPrintEx entrypoint for each plugin,
|
|||
|
// or until one of them returns FALSE.
|
|||
|
//
|
|||
|
|
|||
|
FOREACH_OEMPLUGIN_LOOP(pci)
|
|||
|
|
|||
|
if (HAS_COM_INTERFACE(pOemEntry))
|
|||
|
{
|
|||
|
HRESULT hr;
|
|||
|
|
|||
|
hr = HComOEMDevQueryPrintEx(pOemEntry,
|
|||
|
&pci->oemuiobj,
|
|||
|
pDQPInfo,
|
|||
|
pci->pdm,
|
|||
|
pOemEntry->pOEMDM);
|
|||
|
if (hr == E_NOTIMPL)
|
|||
|
continue;
|
|||
|
|
|||
|
if (!(bResult = SUCCEEDED(hr)))
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ((pfnOEMDevQueryPrintEx = GET_OEM_ENTRYPOINT(pOemEntry, OEMDevQueryPrintEx)) &&
|
|||
|
!pfnOEMDevQueryPrintEx(&pci->oemuiobj, pDQPInfo, pci->pdm, pOemEntry->pOEMDM))
|
|||
|
{
|
|||
|
ERR(("OEMDevQueryPrintEx failed for '%ws': %d\n",
|
|||
|
CURRENT_OEM_MODULE_NAME(pOemEntry),
|
|||
|
GetLastError()));
|
|||
|
|
|||
|
bResult = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
END_OEMPLUGIN_LOOP
|
|||
|
}
|
|||
|
|
|||
|
VFreeCommonInfo(pci);
|
|||
|
return bResult;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
BFormatDQPMessage(
|
|||
|
PDEVQUERYPRINT_INFO pDQPInfo,
|
|||
|
INT iMsgResId,
|
|||
|
...
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Format DevQueryPrintEx error message
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
|
|||
|
iMsgResId - Error message format specifier (string resource ID)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#define MAX_FORMAT_STRING 256
|
|||
|
#define MAX_DQP_MESSAGE 512
|
|||
|
|
|||
|
{
|
|||
|
TCHAR awchFormat[MAX_FORMAT_STRING];
|
|||
|
TCHAR awchMessage[MAX_DQP_MESSAGE];
|
|||
|
INT iLength;
|
|||
|
va_list arglist;
|
|||
|
|
|||
|
//
|
|||
|
// Load the format specifier string resource
|
|||
|
// and use swprintf to format the error message
|
|||
|
//
|
|||
|
|
|||
|
va_start(arglist, iMsgResId);
|
|||
|
|
|||
|
if (! LoadString(ghInstance, iMsgResId, awchFormat, MAX_FORMAT_STRING))
|
|||
|
awchFormat[0] = NUL;
|
|||
|
|
|||
|
iLength = vswprintf(awchMessage, awchFormat, arglist);
|
|||
|
|
|||
|
if (iLength <= 0)
|
|||
|
{
|
|||
|
wcscpy(awchMessage, L"Error");
|
|||
|
iLength = wcslen(awchMessage);
|
|||
|
}
|
|||
|
|
|||
|
va_end(arglist);
|
|||
|
|
|||
|
//
|
|||
|
// Copy the error message string to DQPInfo
|
|||
|
//
|
|||
|
|
|||
|
iLength += 1;
|
|||
|
pDQPInfo->cchNeeded = iLength;
|
|||
|
|
|||
|
if (iLength > (INT) pDQPInfo->cchErrorStr)
|
|||
|
iLength = pDQPInfo->cchErrorStr;
|
|||
|
|
|||
|
if (pDQPInfo->pszErrorStr && iLength)
|
|||
|
CopyString(pDQPInfo->pszErrorStr, awchMessage, iLength);
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
BQueryPrintDevmode(
|
|||
|
PDEVQUERYPRINT_INFO pDQPInfo,
|
|||
|
PCOMMONINFO pci
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Validate devmode information
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
|
|||
|
pci - Points to basic printer info
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, FALSE if the job should be held
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
INT iRealizedRes, iResX, iResY;
|
|||
|
PFEATURE pFeature;
|
|||
|
DWORD dwFeatureIndex, dwOptionIndexOld, dwOptionIndexNew;
|
|||
|
BOOL bUpdateFormField;
|
|||
|
|
|||
|
//
|
|||
|
// Validate input devmode
|
|||
|
// Get printer-sticky properties
|
|||
|
// Merge doc- and printer-sticky printer feature selections
|
|||
|
// Fix up combined options array with public devmode info
|
|||
|
//
|
|||
|
|
|||
|
if (! BFillCommonInfoDevmode(pci, NULL, pDQPInfo->pDevMode))
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_DEVMODE);
|
|||
|
|
|||
|
if (! BFillCommonInfoPrinterData(pci))
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_PRINTERDATA);
|
|||
|
|
|||
|
if (! BCombineCommonInfoOptionsArray(pci))
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_MEMORY);
|
|||
|
|
|||
|
VFixOptionsArrayWithDevmode(pci);
|
|||
|
|
|||
|
//
|
|||
|
// Remember the paper size option parser picked to support the devmode form
|
|||
|
//
|
|||
|
|
|||
|
if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) == NULL)
|
|||
|
{
|
|||
|
ASSERT(FALSE);
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_DEVMODE);
|
|||
|
}
|
|||
|
|
|||
|
dwFeatureIndex = GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature);
|
|||
|
dwOptionIndexOld = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
|
|||
|
|
|||
|
if (! ResolveUIConflicts(
|
|||
|
pci->pRawData,
|
|||
|
pci->pCombinedOptions,
|
|||
|
MAX_COMBINED_OPTIONS,
|
|||
|
MODE_DOCANDPRINTER_STICKY|DONT_RESOLVE_CONFLICT))
|
|||
|
{
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_OPTSELECT);
|
|||
|
}
|
|||
|
|
|||
|
dwOptionIndexNew = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
|
|||
|
|
|||
|
bUpdateFormField = FALSE;
|
|||
|
|
|||
|
if (dwOptionIndexNew != dwOptionIndexOld)
|
|||
|
{
|
|||
|
//
|
|||
|
// Constraint resolving has changed page size selection, so we need
|
|||
|
// to update devmode's form fields.
|
|||
|
//
|
|||
|
|
|||
|
bUpdateFormField = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FORM_INFO_1 *pForm = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Unless the form requested by devmode is not supported on the printer,
|
|||
|
// we still want to show the original form name in upcoming doc-setting UI.
|
|||
|
// For example, if input devmode requested "Legal", parser maps it to option
|
|||
|
// "OEM Legal", but both "Legal" and "OEM Legal" will be shown as supported
|
|||
|
// forms on the printer, then we should still show "Legal" instead of "OEM Legal"
|
|||
|
// in UI's PageSize list. However, if input devmode requestd "8.5 x 12", which
|
|||
|
// won't be shown as a supportd form and it's mapped to "OEM Legal", then we should
|
|||
|
// show "OEM Legal".
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// pdm->dmFormName won't have a valid form name for custom page size (see
|
|||
|
// BValidateDevmodeFormFields()). VOptionsToDevmodeFields() knows to handle that.
|
|||
|
//
|
|||
|
|
|||
|
if ((pci->pdm->dmFields & DM_FORMNAME) &&
|
|||
|
(pForm = MyGetForm(pci->hPrinter, pci->pdm->dmFormName, 1)) &&
|
|||
|
!BFormSupportedOnPrinter(pci, pForm, &dwOptionIndexNew))
|
|||
|
{
|
|||
|
bUpdateFormField = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
MemFree(pForm);
|
|||
|
}
|
|||
|
|
|||
|
VOptionsToDevmodeFields(pci, bUpdateFormField);
|
|||
|
|
|||
|
if (! BUpdateUIInfo(pci))
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_COMMONINFO);
|
|||
|
|
|||
|
//
|
|||
|
// Check if the requested resolution is supported
|
|||
|
//
|
|||
|
|
|||
|
iRealizedRes = max(pci->pdm->dmPrintQuality, pci->pdm->dmYResolution);
|
|||
|
iResX = iResY = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Kludze, there are some cases where apps set dmPrintQuality/dmYResolution
|
|||
|
// to be one of the DMRES values. We skip the checking for resolution
|
|||
|
// since Unidrv/Pscript will map them to one of the valid resolution options
|
|||
|
// at print time
|
|||
|
//
|
|||
|
|
|||
|
if (pDQPInfo->pDevMode->dmFields & DM_PRINTQUALITY)
|
|||
|
{
|
|||
|
iResX = pDQPInfo->pDevMode->dmPrintQuality;
|
|||
|
|
|||
|
if (iResX <= DMRES_DRAFT)
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (pDQPInfo->pDevMode->dmFields & DM_YRESOLUTION)
|
|||
|
{
|
|||
|
iResY = pDQPInfo->pDevMode->dmYResolution;
|
|||
|
|
|||
|
if (iResY <= DMRES_DRAFT)
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (max(iResX, iResY) != iRealizedRes)
|
|||
|
return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_RESOLUTION);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
BQueryPrintForm(
|
|||
|
PDEVQUERYPRINT_INFO pDQPInfo,
|
|||
|
PCOMMONINFO pci
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Check if the requested form and/or tray is available
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
|
|||
|
pci - Points to basic printer info
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, FALSE if the job should be held
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUIINFO pUIInfo;
|
|||
|
PFEATURE pFeature;
|
|||
|
PPAGESIZE pPageSize;
|
|||
|
PWSTR pwstrTrayName;
|
|||
|
FORM_TRAY_TABLE pFormTrayTable;
|
|||
|
FINDFORMTRAY FindData;
|
|||
|
WCHAR awchTrayName[CCHBINNAME];
|
|||
|
DWORD dwFeatureIndex, dwOptionIndex;
|
|||
|
BOOL bResult = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Skip it if form name is not specified
|
|||
|
//
|
|||
|
|
|||
|
if ((pci->pdm->dmFields & DM_FORMNAME) == 0 ||
|
|||
|
pci->pdm->dmFormName[0] == NUL)
|
|||
|
{
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
pUIInfo = pci->pUIInfo;
|
|||
|
|
|||
|
if ((pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_PAGESIZE)) == NULL)
|
|||
|
{
|
|||
|
ASSERT(FALSE);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature);
|
|||
|
dwOptionIndex = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
|
|||
|
|
|||
|
if ((pPageSize = PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex)) == NULL)
|
|||
|
{
|
|||
|
ASSERT(FALSE);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// For custom page size option, we have left the devmode form fields unchanged.
|
|||
|
// See function VOptionToDevmodeFields().
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// We've only shown user forms supported by custom page size in Form-to-Tray table.
|
|||
|
//
|
|||
|
|
|||
|
if (pPageSize->dwPaperSizeID == DMPAPER_USER ||
|
|||
|
pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE)
|
|||
|
{
|
|||
|
FORM_INFO_1 *pForm;
|
|||
|
|
|||
|
//
|
|||
|
// We already verified the dmFormName field at the beginning.
|
|||
|
//
|
|||
|
|
|||
|
if (pForm = MyGetForm(pci->hPrinter, pci->pdm->dmFormName, 1))
|
|||
|
{
|
|||
|
//
|
|||
|
// Built-in and printer forms supported by custom page size option won't show
|
|||
|
// up in either PageSize list or Form-to-Tray assignment table. So we only
|
|||
|
// continue to check the From-to-Tray assignment table for user forms supported
|
|||
|
// by custom page size option. See function BFormSupportedOnPrinter().
|
|||
|
//
|
|||
|
|
|||
|
if (pForm->Flags != FORM_USER)
|
|||
|
{
|
|||
|
MemFree(pForm);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
MemFree(pForm);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the specified tray name, if any
|
|||
|
//
|
|||
|
|
|||
|
pwstrTrayName = NULL;
|
|||
|
|
|||
|
if (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_INPUTSLOT))
|
|||
|
{
|
|||
|
PINPUTSLOT pInputSlot;
|
|||
|
|
|||
|
dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature);
|
|||
|
dwOptionIndex = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
|
|||
|
|
|||
|
if ((pInputSlot = PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex)) &&
|
|||
|
(pInputSlot->dwPaperSourceID != DMBIN_FORMSOURCE) &&
|
|||
|
LOAD_STRING_OPTION_NAME(pci, pInputSlot, awchTrayName, CCHBINNAME))
|
|||
|
{
|
|||
|
pwstrTrayName = awchTrayName;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find out if the requested form/tray pair is
|
|||
|
// listed in the form-to-tray assignment table.
|
|||
|
//
|
|||
|
|
|||
|
if (pFormTrayTable = PGetFormTrayTable(pci->hPrinter, NULL))
|
|||
|
{
|
|||
|
RESET_FINDFORMTRAY(pFormTrayTable, &FindData);
|
|||
|
|
|||
|
bResult = BSearchFormTrayTable(pFormTrayTable,
|
|||
|
pwstrTrayName,
|
|||
|
pci->pdm->dmFormName,
|
|||
|
&FindData);
|
|||
|
MemFree(pFormTrayTable);
|
|||
|
}
|
|||
|
|
|||
|
if (! bResult)
|
|||
|
{
|
|||
|
if (pwstrTrayName != NULL)
|
|||
|
{
|
|||
|
return BFormatDQPMessage(pDQPInfo,
|
|||
|
IDS_DQPERR_FORMTRAY,
|
|||
|
pci->pdm->dmFormName,
|
|||
|
pwstrTrayName);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return BFormatDQPMessage(pDQPInfo,
|
|||
|
IDS_DQPERR_FORMTRAY_ANY,
|
|||
|
pci->pdm->dmFormName);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|