/*++ Copyright (c) 1990-2003 Microsoft Corporation Module Name: docprop.c Abstract: This module contains functions for DrvDocumentPropertySheets Author: 07-Dec-1993 Tue 12:15:40 created [Environment:] GDI Device Driver - Plotter. [Notes:] Revision History: --*/ #include "precomp.h" #pragma hdrstop #define DBG_PLOTFILENAME DbgDocProp extern HMODULE hPlotUIModule; #define DBG_DP_SETUP 0x00000001 #define DBG_DP_FORM 0x00000002 #define DBG_HELP 0x00000004 DEFINE_DBGVAR(0); OPDATA OPOrientation[] = { { 0, IDS_CPSUI_PORTRAIT, IDI_CPSUI_PORTRAIT, 0, 0, 0 }, { 0, IDS_CPSUI_LANDSCAPE, IDI_CPSUI_LANDSCAPE, 0, 0, 0 } }; OPDATA OPColor[] = { { 0, IDS_CPSUI_MONOCHROME, IDI_CPSUI_MONO, 0, 0, 0 }, { 0, IDS_CPSUI_COLOR, IDI_CPSUI_COLOR, 0, 0, 0 } }; OPDATA OPCopyCollate[] = { { 0, IDS_CPSUI_COPIES, IDI_CPSUI_COPY, 0, 0, 0 }, { 0, 0, 1, 0, 0, 100 } }; OPDATA OPScaling[] = { { 0, IDS_CPSUI_PERCENT, IDI_CPSUI_SCALING, 0, 0, 0 }, { 0, 0, 1, 0, 0, 100 } }; OPDATA OPPrintQuality[] = { { 0, IDS_QUALITY_DRAFT, IDI_CPSUI_RES_DRAFT, 0, 0, -1 }, { 0, IDS_QUALITY_LOW, IDI_CPSUI_RES_LOW, 0, 0, -2 }, { 0, IDS_QUALITY_MEDIUM, IDI_CPSUI_RES_MEDIUM, 0, 0, -3 }, { 0, IDS_QUALITY_HIGH, IDI_CPSUI_RES_PRESENTATION, 0, 0, -4 } }; OPDATA OPHTClrAdj = { 0, PI_OFF(PlotDM) + PLOTDM_OFF(ca), IDI_CPSUI_HTCLRADJ, PUSHBUTTON_TYPE_HTCLRADJ, 0, 0 }; extern OPDATA OPNoYes[]; OPDATA OPFillTrueType[] = { { 0, IDS_CPSUI_NO, IDI_FILL_TRUETYPE_NO, 0, 0, 0 }, { 0, IDS_CPSUI_YES, IDI_FILL_TRUETYPE_YES, 0, 0, 0 } }; OIDATA DPOIData[] = { { ODF_PEN_RASTER | ODF_CALLCREATEOI, 0, OI_LEVEL_1, DMPUB_FORMNAME, TVOT_LISTBOX, IDS_CPSUI_FORMNAME, 0, IDH_FORMNAME, 0, (POPDATA)CreateFormOI }, { ODF_PEN_RASTER, 0, OI_LEVEL_1, DMPUB_ORIENTATION, TVOT_2STATES, IDS_CPSUI_ORIENTATION, 0, IDH_ORIENTATION, COUNT_ARRAY(OPOrientation), OPOrientation }, { ODF_PEN_RASTER, 0, OI_LEVEL_1, DMPUB_COPIES_COLLATE, TVOT_UDARROW, IDS_CPSUI_NUM_OF_COPIES, 0, IDH_COPIES_COLLATE, COUNT_ARRAY(OPCopyCollate), OPCopyCollate }, { ODF_PEN_RASTER, 0, OI_LEVEL_1, DMPUB_PRINTQUALITY, TVOT_LISTBOX, IDS_CPSUI_PRINTQUALITY, 0, IDH_PRINTQUALITY, COUNT_ARRAY(OPPrintQuality), OPPrintQuality }, { ODF_RASTER | ODF_COLOR, 0, OI_LEVEL_1, DMPUB_COLOR, TVOT_2STATES, IDS_CPSUI_COLOR_APPERANCE, 0, IDH_COLOR, COUNT_ARRAY(OPColor), OPColor }, { ODF_PEN_RASTER, 0, OI_LEVEL_1, DMPUB_SCALE, TVOT_UDARROW, IDS_CPSUI_SCALING, 0, IDH_SCALE, COUNT_ARRAY(OPScaling), OPScaling }, { ODF_RASTER, 0, OI_LEVEL_1, DP_HTCLRADJ, TVOT_PUSHBUTTON, IDS_CPSUI_HTCLRADJ, OTS_PUSH_ENABLE_ALWAYS, IDH_HTCLRADJ, 1, &OPHTClrAdj }, { ODF_PEN, 0, OI_LEVEL_1, DP_FILL_TRUETYPE, TVOT_2STATES, IDS_FILL_TRUETYPE, 0, IDH_FILL_TRUETYPE, 2, OPFillTrueType }, { ODF_RASTER, 0, OI_LEVEL_1, DP_QUICK_POSTER_MODE, TVOT_2STATES, IDS_POSTER_MODE, 0, IDH_POSTER_MODE, 2, OPNoYes } }; UINT SetupDPOptItems( PPRINTERINFO pPI ) /*++ Routine Description: Arguments: Return Value: Author: 16-Nov-1995 Thu 14:15:25 created Revision History: --*/ { PPLOTDEVMODE pPlotDM; PPLOTGPC pPlotGPC; POPTITEM pOptItem; POPTITEM pOI; POIDATA pOIData; DWORD Flags; DWORD ODFlags; UINT i; pOI = pOptItem = pPI->pOptItem; pOIData = DPOIData; i = (UINT)COUNT_ARRAY(DPOIData); pPlotGPC = pPI->pPlotGPC; pPlotDM = &(pPI->PlotDM); Flags = pPlotGPC->Flags; ODFlags = (Flags & PLOTF_RASTER) ? ODF_RASTER : ODF_PEN; while (i--) { DWORD OIFlags = pOIData->Flags; switch (pOIData->DMPubID) { case DMPUB_COPIES_COLLATE: if (pPlotGPC->MaxCopies <= 1) { OIFlags = 0; } break; case DMPUB_SCALE: if (!pPlotGPC->MaxScale) { OIFlags = 0; } break; } if ((!(OIFlags & ODFlags)) || ((OIFlags & ODF_ROLLFEED) && (!(Flags & PLOTF_ROLLFEED))) || ((OIFlags & ODF_NO_PAPERTRAY) && (Flags & PLOTF_PAPERTRAY)) || ((OIFlags & ODF_COLOR) && (!(Flags & PLOTF_COLOR)))) { // // Nothing to do here // NULL; } else if (OIFlags & ODF_CALLCREATEOI) { pOI += pOIData->pfnCreateOI(pPI, (LPVOID)((pOptItem) ? pOI : NULL), pOIData); } else if (pOptItem) { if (CreateOPTTYPE(pPI, pOI, pOIData, pOIData->cOPData, NULL)) { POPTPARAM pOP = pOI->pOptType->pOptParam; switch (pOI->DMPubID) { case DMPUB_ORIENTATION: pOI->Sel = (LONG)((pPlotDM->dm.dmOrientation == DMORIENT_PORTRAIT) ? 0 : 1); break; case DMPUB_COPIES_COLLATE: pOP[1].lParam = (LONG)pPlotGPC->MaxCopies; pOI->Sel = (LONG)pPlotDM->dm.dmCopies; break; case DMPUB_PRINTQUALITY: switch (pPlotGPC->MaxQuality) { case 0: case 1: pPlotDM->dm.dmPrintQuality = DMRES_HIGH; pOP[0].Flags |= OPTPF_HIDE; case 2: pOP[2].Flags |= OPTPF_HIDE; case 3: pOP[1].Flags |= OPTPF_HIDE; break; default: break; } pOI->Sel = (LONG)-(pPlotDM->dm.dmPrintQuality - DMRES_DRAFT); break; case DMPUB_COLOR: pOI->Sel = (LONG)((pPlotDM->dm.dmColor == DMCOLOR_COLOR) ? 1 : 0); break; case DMPUB_SCALE: pOP[1].lParam = (LONG)pPlotGPC->MaxScale; pOI->Sel = (LONG)pPlotDM->dm.dmScale; break; case DP_FILL_TRUETYPE: pOI->Sel = (LONG)((pPlotDM->Flags & PDMF_FILL_TRUETYPE) ? 1 : 0); break; case DP_QUICK_POSTER_MODE: pOI->Sel = (LONG)((pPlotDM->Flags & PDMF_PLOT_ON_THE_FLY) ? 1 : 0); break; } pOI++; } } else { pOI++; } pOIData++; } if ((i = (UINT)(pOI - pOptItem)) && (!pOptItem)) { if (pPI->pOptItem = (POPTITEM)LocalAlloc(LPTR, sizeof(OPTITEM) * i)) { pPI->cOptItem = (WORD)i; // // Call myself second time to really create it // SetupDPOptItems(pPI); } else { i = 0; PLOTERR(("GetPPpOptItem(): LocalAlloc(%ld) failed", sizeof(OPTITEM) * i)); } } return(i); } VOID SaveDPOptItems( PPRINTERINFO pPI ) /*++ Routine Description: This function save all the device options back to registry if one changed and has a update permission Arguments: pPI - Pointer to the PRINTERINFO Return Value: VOID Author: 06-Nov-1995 Mon 18:05:16 created Revision History: --*/ { POPTITEM pOI; POPTITEM pLastItem; PPLOTDEVMODE pPlotDM; BYTE DMPubID; pOI = pPI->pOptItem; pLastItem = pOI + pPI->cOptItem - 1; pPlotDM = &(pPI->PlotDM); while (pOI <= pLastItem) { if (pOI->Flags & OPTIF_CHANGEONCE) { switch (pOI->DMPubID) { case DMPUB_FORMNAME: GetFormSelect(pPI, pOI); break; case DMPUB_ORIENTATION: pPlotDM->dm.dmOrientation = (SHORT)((pOI->Sel) ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT); break; case DMPUB_COPIES_COLLATE: pPlotDM->dm.dmCopies = (SHORT)pOI->Sel; break; case DMPUB_PRINTQUALITY: pPlotDM->dm.dmPrintQuality = (SHORT)(-(pOI->Sel) + DMRES_DRAFT); break; case DMPUB_COLOR: pPlotDM->dm.dmColor = (SHORT)((pOI->Sel) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME); break; case DMPUB_SCALE: pPlotDM->dm.dmScale = (SHORT)pOI->Sel; break; case DP_FILL_TRUETYPE: if (pOI->Sel) { pPlotDM->Flags |= PDMF_FILL_TRUETYPE; } else { pPlotDM->Flags &= ~PDMF_FILL_TRUETYPE; } break; case DP_QUICK_POSTER_MODE: if (pOI->Sel) { pPlotDM->Flags |= PDMF_PLOT_ON_THE_FLY; } else { pPlotDM->Flags &= ~PDMF_PLOT_ON_THE_FLY; } break; } } pOI++; } } CPSUICALLBACK DPCallBack( PCPSUICBPARAM pCPSUICBParam ) /*++ Routine Description: This is the callback function from the common property sheet UI Arguments: pCPSUICBParam - Pointer to the CPSUICBPARAM data structure to describe the nature of the callback Return Value: LONG Author: 07-Nov-1995 Tue 15:15:02 created Revision History: --*/ { POPTITEM pCurItem = pCPSUICBParam->pCurItem; LONG Action = CPSUICB_ACTION_NONE; if (pCPSUICBParam->Reason == CPSUICB_REASON_APPLYNOW) { PPRINTERINFO pPI = (PPRINTERINFO)pCPSUICBParam->UserData; if ((pPI->Flags & PIF_UPDATE_PERMISSION) && (pPI->pPlotDMOut)) { SaveDPOptItems(pPI); PLOTDBG(DBG_DP_SETUP, ("APPLYNOW: ConvertDevmodeOut")); ConvertDevmodeOut((PDEVMODE)&(pPI->PlotDM), (PDEVMODE)pPI->pPlotDMIn, (PDEVMODE)pPI->pPlotDMOut); pCPSUICBParam->Result = CPSUI_OK; Action = CPSUICB_ACTION_ITEMS_APPLIED; } } return(Action); } BOOL DrvConvertDevMode( LPTSTR pPrinterName, PDEVMODE pDMIn, PDEVMODE pDMOut, PLONG pcbNeeded, DWORD fMode ) /*++ Routine Description: This function is used by the SetPrinter() and GetPrinter() spooler calls. Arguments: pPrinterName - Points to printer name string pDMIn - Points to the input devmode pDMOut - Points to the output devmode buffer pcbNeeded - Specifies the size of output buffer on input On output, this is the size of output devmode fMode - Specifies what function to perform Return Value: TRUE if successful FALSE otherwise and an error code is logged Author: 08-Jan-1996 Mon 12:40:22 created Revision History: --*/ { DWORD cb; INT Result; static DRIVER_VERSION_INFO PlotDMVersions = { DRIVER_VERSION, PLOTDM_PRIV_SIZE, // current version/size 0x0350, PLOTDM_PRIV_SIZE, // NT3.51 version/size }; // // Call a library routine to handle the common cases // Result = CommonDrvConvertDevmode(pPrinterName, pDMIn, pDMOut, pcbNeeded, fMode, &PlotDMVersions); // // If not handled by the library routine, we only need to worry // about the case when fMode is CDM_DRIVER_DEFAULT // if ((Result == CDM_RESULT_NOT_HANDLED) && (fMode == CDM_DRIVER_DEFAULT)) { HANDLE hPrinter; if (OpenPrinter(pPrinterName, &hPrinter, NULL)) { PPLOTGPC pPlotGPC; if (pPlotGPC = hPrinterToPlotGPC(hPrinter, pDMOut->dmDeviceName, CCHOF(pDMOut->dmDeviceName))) { SetDefaultPLOTDM(hPrinter, pPlotGPC, pDMOut->dmDeviceName, (PPLOTDEVMODE)pDMOut, NULL); UnGetCachedPlotGPC(pPlotGPC); Result = CDM_RESULT_TRUE; } else { PLOTERR(("DrvConvertDevMode: hPrinterToPlotGPC(%ws) failed.", pPrinterName)); SetLastError(ERROR_INVALID_DATA); } ClosePrinter(hPrinter); } else { PLOTERR(("DrvConvertDevMode: OpenPrinter(%ws) failed.", pPrinterName)); SetLastError(ERROR_INVALID_DATA); } } return(Result == CDM_RESULT_TRUE); } LONG DrvDocumentPropertySheets( PPROPSHEETUI_INFO pPSUIInfo, LPARAM lParam ) /*++ Routine Description: Show document property dialog box and update the output DEVMODE Arguments: pPSUIInfo - Pointer to the PROPSHEETUI_INFO data structure lParam - LPARAM for this call, it is a pointer to the DOCUMENTPROPERTYHEADER Return Value: LONG, 1=successful, 0=failed. Author: 02-Feb-1996 Fri 10:47:42 created Revision History: --*/ { PDOCUMENTPROPERTYHEADER pDPHdr; PPRINTERINFO pPI; LONG_PTR Result; // // Assume faild first // Result = -1; if (pPSUIInfo) { if (!(pDPHdr = (PDOCUMENTPROPERTYHEADER)pPSUIInfo->lParamInit)) { PLOTERR(("DrvDocumentPropertySheets: Pass a NULL lParamInit")); return(-1); } } else { if (pDPHdr = (PDOCUMENTPROPERTYHEADER)lParam) { // // We do not have pPSUIInfo, so that we assume this is call // directly from the spooler and lParam is the pDPHdr // if ((pDPHdr->fMode == 0) || (pDPHdr->pdmOut == NULL)) { Result = (pDPHdr->cbOut = sizeof(PLOTDEVMODE)); } else if ((pDPHdr->fMode & (DM_COPY | DM_UPDATE)) && (!(pDPHdr->fMode & DM_NOPERMISSION)) && (pDPHdr->pdmOut)) { // // The MapPrinter will allocate memory, set default devmode, // reading and validating the GPC then update from current pritner // registry, it also will cached the pPI. // if (pPI = MapPrinter(pDPHdr->hPrinter, (PPLOTDEVMODE)pDPHdr->pdmIn, NULL, 0)) { ConvertDevmodeOut((PDEVMODE)&(pPI->PlotDM), (PDEVMODE)pDPHdr->pdmIn, (PDEVMODE)pDPHdr->pdmOut); Result = 1; UnMapPrinter(pPI); } else { PLOTRIP(("DrvDocumentPropertySheets: MapPrinter() failed")); } } else { Result = 1; } } else { PLOTRIP(("DrvDocumentPropertySheets: ??? pDPHdr (lParam) = NULL")); } return((LONG)Result); } // // Now, this is the call from common UI, assume error to start with // if (pPSUIInfo->Reason == PROPSHEETUI_REASON_INIT) { if (!(pPI = MapPrinter(pDPHdr->hPrinter, (PPLOTDEVMODE)pDPHdr->pdmIn, NULL, MPF_HELPFILE | MPF_PCPSUI))) { PLOTRIP(("DrvDocumentPropertySheets: MapPrinter() failed")); SetLastError(ERROR_INVALID_DATA); return(ERR_CPSUI_GETLASTERROR); } if ((pDPHdr->fMode & (DM_COPY | DM_UPDATE)) && (!(pDPHdr->fMode & DM_NOPERMISSION)) && (pDPHdr->pdmOut)) { pPI->Flags = (PIF_DOCPROP | PIF_UPDATE_PERMISSION); pPI->pPlotDMOut = (PPLOTDEVMODE)pDPHdr->pdmOut; } else { pPI->Flags = PIF_DOCPROP; pPI->pPlotDMOut = NULL; } // // We need to display something to let user modify/update, we wll check // which document properties dialog box to be used // // The return value either IDOK or IDCANCEL // pPI->pCPSUI->Flags = 0; pPI->pCPSUI->pfnCallBack = DPCallBack; pPI->pCPSUI->pDlgPage = (pDPHdr->fMode & DM_ADVANCED) ? CPSUI_PDLGPAGE_ADVDOCPROP : CPSUI_PDLGPAGE_DOCPROP; Result = (LONG_PTR)SetupDPOptItems(pPI); } else { pPI = (PPRINTERINFO)pPSUIInfo->UserData; Result = (LONG_PTR)pDPHdr->pszPrinterName; } return(DefCommonUIFunc(pPSUIInfo, lParam, pPI, Result)); } // @@BEGIN_DDKSPLIT // DrvDocumentProperties() and DrvAdvancedDocumentProperties() // are obsolete, but we keep them here for old application which // might be using these. But, we don't want these in the DDK samples. LONG DrvDocumentProperties( HWND hWnd, HANDLE hPrinter, LPWSTR pwDeviceName, PPLOTDEVMODE pDMOut, PPLOTDEVMODE pDMIn, DWORD fMode ) /*++ Routine Description: DrvDocumentProperties sets the public members of a PLOTDEVMODE structure for the given print document. Arguments: hWnd - Identifies the parent window of the printer-configuration dialog box. hPrinter - Identifies a printer object. pwDeviceName - Points to a zero-terminated string that specifies the name of the device for which the printer-configuration dialog box should be displayed. pDMOut - Points to a PLOTDEVMODE structure that initializes the dialog box controls. NULL forces the use of the default values. pDMIn - Points to a PLOTDEVMODE structure that receives the printer configuration data specified by the user. fMode - Specifies a mask of values that determines which operations the function performs. If this parameter is zero, DrvDocumentProperties returns the number of bytes required by the printer driver's PLOTDEVMODE structure. Otherwise, use one or more of the following constants to construct a value for this parameter; note, however, that in order to change the print settings, an application must specify at least one input value and one output value: Value Meaning ------------------------------------------------------------------ DM_IN_BUFFER Input value. Before prompting, copying, or updating, (DM_MODIFY) the function merges the printer driver's current print settings with the settings in the PLOTDEVMODE specified by the pDMIn parameter. The structure is updated only for those members specified by the PLOTDEVMODE structure's dmFields member. This value is also defined as DM_MODIFY. DM_IN_PROMPT Input value. The function presents the print (DM_PROMPT) driver's Print Setup dialog box, then change the settings in the printer's PLOTDEVMODE structure to the values specified by the user. This value is also defined as DM_PROMPT. DM_OUT_BUFFER Output value. The function writes the printer (DM_COPY) driver's current print settings, including private data, to the PLOTDEVMODE structure specified by pDMOut. The caller must allocate a buffer large enough to contain the information. If the bit DM_OUT_BUFFER is clear, pDMOut can be NULL. This value is also defined as DM_COPY. Return Value: If fMode is zero, the return value is the size of the buffer (in bytes) required to contain the printer driver initialization data. Note that this buffer will generally be larger than the PLOTDEVMODE structure if the printer driver appends private data to the structure. If the function displays the initialization dialog box, the return value is either IDOK or IDCANCEL, depending on which button the user selects. If the function does not display the dialog box and is successful, the return value is IDOK. If the function fails, the return value is less than zero. In order to change print settings that are local to an application, the application should: * Call with fMode = 0 to get the size of DM_OUT_BUFFER. * Modify the returned PLOTDEVMODE structure. * Pass the modified PLOTDEVMODE back by calling DrvDocumentProperties, specifying both DM_IN_BUFFER and DM_OUT_BUFFER. Author: 15-Dec-1993 Wed 15:07:01 updated it seems that spooler never passed a DM_MODIFY to the driver, and that caused we never merge the input devmode, we will assume that user has valid DM_IN_BUFFER/DM_MODIFY bit set if the pDMIn is not a NULL pointer. 07-Dec-1993 Tue 12:19:47 created Revision History: --*/ { DOCUMENTPROPERTYHEADER DPHdr; LONG Result; DPHdr.cbSize = sizeof(DPHdr); DPHdr.Reserved = 0; DPHdr.hPrinter = hPrinter; DPHdr.pszPrinterName = pwDeviceName; DPHdr.pdmIn = (PDEVMODE)pDMIn; DPHdr.pdmOut = (PDEVMODE)pDMOut; DPHdr.cbOut = sizeof(PLOTDEVMODE); DPHdr.fMode = fMode; PLOTDBG(DBG_DP_SETUP, ("DocProp: fMode=%08lx, %ws%ws%ws%ws", fMode, (INT_PTR)((fMode & DM_UPDATE) ? L"DM_UPDATE " : L""), (INT_PTR)((fMode & DM_COPY ) ? L"DM_COPY " : L""), (INT_PTR)((fMode & DM_PROMPT) ? L"DM_PROMPT " : L""), (INT_PTR)((fMode & DM_MODIFY) ? L"DM_MODIFY " : L""))); if (fMode & DM_PROMPT) { Result = CPSUI_CANCEL; if (CallCommonPropertySheetUI(hWnd, DrvDocumentPropertySheets, (LPARAM)&DPHdr, (LPDWORD)&Result) < 0) { Result = CPSUI_CANCEL; } PLOTDBG(DBG_DP_SETUP, ("Result=%hs", (Result == CPSUI_OK) ? "IDOK" : "IDCANCEL")); return((Result == CPSUI_OK) ? IDOK : IDCANCEL); } else { return(DrvDocumentPropertySheets(NULL, (LPARAM)&DPHdr)); } } LONG DrvAdvancedDocumentProperties( HWND hWnd, HANDLE hPrinter, LPWSTR pwDeviceName, PPLOTDEVMODE pDMOut, PPLOTDEVMODE pDMIn ) /*++ Routine Description: DrvAdvancedDocumentProperties sets the public members of a PLOTDEVMODE structure for the given print document. Arguments: hWnd - Identifies the parent window of the printer-configuration dialog box. hPrinter - Identifies a printer object. pwDeviceName - Points to a zero-terminated string that specifies the name of the device for which the printer-configuration dialog box should be displayed. pDMOut - Points to a PLOTDEVMODE structure that initializes the dialog box controls. NULL forces the use of the default values. pDMIn - Points to a PLOTDEVMODE structure that receives the printer configuration data specified by the user. Return Value: LONG value depends on the dilaog box outcome eiterh IDOK or IDCANCEL, if an error occurred then a negative number is returned Author: 07-Dec-1993 Tue 12:19:47 created Revision History: --*/ { return((DrvDocumentProperties(hWnd, hPrinter, pwDeviceName, pDMOut, pDMIn, DM_PROMPT | DM_MODIFY | DM_COPY | DM_ADVANCED) == CPSUI_OK) ? 1 : 0); } // @@END_DDKSPLIT