windows-nt/Source/XPSP1/NT/printscan/print/drivers/usermode/driverui/quryprnt.c

520 lines
13 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}