|  | /* | 
|  | * COMMDLG - Print Dialog | 
|  | * | 
|  | * Copyright 1994 Martin Ayotte | 
|  | * Copyright 1996 Albrecht Kleine | 
|  | * Copyright 1999 Klaas van Gend | 
|  | * Copyright 2000 Huw D M Davies | 
|  | * Copyright 2010 Vitaly Perov | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  | #include <ctype.h> | 
|  | #include <stdlib.h> | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #include <assert.h> | 
|  |  | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winspool.h" | 
|  | #include "winerror.h" | 
|  |  | 
|  | #include "wine/unicode.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "commdlg.h" | 
|  | #include "dlgs.h" | 
|  | #include "cderr.h" | 
|  | #include "cdlg.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(commdlg); | 
|  |  | 
|  | /* Yes these constants are the same, but we're just copying win98 */ | 
|  | #define UPDOWN_ID 0x270f | 
|  | #define MAX_COPIES 9999 | 
|  |  | 
|  | /* This PRINTDLGA internal structure stores | 
|  | * pointers to several throughout useful structures. | 
|  | */ | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | LPDEVMODEA        lpDevMode; | 
|  | LPPRINTDLGA       lpPrintDlg; | 
|  | LPPRINTER_INFO_2A lpPrinterInfo; | 
|  | LPDRIVER_INFO_3A  lpDriverInfo; | 
|  | UINT              HelpMessageID; | 
|  | HICON             hCollateIcon;    /* PrintDlg only */ | 
|  | HICON             hNoCollateIcon;  /* PrintDlg only */ | 
|  | HICON             hPortraitIcon;   /* PrintSetupDlg only */ | 
|  | HICON             hLandscapeIcon;  /* PrintSetupDlg only */ | 
|  | HWND              hwndUpDown; | 
|  | } PRINT_PTRA; | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | LPDEVMODEW        lpDevMode; | 
|  | LPPRINTDLGW       lpPrintDlg; | 
|  | LPPRINTER_INFO_2W lpPrinterInfo; | 
|  | LPDRIVER_INFO_3W  lpDriverInfo; | 
|  | UINT              HelpMessageID; | 
|  | HICON             hCollateIcon;    /* PrintDlg only */ | 
|  | HICON             hNoCollateIcon;  /* PrintDlg only */ | 
|  | HICON             hPortraitIcon;   /* PrintSetupDlg only */ | 
|  | HICON             hLandscapeIcon;  /* PrintSetupDlg only */ | 
|  | HWND              hwndUpDown; | 
|  | } PRINT_PTRW; | 
|  |  | 
|  | /* Debugging info */ | 
|  | struct pd_flags | 
|  | { | 
|  | DWORD  flag; | 
|  | LPCSTR name; | 
|  | }; | 
|  |  | 
|  | static const struct pd_flags psd_flags[] = { | 
|  | {PSD_MINMARGINS,"PSD_MINMARGINS"}, | 
|  | {PSD_MARGINS,"PSD_MARGINS"}, | 
|  | {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"}, | 
|  | {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"}, | 
|  | {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"}, | 
|  | {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"}, | 
|  | {PSD_NOWARNING,"PSD_NOWARNING"}, | 
|  | {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"}, | 
|  | {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"}, | 
|  | {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"}, | 
|  | {PSD_SHOWHELP,"PSD_SHOWHELP"}, | 
|  | {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"}, | 
|  | {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"}, | 
|  | {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"}, | 
|  | {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"}, | 
|  | {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"}, | 
|  | {-1, NULL} | 
|  | }; | 
|  |  | 
|  | static const struct pd_flags pd_flags[] = { | 
|  | {PD_SELECTION, "PD_SELECTION "}, | 
|  | {PD_PAGENUMS, "PD_PAGENUMS "}, | 
|  | {PD_NOSELECTION, "PD_NOSELECTION "}, | 
|  | {PD_NOPAGENUMS, "PD_NOPAGENUMS "}, | 
|  | {PD_COLLATE, "PD_COLLATE "}, | 
|  | {PD_PRINTTOFILE, "PD_PRINTTOFILE "}, | 
|  | {PD_PRINTSETUP, "PD_PRINTSETUP "}, | 
|  | {PD_NOWARNING, "PD_NOWARNING "}, | 
|  | {PD_RETURNDC, "PD_RETURNDC "}, | 
|  | {PD_RETURNIC, "PD_RETURNIC "}, | 
|  | {PD_RETURNDEFAULT, "PD_RETURNDEFAULT "}, | 
|  | {PD_SHOWHELP, "PD_SHOWHELP "}, | 
|  | {PD_ENABLEPRINTHOOK, "PD_ENABLEPRINTHOOK "}, | 
|  | {PD_ENABLESETUPHOOK, "PD_ENABLESETUPHOOK "}, | 
|  | {PD_ENABLEPRINTTEMPLATE, "PD_ENABLEPRINTTEMPLATE "}, | 
|  | {PD_ENABLESETUPTEMPLATE, "PD_ENABLESETUPTEMPLATE "}, | 
|  | {PD_ENABLEPRINTTEMPLATEHANDLE, "PD_ENABLEPRINTTEMPLATEHANDLE "}, | 
|  | {PD_ENABLESETUPTEMPLATEHANDLE, "PD_ENABLESETUPTEMPLATEHANDLE "}, | 
|  | {PD_USEDEVMODECOPIES, "PD_USEDEVMODECOPIES[ANDCOLLATE] "}, | 
|  | {PD_DISABLEPRINTTOFILE, "PD_DISABLEPRINTTOFILE "}, | 
|  | {PD_HIDEPRINTTOFILE, "PD_HIDEPRINTTOFILE "}, | 
|  | {PD_NONETWORKBUTTON, "PD_NONETWORKBUTTON "}, | 
|  | {-1, NULL} | 
|  | }; | 
|  | /* address of wndproc for subclassed Static control */ | 
|  | static WNDPROC lpfnStaticWndProc; | 
|  | static WNDPROC edit_wndproc; | 
|  | /* the text of the fake document to render for the Page Setup dialog */ | 
|  | static WCHAR wszFakeDocumentText[1024]; | 
|  | static const WCHAR pd32_collateW[] = { 'P', 'D', '3', '2', '_', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; | 
|  | static const WCHAR pd32_nocollateW[] = { 'P', 'D', '3', '2', '_', 'N', 'O', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; | 
|  | static const WCHAR pd32_portraitW[] = { 'P', 'D', '3', '2', '_', 'P', 'O', 'R', 'T', 'R', 'A', 'I', 'T', 0 }; | 
|  | static const WCHAR pd32_landscapeW[] = { 'P', 'D', '3', '2', '_', 'L', 'A', 'N', 'D', 'S', 'C', 'A', 'P', 'E', 0 }; | 
|  | static const WCHAR printdlg_prop[] = {'_','_','W','I','N','E','_','P','R','I','N','T','D','L','G','D','A','T','A',0}; | 
|  | static const WCHAR pagesetupdlg_prop[] = { '_', '_', 'W', 'I', 'N', 'E', '_', 'P', 'A', 'G', 'E', | 
|  | 'S', 'E', 'T', 'U', 'P', 'D', 'L', 'G', 'D', 'A', 'T', 'A', 0 }; | 
|  |  | 
|  |  | 
|  | static LPWSTR strdupW(LPCWSTR p) | 
|  | { | 
|  | LPWSTR ret; | 
|  | DWORD len; | 
|  |  | 
|  | if(!p) return NULL; | 
|  | len = (strlenW(p) + 1) * sizeof(WCHAR); | 
|  | ret = HeapAlloc(GetProcessHeap(), 0, len); | 
|  | memcpy(ret, p, len); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************** | 
|  | * convert_to_devmodeA | 
|  | * | 
|  | * Creates an ansi copy of supplied devmode | 
|  | */ | 
|  | static DEVMODEA *convert_to_devmodeA(const DEVMODEW *dmW) | 
|  | { | 
|  | DEVMODEA *dmA; | 
|  | DWORD size; | 
|  |  | 
|  | if (!dmW) return NULL; | 
|  | size = dmW->dmSize - CCHDEVICENAME - | 
|  | ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0); | 
|  |  | 
|  | dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra); | 
|  | if (!dmA) return NULL; | 
|  |  | 
|  | WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, | 
|  | (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL); | 
|  |  | 
|  | if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) | 
|  | { | 
|  | memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion, | 
|  | dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion)); | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion, | 
|  | FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion)); | 
|  | WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, | 
|  | (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL); | 
|  |  | 
|  | memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels)); | 
|  | } | 
|  |  | 
|  | dmA->dmSize = size; | 
|  | memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra); | 
|  | return dmA; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *    PRINTDLG_OpenDefaultPrinter | 
|  | * | 
|  | * Returns a winspool printer handle to the default printer in *hprn | 
|  | * Caller must call ClosePrinter on the handle | 
|  | * | 
|  | * Returns TRUE on success else FALSE | 
|  | */ | 
|  | static BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn) | 
|  | { | 
|  | WCHAR buf[260]; | 
|  | DWORD dwBufLen = sizeof(buf) / sizeof(buf[0]); | 
|  | BOOL res; | 
|  | if(!GetDefaultPrinterW(buf, &dwBufLen)) | 
|  | return FALSE; | 
|  | res = OpenPrinterW(buf, hprn, NULL); | 
|  | if (!res) | 
|  | WARN("Could not open printer %s\n", debugstr_w(buf)); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *    PRINTDLG_SetUpPrinterListCombo | 
|  | * | 
|  | * Initializes printer list combox. | 
|  | * hDlg:  HWND of dialog | 
|  | * id:    Control id of combo | 
|  | * name:  Name of printer to select | 
|  | * | 
|  | * Initializes combo with list of available printers.  Selects printer 'name' | 
|  | * If name is NULL or does not exist select the default printer. | 
|  | * | 
|  | * Returns number of printers added to list. | 
|  | */ | 
|  | static INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name) | 
|  | { | 
|  | DWORD needed, num; | 
|  | INT i; | 
|  | LPPRINTER_INFO_2A pi; | 
|  | EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); | 
|  | pi = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, | 
|  | &num); | 
|  |  | 
|  | SendDlgItemMessageA(hDlg, id, CB_RESETCONTENT, 0, 0); | 
|  |  | 
|  | for(i = 0; i < num; i++) { | 
|  | SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0, | 
|  | (LPARAM)pi[i].pPrinterName ); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, pi); | 
|  | if(!name || | 
|  | (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, | 
|  | (LPARAM)name)) == CB_ERR) { | 
|  |  | 
|  | char buf[260]; | 
|  | DWORD dwBufLen = sizeof(buf); | 
|  | if (name != NULL) | 
|  | WARN("Can't find %s in printer list so trying to find default\n", | 
|  | debugstr_a(name)); | 
|  | if(!GetDefaultPrinterA(buf, &dwBufLen)) | 
|  | return num; | 
|  | i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); | 
|  | if(i == CB_ERR) | 
|  | FIXME("Can't find default printer in printer list\n"); | 
|  | } | 
|  | SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0); | 
|  | return num; | 
|  | } | 
|  |  | 
|  | static INT PRINTDLG_SetUpPrinterListComboW(HWND hDlg, UINT id, LPCWSTR name) | 
|  | { | 
|  | DWORD needed, num; | 
|  | INT i; | 
|  | LPPRINTER_INFO_2W pi; | 
|  | EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); | 
|  | pi = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, | 
|  | &num); | 
|  |  | 
|  | for(i = 0; i < num; i++) { | 
|  | SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0, | 
|  | (LPARAM)pi[i].pPrinterName ); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, pi); | 
|  | if(!name || | 
|  | (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, | 
|  | (LPARAM)name)) == CB_ERR) { | 
|  | WCHAR buf[260]; | 
|  | DWORD dwBufLen = sizeof(buf)/sizeof(buf[0]); | 
|  | if (name != NULL) | 
|  | WARN("Can't find %s in printer list so trying to find default\n", | 
|  | debugstr_w(name)); | 
|  | if(!GetDefaultPrinterW(buf, &dwBufLen)) | 
|  | return num; | 
|  | i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); | 
|  | if(i == CB_ERR) | 
|  | TRACE("Can't find default printer in printer list\n"); | 
|  | } | 
|  | SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0); | 
|  | return num; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *             PRINTDLG_CreateDevNames          [internal] | 
|  | * | 
|  | * | 
|  | *   creates a DevNames structure. | 
|  | * | 
|  | *  (NB. when we handle unicode the offsets will be in wchars). | 
|  | */ | 
|  | static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, const char* DeviceDriverName, | 
|  | const char* DeviceName, const char* OutputPort) | 
|  | { | 
|  | long size; | 
|  | char*   pDevNamesSpace; | 
|  | char*   pTempPtr; | 
|  | LPDEVNAMES lpDevNames; | 
|  | char buf[260]; | 
|  | DWORD dwBufLen = sizeof(buf); | 
|  |  | 
|  | size = strlen(DeviceDriverName) + 1 | 
|  | + strlen(DeviceName) + 1 | 
|  | + strlen(OutputPort) + 1 | 
|  | + sizeof(DEVNAMES); | 
|  |  | 
|  | if(*hmem) | 
|  | *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); | 
|  | else | 
|  | *hmem = GlobalAlloc(GMEM_MOVEABLE, size); | 
|  | if (*hmem == 0) | 
|  | return FALSE; | 
|  |  | 
|  | pDevNamesSpace = GlobalLock(*hmem); | 
|  | lpDevNames = (LPDEVNAMES) pDevNamesSpace; | 
|  |  | 
|  | pTempPtr = pDevNamesSpace + sizeof(DEVNAMES); | 
|  | strcpy(pTempPtr, DeviceDriverName); | 
|  | lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; | 
|  |  | 
|  | pTempPtr += strlen(DeviceDriverName) + 1; | 
|  | strcpy(pTempPtr, DeviceName); | 
|  | lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; | 
|  |  | 
|  | pTempPtr += strlen(DeviceName) + 1; | 
|  | strcpy(pTempPtr, OutputPort); | 
|  | lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; | 
|  |  | 
|  | GetDefaultPrinterA(buf, &dwBufLen); | 
|  | lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0; | 
|  | GlobalUnlock(*hmem); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName, | 
|  | LPCWSTR DeviceName, LPCWSTR OutputPort) | 
|  | { | 
|  | long size; | 
|  | LPWSTR   pDevNamesSpace; | 
|  | LPWSTR   pTempPtr; | 
|  | LPDEVNAMES lpDevNames; | 
|  | WCHAR bufW[260]; | 
|  | DWORD dwBufLen = sizeof(bufW) / sizeof(WCHAR); | 
|  |  | 
|  | size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2 | 
|  | + sizeof(WCHAR)*lstrlenW(DeviceName) + 2 | 
|  | + sizeof(WCHAR)*lstrlenW(OutputPort) + 2 | 
|  | + sizeof(DEVNAMES); | 
|  |  | 
|  | if(*hmem) | 
|  | *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); | 
|  | else | 
|  | *hmem = GlobalAlloc(GMEM_MOVEABLE, size); | 
|  | if (*hmem == 0) | 
|  | return FALSE; | 
|  |  | 
|  | pDevNamesSpace = GlobalLock(*hmem); | 
|  | lpDevNames = (LPDEVNAMES) pDevNamesSpace; | 
|  |  | 
|  | pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1); | 
|  | lstrcpyW(pTempPtr, DeviceDriverName); | 
|  | lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; | 
|  |  | 
|  | pTempPtr += lstrlenW(DeviceDriverName) + 1; | 
|  | lstrcpyW(pTempPtr, DeviceName); | 
|  | lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; | 
|  |  | 
|  | pTempPtr += lstrlenW(DeviceName) + 1; | 
|  | lstrcpyW(pTempPtr, OutputPort); | 
|  | lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; | 
|  |  | 
|  | GetDefaultPrinterW(bufW, &dwBufLen); | 
|  | lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0; | 
|  | GlobalUnlock(*hmem); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *             PRINTDLG_UpdatePrintDlg          [internal] | 
|  | * | 
|  | * | 
|  | *   updates the PrintDlg structure for return values. | 
|  | * | 
|  | * RETURNS | 
|  | *   FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values) | 
|  | *   TRUE  if successful. | 
|  | */ | 
|  | static BOOL PRINTDLG_UpdatePrintDlgA(HWND hDlg, | 
|  | PRINT_PTRA* PrintStructures) | 
|  | { | 
|  | LPPRINTDLGA       lppd = PrintStructures->lpPrintDlg; | 
|  | PDEVMODEA         lpdm = PrintStructures->lpDevMode; | 
|  | LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo; | 
|  |  | 
|  |  | 
|  | if(!lpdm) { | 
|  | FIXME("No lpdm ptr?\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | if(!(lppd->Flags & PD_PRINTSETUP)) { | 
|  | /* check whether nFromPage and nToPage are within range defined by | 
|  | * nMinPage and nMaxPage | 
|  | */ | 
|  | if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ | 
|  | WORD nToPage; | 
|  | WORD nFromPage; | 
|  | BOOL translated; | 
|  | nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); | 
|  | nToPage   = GetDlgItemInt(hDlg, edt2, &translated, FALSE); | 
|  |  | 
|  | /* if no ToPage value is entered, use the FromPage value */ | 
|  | if(!translated) nToPage = nFromPage; | 
|  |  | 
|  | if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || | 
|  | nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { | 
|  | WCHAR resourcestr[256]; | 
|  | WCHAR resultstr[256]; | 
|  | LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, resourcestr, 255); | 
|  | wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage); | 
|  | LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, resourcestr, 255); | 
|  | MessageBoxW(hDlg, resultstr, resourcestr, MB_OK | MB_ICONWARNING); | 
|  | return FALSE; | 
|  | } | 
|  | lppd->nFromPage = nFromPage; | 
|  | lppd->nToPage   = nToPage; | 
|  | lppd->Flags |= PD_PAGENUMS; | 
|  | } | 
|  | else | 
|  | lppd->Flags &= ~PD_PAGENUMS; | 
|  |  | 
|  | if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */ | 
|  | lppd->Flags |= PD_SELECTION; | 
|  | else | 
|  | lppd->Flags &= ~PD_SELECTION; | 
|  |  | 
|  | if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ | 
|  | static char file[] = "FILE:"; | 
|  | lppd->Flags |= PD_PRINTTOFILE; | 
|  | pi->pPortName = file; | 
|  | } | 
|  |  | 
|  | if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ | 
|  | FIXME("Collate lppd not yet implemented as output\n"); | 
|  | } | 
|  |  | 
|  | /* set PD_Collate and nCopies */ | 
|  | if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { | 
|  | /*  The application doesn't support multiple copies or collate... | 
|  | */ | 
|  | lppd->Flags &= ~PD_COLLATE; | 
|  | lppd->nCopies = 1; | 
|  | /* if the printer driver supports it... store info there | 
|  | * otherwise no collate & multiple copies ! | 
|  | */ | 
|  | if (lpdm->dmFields & DM_COLLATE) | 
|  | lpdm->dmCollate = | 
|  | (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); | 
|  | if (lpdm->dmFields & DM_COPIES) | 
|  | lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); | 
|  | } else { | 
|  | /* Application is responsible for multiple copies */ | 
|  | if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) | 
|  | lppd->Flags |= PD_COLLATE; | 
|  | else | 
|  | lppd->Flags &= ~PD_COLLATE; | 
|  | lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); | 
|  | /* multiple copies already included in the document. Driver must print only one copy */ | 
|  | lpdm->u1.s1.dmCopies = 1; | 
|  | } | 
|  |  | 
|  | /* Print quality, PrintDlg16 */ | 
|  | if(GetDlgItem(hDlg, cmb1)) | 
|  | { | 
|  | HWND hQuality = GetDlgItem(hDlg, cmb1); | 
|  | int Sel = SendMessageA(hQuality, CB_GETCURSEL, 0, 0); | 
|  |  | 
|  | if(Sel != CB_ERR) | 
|  | { | 
|  | LONG dpi = SendMessageA(hQuality, CB_GETITEMDATA, Sel, 0); | 
|  | lpdm->dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION; | 
|  | lpdm->u1.s1.dmPrintQuality = LOWORD(dpi); | 
|  | lpdm->dmYResolution = HIWORD(dpi); | 
|  | } | 
|  | } | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL PRINTDLG_UpdatePrintDlgW(HWND hDlg, | 
|  | PRINT_PTRW* PrintStructures) | 
|  | { | 
|  | LPPRINTDLGW       lppd = PrintStructures->lpPrintDlg; | 
|  | PDEVMODEW         lpdm = PrintStructures->lpDevMode; | 
|  | LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo; | 
|  |  | 
|  |  | 
|  | if(!lpdm) { | 
|  | FIXME("No lpdm ptr?\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | if(!(lppd->Flags & PD_PRINTSETUP)) { | 
|  | /* check whether nFromPage and nToPage are within range defined by | 
|  | * nMinPage and nMaxPage | 
|  | */ | 
|  | if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ | 
|  | WORD nToPage; | 
|  | WORD nFromPage; | 
|  | BOOL translated; | 
|  | nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); | 
|  | nToPage   = GetDlgItemInt(hDlg, edt2, &translated, FALSE); | 
|  |  | 
|  | /* if no ToPage value is entered, use the FromPage value */ | 
|  | if(!translated) nToPage = nFromPage; | 
|  |  | 
|  | if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || | 
|  | nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { | 
|  | WCHAR resourcestr[256]; | 
|  | WCHAR resultstr[256]; | 
|  | LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, | 
|  | resourcestr, 255); | 
|  | wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage); | 
|  | LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, | 
|  | resourcestr, 255); | 
|  | MessageBoxW(hDlg, resultstr, resourcestr, | 
|  | MB_OK | MB_ICONWARNING); | 
|  | return FALSE; | 
|  | } | 
|  | lppd->nFromPage = nFromPage; | 
|  | lppd->nToPage   = nToPage; | 
|  | lppd->Flags |= PD_PAGENUMS; | 
|  | } | 
|  | else | 
|  | lppd->Flags &= ~PD_PAGENUMS; | 
|  |  | 
|  | if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */ | 
|  | lppd->Flags |= PD_SELECTION; | 
|  | else | 
|  | lppd->Flags &= ~PD_SELECTION; | 
|  |  | 
|  | if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ | 
|  | static WCHAR file[] = {'F','I','L','E',':',0}; | 
|  | lppd->Flags |= PD_PRINTTOFILE; | 
|  | pi->pPortName = file; | 
|  | } | 
|  |  | 
|  | if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ | 
|  | FIXME("Collate lppd not yet implemented as output\n"); | 
|  | } | 
|  |  | 
|  | /* set PD_Collate and nCopies */ | 
|  | if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { | 
|  | /*  The application doesn't support multiple copies or collate... | 
|  | */ | 
|  | lppd->Flags &= ~PD_COLLATE; | 
|  | lppd->nCopies = 1; | 
|  | /* if the printer driver supports it... store info there | 
|  | * otherwise no collate & multiple copies ! | 
|  | */ | 
|  | if (lpdm->dmFields & DM_COLLATE) | 
|  | lpdm->dmCollate = | 
|  | (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); | 
|  | if (lpdm->dmFields & DM_COPIES) | 
|  | lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); | 
|  | } else { | 
|  | if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) | 
|  | lppd->Flags |= PD_COLLATE; | 
|  | else | 
|  | lppd->Flags &= ~PD_COLLATE; | 
|  | lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); | 
|  | } | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * PRINTDLG_SetUpPaperComboBox | 
|  | * | 
|  | * Initialize either the papersize or inputslot combos of the Printer Setup | 
|  | * dialog.  We store the associated word (eg DMPAPER_A4) as the item data. | 
|  | * We also try to re-select the old selection. | 
|  | */ | 
|  | static BOOL PRINTDLG_SetUpPaperComboBoxA(HWND hDlg, | 
|  | int   nIDComboBox, | 
|  | char* PrinterName, | 
|  | char* PortName, | 
|  | LPDEVMODEA dm) | 
|  | { | 
|  | int     i; | 
|  | int     NrOfEntries; | 
|  | char*   Names; | 
|  | WORD*   Words; | 
|  | DWORD   Sel; | 
|  | WORD    oldWord = 0; | 
|  | int     NamesSize; | 
|  | int     fwCapability_Names; | 
|  | int     fwCapability_Words; | 
|  |  | 
|  | TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox); | 
|  |  | 
|  | /* query the dialog box for the current selected value */ | 
|  | Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); | 
|  | if(Sel != CB_ERR) { | 
|  | /* we enter here only if a different printer is selected after | 
|  | * the Print Setup dialog is opened. The current settings are | 
|  | * stored into the newly selected printer. | 
|  | */ | 
|  | oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, | 
|  | Sel, 0); | 
|  | if (dm) { | 
|  | if (nIDComboBox == cmb2) | 
|  | dm->u1.s1.dmPaperSize = oldWord; | 
|  | else | 
|  | dm->u1.s1.dmDefaultSource = oldWord; | 
|  | } | 
|  | } | 
|  | else { | 
|  | /* we enter here only when the Print setup dialog is initially | 
|  | * opened. In this case the settings are restored from when | 
|  | * the dialog was last closed. | 
|  | */ | 
|  | if (dm) { | 
|  | if (nIDComboBox == cmb2) | 
|  | oldWord = dm->u1.s1.dmPaperSize; | 
|  | else | 
|  | oldWord = dm->u1.s1.dmDefaultSource; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (nIDComboBox == cmb2) { | 
|  | NamesSize          = 64; | 
|  | fwCapability_Names = DC_PAPERNAMES; | 
|  | fwCapability_Words = DC_PAPERS; | 
|  | } else { | 
|  | nIDComboBox        = cmb3; | 
|  | NamesSize          = 24; | 
|  | fwCapability_Names = DC_BINNAMES; | 
|  | fwCapability_Words = DC_BINS; | 
|  | } | 
|  |  | 
|  | NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, | 
|  | fwCapability_Names, NULL, dm); | 
|  | if (NrOfEntries == 0) | 
|  | WARN("no Name Entries found!\n"); | 
|  | else if (NrOfEntries < 0) | 
|  | return FALSE; | 
|  |  | 
|  | if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm) | 
|  | != NrOfEntries) { | 
|  | ERR("Number of caps is different\n"); | 
|  | NrOfEntries = 0; | 
|  | } | 
|  |  | 
|  | Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize); | 
|  | Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); | 
|  | NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, | 
|  | fwCapability_Names, Names, dm); | 
|  | NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, | 
|  | fwCapability_Words, (LPSTR)Words, dm); | 
|  |  | 
|  | /* reset any current content in the combobox */ | 
|  | SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); | 
|  |  | 
|  | /* store new content */ | 
|  | for (i = 0; i < NrOfEntries; i++) { | 
|  | DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0, | 
|  | (LPARAM)(&Names[i*NamesSize]) ); | 
|  | SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos, | 
|  | Words[i]); | 
|  | } | 
|  |  | 
|  | /* Look for old selection - can't do this is previous loop since | 
|  | item order will change as more items are added */ | 
|  | Sel = 0; | 
|  | for (i = 0; i < NrOfEntries; i++) { | 
|  | if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == | 
|  | oldWord) { | 
|  | Sel = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,Words); | 
|  | HeapFree(GetProcessHeap(),0,Names); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL PRINTDLG_SetUpPaperComboBoxW(HWND hDlg, | 
|  | int   nIDComboBox, | 
|  | const WCHAR* PrinterName, | 
|  | const WCHAR* PortName, | 
|  | LPDEVMODEW dm) | 
|  | { | 
|  | int     i; | 
|  | int     NrOfEntries; | 
|  | WCHAR*  Names; | 
|  | WORD*   Words; | 
|  | DWORD   Sel; | 
|  | WORD    oldWord = 0; | 
|  | int     NamesSize; | 
|  | int     fwCapability_Names; | 
|  | int     fwCapability_Words; | 
|  |  | 
|  | TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox); | 
|  |  | 
|  | /* query the dialog box for the current selected value */ | 
|  | Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); | 
|  | if(Sel != CB_ERR) { | 
|  | /* we enter here only if a different printer is selected after | 
|  | * the Print Setup dialog is opened. The current settings are | 
|  | * stored into the newly selected printer. | 
|  | */ | 
|  | oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, | 
|  | Sel, 0); | 
|  | if (dm) { | 
|  | if (nIDComboBox == cmb2) | 
|  | dm->u1.s1.dmPaperSize = oldWord; | 
|  | else | 
|  | dm->u1.s1.dmDefaultSource = oldWord; | 
|  | } | 
|  | } | 
|  | else { | 
|  | /* we enter here only when the Print setup dialog is initially | 
|  | * opened. In this case the settings are restored from when | 
|  | * the dialog was last closed. | 
|  | */ | 
|  | if (dm) { | 
|  | if (nIDComboBox == cmb2) | 
|  | oldWord = dm->u1.s1.dmPaperSize; | 
|  | else | 
|  | oldWord = dm->u1.s1.dmDefaultSource; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (nIDComboBox == cmb2) { | 
|  | NamesSize          = 64; | 
|  | fwCapability_Names = DC_PAPERNAMES; | 
|  | fwCapability_Words = DC_PAPERS; | 
|  | } else { | 
|  | nIDComboBox        = cmb3; | 
|  | NamesSize          = 24; | 
|  | fwCapability_Names = DC_BINNAMES; | 
|  | fwCapability_Words = DC_BINS; | 
|  | } | 
|  |  | 
|  | NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, | 
|  | fwCapability_Names, NULL, dm); | 
|  | if (NrOfEntries == 0) | 
|  | WARN("no Name Entries found!\n"); | 
|  | else if (NrOfEntries < 0) | 
|  | return FALSE; | 
|  |  | 
|  | if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm) | 
|  | != NrOfEntries) { | 
|  | ERR("Number of caps is different\n"); | 
|  | NrOfEntries = 0; | 
|  | } | 
|  |  | 
|  | Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize); | 
|  | Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); | 
|  | NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, | 
|  | fwCapability_Names, Names, dm); | 
|  | NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, | 
|  | fwCapability_Words, Words, dm); | 
|  |  | 
|  | /* reset any current content in the combobox */ | 
|  | SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); | 
|  |  | 
|  | /* store new content */ | 
|  | for (i = 0; i < NrOfEntries; i++) { | 
|  | DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0, | 
|  | (LPARAM)(&Names[i*NamesSize]) ); | 
|  | SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos, | 
|  | Words[i]); | 
|  | } | 
|  |  | 
|  | /* Look for old selection - can't do this is previous loop since | 
|  | item order will change as more items are added */ | 
|  | Sel = 0; | 
|  | for (i = 0; i < NrOfEntries; i++) { | 
|  | if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == | 
|  | oldWord) { | 
|  | Sel = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,Words); | 
|  | HeapFree(GetProcessHeap(),0,Names); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *               PRINTDLG_UpdatePrinterInfoTexts               [internal] | 
|  | */ | 
|  | static void PRINTDLG_UpdatePrinterInfoTextsA(HWND hDlg, const PRINTER_INFO_2A *pi) | 
|  | { | 
|  | char   StatusMsg[256]; | 
|  | char   ResourceString[256]; | 
|  | int    i; | 
|  |  | 
|  | /* Status Message */ | 
|  | StatusMsg[0]='\0'; | 
|  |  | 
|  | /* add all status messages */ | 
|  | for (i = 0; i < 25; i++) { | 
|  | if (pi->Status & (1<<i)) { | 
|  | LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i, | 
|  | ResourceString, 255); | 
|  | strcat(StatusMsg,ResourceString); | 
|  | } | 
|  | } | 
|  | /* append "ready" */ | 
|  | /* FIXME: status==ready must only be appended if really so. | 
|  | but how to detect? */ | 
|  | LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY, | 
|  | ResourceString, 255); | 
|  | strcat(StatusMsg,ResourceString); | 
|  | SetDlgItemTextA(hDlg, stc12, StatusMsg); | 
|  |  | 
|  | /* set all other printer info texts */ | 
|  | SetDlgItemTextA(hDlg, stc11, pi->pDriverName); | 
|  |  | 
|  | if (pi->pLocation != NULL && pi->pLocation[0] != '\0') | 
|  | SetDlgItemTextA(hDlg, stc14, pi->pLocation); | 
|  | else | 
|  | SetDlgItemTextA(hDlg, stc14, pi->pPortName); | 
|  | SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : ""); | 
|  | return; | 
|  | } | 
|  |  | 
|  | static void PRINTDLG_UpdatePrinterInfoTextsW(HWND hDlg, const PRINTER_INFO_2W *pi) | 
|  | { | 
|  | WCHAR   StatusMsg[256]; | 
|  | WCHAR   ResourceString[256]; | 
|  | static const WCHAR emptyW[] = {0}; | 
|  | int    i; | 
|  |  | 
|  | /* Status Message */ | 
|  | StatusMsg[0]='\0'; | 
|  |  | 
|  | /* add all status messages */ | 
|  | for (i = 0; i < 25; i++) { | 
|  | if (pi->Status & (1<<i)) { | 
|  | LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i, | 
|  | ResourceString, 255); | 
|  | lstrcatW(StatusMsg,ResourceString); | 
|  | } | 
|  | } | 
|  | /* append "ready" */ | 
|  | /* FIXME: status==ready must only be appended if really so. | 
|  | but how to detect? */ | 
|  | LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY, | 
|  | ResourceString, 255); | 
|  | lstrcatW(StatusMsg,ResourceString); | 
|  | SetDlgItemTextW(hDlg, stc12, StatusMsg); | 
|  |  | 
|  | /* set all other printer info texts */ | 
|  | SetDlgItemTextW(hDlg, stc11, pi->pDriverName); | 
|  | if (pi->pLocation != NULL && pi->pLocation[0] != '\0') | 
|  | SetDlgItemTextW(hDlg, stc14, pi->pLocation); | 
|  | else | 
|  | SetDlgItemTextW(hDlg, stc14, pi->pPortName); | 
|  | SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW); | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************* | 
|  | * | 
|  | *                 PRINTDLG_ChangePrinter | 
|  | * | 
|  | */ | 
|  | static BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, PRINT_PTRA *PrintStructures) | 
|  | { | 
|  | LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; | 
|  | LPDEVMODEA lpdm = NULL; | 
|  | LONG dmSize; | 
|  | DWORD needed; | 
|  | HANDLE hprn; | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); | 
|  | HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); | 
|  | if(!OpenPrinterA(name, &hprn, NULL)) { | 
|  | ERR("Can't open printer %s\n", name); | 
|  | return FALSE; | 
|  | } | 
|  | GetPrinterA(hprn, 2, NULL, 0, &needed); | 
|  | PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed); | 
|  | GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, | 
|  | &needed); | 
|  | GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); | 
|  | PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed); | 
|  | if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, | 
|  | needed, &needed)) { | 
|  | ERR("GetPrinterDriverA failed for %s, fix your config!\n",PrintStructures->lpPrinterInfo->pPrinterName); | 
|  | return FALSE; | 
|  | } | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | PRINTDLG_UpdatePrinterInfoTextsA(hDlg, PrintStructures->lpPrinterInfo); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); | 
|  | PrintStructures->lpDevMode = NULL; | 
|  |  | 
|  | dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0); | 
|  | if(dmSize == -1) { | 
|  | ERR("DocumentProperties fails on %s\n", debugstr_a(name)); | 
|  | return FALSE; | 
|  | } | 
|  | PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); | 
|  | dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL, | 
|  | DM_OUT_BUFFER); | 
|  | if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && | 
|  | !lstrcmpA( (LPSTR) lpdm->dmDeviceName, | 
|  | (LPSTR) PrintStructures->lpDevMode->dmDeviceName)) { | 
|  | /* Supplied devicemode matches current printer so try to use it */ | 
|  | DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm, | 
|  | DM_OUT_BUFFER | DM_IN_BUFFER); | 
|  | } | 
|  | if(lpdm) | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  |  | 
|  | lpdm = PrintStructures->lpDevMode;  /* use this as a shortcut */ | 
|  |  | 
|  | if(!(lppd->Flags & PD_PRINTSETUP)) { | 
|  | /* Print range (All/Range/Selection) */ | 
|  | if(lppd->nFromPage != 0xffff) | 
|  | SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); | 
|  | if(lppd->nToPage != 0xffff) | 
|  | SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); | 
|  |  | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad1);		/* default */ | 
|  | if (lppd->Flags & PD_NOSELECTION) | 
|  | EnableWindow(GetDlgItem(hDlg, rad2), FALSE); | 
|  | else | 
|  | if (lppd->Flags & PD_SELECTION) | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad2); | 
|  | if (lppd->Flags & PD_NOPAGENUMS) { | 
|  | EnableWindow(GetDlgItem(hDlg, rad3), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, stc2),FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, edt1), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, stc3),FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, edt2), FALSE); | 
|  | } else { | 
|  | if (lppd->Flags & PD_PAGENUMS) | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad3); | 
|  | } | 
|  |  | 
|  | /* Collate pages | 
|  | * | 
|  | * FIXME: The ico3 is not displayed for some reason. I don't know why. | 
|  | */ | 
|  | if (lppd->Flags & PD_COLLATE) { | 
|  | SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hCollateIcon); | 
|  | CheckDlgButton(hDlg, chx2, 1); | 
|  | } else { | 
|  | SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hNoCollateIcon); | 
|  | CheckDlgButton(hDlg, chx2, 0); | 
|  | } | 
|  |  | 
|  | if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { | 
|  | /* if printer doesn't support it: no Collate */ | 
|  | if (!(lpdm->dmFields & DM_COLLATE)) { | 
|  | EnableWindow(GetDlgItem(hDlg, chx2), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, ico3), FALSE); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* nCopies */ | 
|  | { | 
|  | INT copies; | 
|  | if (lppd->hDevMode == 0) | 
|  | copies = lppd->nCopies; | 
|  | else | 
|  | copies = lpdm->u1.s1.dmCopies; | 
|  | if(copies == 0) copies = 1; | 
|  | else if(copies < 0) copies = MAX_COPIES; | 
|  | SetDlgItemInt(hDlg, edt3, copies, FALSE); | 
|  | } | 
|  |  | 
|  | if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { | 
|  | /* if printer doesn't support it: no nCopies */ | 
|  | if (!(lpdm->dmFields & DM_COPIES)) { | 
|  | EnableWindow(GetDlgItem(hDlg, edt3), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, stc5), FALSE); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* print to file */ | 
|  | CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); | 
|  | if (lppd->Flags & PD_DISABLEPRINTTOFILE) | 
|  | EnableWindow(GetDlgItem(hDlg, chx1), FALSE); | 
|  | if (lppd->Flags & PD_HIDEPRINTTOFILE) | 
|  | ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); | 
|  |  | 
|  | /* Fill print quality combo, PrintDlg16 */ | 
|  | if(GetDlgItem(hDlg, cmb1)) | 
|  | { | 
|  | DWORD numResolutions = DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName, | 
|  | PrintStructures->lpPrinterInfo->pPortName, | 
|  | DC_ENUMRESOLUTIONS, NULL, lpdm); | 
|  |  | 
|  | if(numResolutions != -1) | 
|  | { | 
|  | HWND hQuality = GetDlgItem(hDlg, cmb1); | 
|  | LONG* Resolutions; | 
|  | char buf[255]; | 
|  | DWORD i; | 
|  | int dpiX, dpiY; | 
|  | HDC hPrinterDC = CreateDCA(PrintStructures->lpPrinterInfo->pDriverName, | 
|  | PrintStructures->lpPrinterInfo->pPrinterName, | 
|  | 0, lpdm); | 
|  |  | 
|  | Resolutions = HeapAlloc(GetProcessHeap(), 0, numResolutions*sizeof(LONG)*2); | 
|  | DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName, | 
|  | PrintStructures->lpPrinterInfo->pPortName, | 
|  | DC_ENUMRESOLUTIONS, (LPSTR)Resolutions, lpdm); | 
|  |  | 
|  | dpiX = GetDeviceCaps(hPrinterDC, LOGPIXELSX); | 
|  | dpiY = GetDeviceCaps(hPrinterDC, LOGPIXELSY); | 
|  | DeleteDC(hPrinterDC); | 
|  |  | 
|  | SendMessageA(hQuality, CB_RESETCONTENT, 0, 0); | 
|  | for(i = 0; i < (numResolutions * 2); i += 2) | 
|  | { | 
|  | BOOL IsDefault = FALSE; | 
|  | LRESULT Index; | 
|  |  | 
|  | if(Resolutions[i] == Resolutions[i+1]) | 
|  | { | 
|  | if(dpiX == Resolutions[i]) | 
|  | IsDefault = TRUE; | 
|  | sprintf(buf, "%d dpi", Resolutions[i]); | 
|  | } else | 
|  | { | 
|  | if(dpiX == Resolutions[i] && dpiY == Resolutions[i+1]) | 
|  | IsDefault = TRUE; | 
|  | sprintf(buf, "%d dpi x %d dpi", Resolutions[i], Resolutions[i+1]); | 
|  | } | 
|  |  | 
|  | Index = SendMessageA(hQuality, CB_ADDSTRING, 0, (LPARAM)buf); | 
|  |  | 
|  | if(IsDefault) | 
|  | SendMessageA(hQuality, CB_SETCURSEL, Index, 0); | 
|  |  | 
|  | SendMessageA(hQuality, CB_SETITEMDATA, Index, MAKELONG(dpiX,dpiY)); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, Resolutions); | 
|  | } | 
|  | } | 
|  | } else { /* PD_PRINTSETUP */ | 
|  | BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT); | 
|  |  | 
|  | PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb2, | 
|  | PrintStructures->lpPrinterInfo->pPrinterName, | 
|  | PrintStructures->lpPrinterInfo->pPortName, | 
|  | lpdm); | 
|  | PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb3, | 
|  | PrintStructures->lpPrinterInfo->pPrinterName, | 
|  | PrintStructures->lpPrinterInfo->pPortName, | 
|  | lpdm); | 
|  | CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); | 
|  | SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : | 
|  | PrintStructures->hLandscapeIcon)); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* help button */ | 
|  | if ((lppd->Flags & PD_SHOWHELP)==0) { | 
|  | /* hide if PD_SHOWHELP not specified */ | 
|  | ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL PRINTDLG_ChangePrinterW(HWND hDlg, WCHAR *name, | 
|  | PRINT_PTRW *PrintStructures) | 
|  | { | 
|  | LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; | 
|  | LPDEVMODEW lpdm = NULL; | 
|  | LONG dmSize; | 
|  | DWORD needed; | 
|  | HANDLE hprn; | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); | 
|  | HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); | 
|  | if(!OpenPrinterW(name, &hprn, NULL)) { | 
|  | ERR("Can't open printer %s\n", debugstr_w(name)); | 
|  | return FALSE; | 
|  | } | 
|  | GetPrinterW(hprn, 2, NULL, 0, &needed); | 
|  | PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed); | 
|  | GetPrinterW(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, | 
|  | &needed); | 
|  | GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); | 
|  | PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed); | 
|  | if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, | 
|  | needed, &needed)) { | 
|  | ERR("GetPrinterDriverA failed for %s, fix your config!\n",debugstr_w(PrintStructures->lpPrinterInfo->pPrinterName)); | 
|  | return FALSE; | 
|  | } | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | PRINTDLG_UpdatePrinterInfoTextsW(hDlg, PrintStructures->lpPrinterInfo); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); | 
|  | PrintStructures->lpDevMode = NULL; | 
|  |  | 
|  | dmSize = DocumentPropertiesW(0, 0, name, NULL, NULL, 0); | 
|  | if(dmSize == -1) { | 
|  | ERR("DocumentProperties fails on %s\n", debugstr_w(name)); | 
|  | return FALSE; | 
|  | } | 
|  | PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); | 
|  | dmSize = DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, NULL, | 
|  | DM_OUT_BUFFER); | 
|  | if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && | 
|  | !lstrcmpW(lpdm->dmDeviceName, | 
|  | PrintStructures->lpDevMode->dmDeviceName)) { | 
|  | /* Supplied devicemode matches current printer so try to use it */ | 
|  | DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, lpdm, | 
|  | DM_OUT_BUFFER | DM_IN_BUFFER); | 
|  | } | 
|  | if(lpdm) | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  |  | 
|  | lpdm = PrintStructures->lpDevMode;  /* use this as a shortcut */ | 
|  |  | 
|  | if(!(lppd->Flags & PD_PRINTSETUP)) { | 
|  | /* Print range (All/Range/Selection) */ | 
|  | if(lppd->nFromPage != 0xffff) | 
|  | SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); | 
|  | if(lppd->nToPage != 0xffff) | 
|  | SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); | 
|  |  | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad1);		/* default */ | 
|  | if (lppd->Flags & PD_NOSELECTION) | 
|  | EnableWindow(GetDlgItem(hDlg, rad2), FALSE); | 
|  | else | 
|  | if (lppd->Flags & PD_SELECTION) | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad2); | 
|  | if (lppd->Flags & PD_NOPAGENUMS) { | 
|  | EnableWindow(GetDlgItem(hDlg, rad3), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, stc2),FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, edt1), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, stc3),FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, edt2), FALSE); | 
|  | } else { | 
|  | if (lppd->Flags & PD_PAGENUMS) | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad3); | 
|  | } | 
|  |  | 
|  | /* Collate pages | 
|  | * | 
|  | * FIXME: The ico3 is not displayed for some reason. I don't know why. | 
|  | */ | 
|  | if (lppd->Flags & PD_COLLATE) { | 
|  | SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hCollateIcon); | 
|  | CheckDlgButton(hDlg, chx2, 1); | 
|  | } else { | 
|  | SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hNoCollateIcon); | 
|  | CheckDlgButton(hDlg, chx2, 0); | 
|  | } | 
|  |  | 
|  | if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { | 
|  | /* if printer doesn't support it: no Collate */ | 
|  | if (!(lpdm->dmFields & DM_COLLATE)) { | 
|  | EnableWindow(GetDlgItem(hDlg, chx2), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, ico3), FALSE); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* nCopies */ | 
|  | { | 
|  | INT copies; | 
|  | if (lppd->hDevMode == 0) | 
|  | copies = lppd->nCopies; | 
|  | else | 
|  | copies = lpdm->u1.s1.dmCopies; | 
|  | if(copies == 0) copies = 1; | 
|  | else if(copies < 0) copies = MAX_COPIES; | 
|  | SetDlgItemInt(hDlg, edt3, copies, FALSE); | 
|  | } | 
|  |  | 
|  | if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { | 
|  | /* if printer doesn't support it: no nCopies */ | 
|  | if (!(lpdm->dmFields & DM_COPIES)) { | 
|  | EnableWindow(GetDlgItem(hDlg, edt3), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, stc5), FALSE); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* print to file */ | 
|  | CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); | 
|  | if (lppd->Flags & PD_DISABLEPRINTTOFILE) | 
|  | EnableWindow(GetDlgItem(hDlg, chx1), FALSE); | 
|  | if (lppd->Flags & PD_HIDEPRINTTOFILE) | 
|  | ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); | 
|  |  | 
|  | } else { /* PD_PRINTSETUP */ | 
|  | BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT); | 
|  |  | 
|  | PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, | 
|  | PrintStructures->lpPrinterInfo->pPrinterName, | 
|  | PrintStructures->lpPrinterInfo->pPortName, | 
|  | lpdm); | 
|  | PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, | 
|  | PrintStructures->lpPrinterInfo->pPrinterName, | 
|  | PrintStructures->lpPrinterInfo->pPortName, | 
|  | lpdm); | 
|  | CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); | 
|  | SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : | 
|  | PrintStructures->hLandscapeIcon)); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* help button */ | 
|  | if ((lppd->Flags & PD_SHOWHELP)==0) { | 
|  | /* hide if PD_SHOWHELP not specified */ | 
|  | ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           check_printer_setup			[internal] | 
|  | */ | 
|  | static LRESULT check_printer_setup(HWND hDlg) | 
|  | { | 
|  | DWORD needed,num; | 
|  | WCHAR resourcestr[256],resultstr[256]; | 
|  |  | 
|  | EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); | 
|  | if(needed == 0) | 
|  | { | 
|  | EnumPrintersW(PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &num); | 
|  | } | 
|  | if(needed > 0) | 
|  | return TRUE; | 
|  | else | 
|  | { | 
|  | LoadStringW(COMDLG32_hInstance, PD32_NO_DEVICES,resultstr, 255); | 
|  | LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,resourcestr, 255); | 
|  | MessageBoxW(hDlg, resultstr, resourcestr,MB_OK | MB_ICONWARNING); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PRINTDLG_WMInitDialog                      [internal] | 
|  | */ | 
|  | static LRESULT PRINTDLG_WMInitDialog(HWND hDlg, | 
|  | PRINT_PTRA* PrintStructures) | 
|  | { | 
|  | LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; | 
|  | DEVNAMES *pdn; | 
|  | DEVMODEA *pdm; | 
|  | char *name = NULL; | 
|  | UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; | 
|  |  | 
|  | /* load Collate ICONs */ | 
|  | /* We load these with LoadImage because they are not a standard | 
|  | size and we don't want them rescaled */ | 
|  | PrintStructures->hCollateIcon = | 
|  | LoadImageA(COMDLG32_hInstance, "PD32_COLLATE", IMAGE_ICON, 0, 0, 0); | 
|  | PrintStructures->hNoCollateIcon = | 
|  | LoadImageA(COMDLG32_hInstance, "PD32_NOCOLLATE", IMAGE_ICON, 0, 0, 0); | 
|  |  | 
|  | /* These can be done with LoadIcon */ | 
|  | PrintStructures->hPortraitIcon = | 
|  | LoadIconA(COMDLG32_hInstance, "PD32_PORTRAIT"); | 
|  | PrintStructures->hLandscapeIcon = | 
|  | LoadIconA(COMDLG32_hInstance, "PD32_LANDSCAPE"); | 
|  |  | 
|  | /* display the collate/no_collate icon */ | 
|  | SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hNoCollateIcon); | 
|  |  | 
|  | if(PrintStructures->hCollateIcon == 0 || | 
|  | PrintStructures->hNoCollateIcon == 0 || | 
|  | PrintStructures->hPortraitIcon == 0 || | 
|  | PrintStructures->hLandscapeIcon == 0) { | 
|  | ERR("no icon in resourcefile\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); | 
|  | EndDialog(hDlg, FALSE); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message | 
|  | * must be registered and the Help button must be shown. | 
|  | */ | 
|  | if (lppd->Flags & PD_SHOWHELP) { | 
|  | if((PrintStructures->HelpMessageID = | 
|  | RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); | 
|  | return FALSE; | 
|  | } | 
|  | } else | 
|  | PrintStructures->HelpMessageID = 0; | 
|  |  | 
|  | if(!(lppd->Flags &PD_PRINTSETUP)) { | 
|  | PrintStructures->hwndUpDown = | 
|  | CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | | 
|  | UDS_NOTHOUSANDS | UDS_ARROWKEYS | | 
|  | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, | 
|  | hDlg, UPDOWN_ID, COMDLG32_hInstance, | 
|  | GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); | 
|  | } | 
|  |  | 
|  | /* FIXME: I allow more freedom than either Win95 or WinNT, | 
|  | *        which do not agree to what errors should be thrown or not | 
|  | *        in case nToPage or nFromPage is out-of-range. | 
|  | */ | 
|  | if (lppd->nMaxPage < lppd->nMinPage) | 
|  | lppd->nMaxPage = lppd->nMinPage; | 
|  | if (lppd->nMinPage == lppd->nMaxPage) | 
|  | lppd->Flags |= PD_NOPAGENUMS; | 
|  | if (lppd->nToPage < lppd->nMinPage) | 
|  | lppd->nToPage = lppd->nMinPage; | 
|  | if (lppd->nToPage > lppd->nMaxPage) | 
|  | lppd->nToPage = lppd->nMaxPage; | 
|  | if (lppd->nFromPage < lppd->nMinPage) | 
|  | lppd->nFromPage = lppd->nMinPage; | 
|  | if (lppd->nFromPage > lppd->nMaxPage) | 
|  | lppd->nFromPage = lppd->nMaxPage; | 
|  |  | 
|  | /* if we have the combo box, fill it */ | 
|  | if (GetDlgItem(hDlg,comboID)) { | 
|  | /* Fill Combobox | 
|  | */ | 
|  | pdn = GlobalLock(lppd->hDevNames); | 
|  | pdm = GlobalLock(lppd->hDevMode); | 
|  | if(pdn) | 
|  | name = (char*)pdn + pdn->wDeviceOffset; | 
|  | else if(pdm) | 
|  | name = (char*)pdm->dmDeviceName; | 
|  | PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name); | 
|  | if(pdm) GlobalUnlock(lppd->hDevMode); | 
|  | if(pdn) GlobalUnlock(lppd->hDevNames); | 
|  |  | 
|  | /* Now find selected printer and update rest of dlg */ | 
|  | name = HeapAlloc(GetProcessHeap(),0,256); | 
|  | if (GetDlgItemTextA(hDlg, comboID, name, 255)) | 
|  | PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); | 
|  | HeapFree(GetProcessHeap(),0,name); | 
|  | } else { | 
|  | /* else use default printer */ | 
|  | char name[200]; | 
|  | DWORD dwBufLen = sizeof(name); | 
|  | BOOL ret = GetDefaultPrinterA(name, &dwBufLen); | 
|  |  | 
|  | if (ret) | 
|  | PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); | 
|  | else | 
|  | FIXME("No default printer found, expect problems!\n"); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static LRESULT PRINTDLG_WMInitDialogW(HWND hDlg, | 
|  | PRINT_PTRW* PrintStructures) | 
|  | { | 
|  | LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; | 
|  | DEVNAMES *pdn; | 
|  | DEVMODEW *pdm; | 
|  | WCHAR *name = NULL; | 
|  | UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; | 
|  |  | 
|  | /* load Collate ICONs */ | 
|  | /* We load these with LoadImage because they are not a standard | 
|  | size and we don't want them rescaled */ | 
|  | PrintStructures->hCollateIcon = | 
|  | LoadImageW(COMDLG32_hInstance, pd32_collateW, IMAGE_ICON, 0, 0, 0); | 
|  | PrintStructures->hNoCollateIcon = | 
|  | LoadImageW(COMDLG32_hInstance, pd32_nocollateW, IMAGE_ICON, 0, 0, 0); | 
|  |  | 
|  | /* These can be done with LoadIcon */ | 
|  | PrintStructures->hPortraitIcon = | 
|  | LoadIconW(COMDLG32_hInstance, pd32_portraitW); | 
|  | PrintStructures->hLandscapeIcon = | 
|  | LoadIconW(COMDLG32_hInstance, pd32_landscapeW); | 
|  |  | 
|  | /* display the collate/no_collate icon */ | 
|  | SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hNoCollateIcon); | 
|  |  | 
|  | if(PrintStructures->hCollateIcon == 0 || | 
|  | PrintStructures->hNoCollateIcon == 0 || | 
|  | PrintStructures->hPortraitIcon == 0 || | 
|  | PrintStructures->hLandscapeIcon == 0) { | 
|  | ERR("no icon in resourcefile\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); | 
|  | EndDialog(hDlg, FALSE); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message | 
|  | * must be registered and the Help button must be shown. | 
|  | */ | 
|  | if (lppd->Flags & PD_SHOWHELP) { | 
|  | if((PrintStructures->HelpMessageID = | 
|  | RegisterWindowMessageW(HELPMSGSTRINGW)) == 0) { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); | 
|  | return FALSE; | 
|  | } | 
|  | } else | 
|  | PrintStructures->HelpMessageID = 0; | 
|  |  | 
|  | if(!(lppd->Flags &PD_PRINTSETUP)) { | 
|  | PrintStructures->hwndUpDown = | 
|  | CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | | 
|  | UDS_NOTHOUSANDS | UDS_ARROWKEYS | | 
|  | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, | 
|  | hDlg, UPDOWN_ID, COMDLG32_hInstance, | 
|  | GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); | 
|  | } | 
|  |  | 
|  | /* FIXME: I allow more freedom than either Win95 or WinNT, | 
|  | *        which do not agree to what errors should be thrown or not | 
|  | *        in case nToPage or nFromPage is out-of-range. | 
|  | */ | 
|  | if (lppd->nMaxPage < lppd->nMinPage) | 
|  | lppd->nMaxPage = lppd->nMinPage; | 
|  | if (lppd->nMinPage == lppd->nMaxPage) | 
|  | lppd->Flags |= PD_NOPAGENUMS; | 
|  | if (lppd->nToPage < lppd->nMinPage) | 
|  | lppd->nToPage = lppd->nMinPage; | 
|  | if (lppd->nToPage > lppd->nMaxPage) | 
|  | lppd->nToPage = lppd->nMaxPage; | 
|  | if (lppd->nFromPage < lppd->nMinPage) | 
|  | lppd->nFromPage = lppd->nMinPage; | 
|  | if (lppd->nFromPage > lppd->nMaxPage) | 
|  | lppd->nFromPage = lppd->nMaxPage; | 
|  |  | 
|  | /* if we have the combo box, fill it */ | 
|  | if (GetDlgItem(hDlg,comboID)) { | 
|  | /* Fill Combobox | 
|  | */ | 
|  | pdn = GlobalLock(lppd->hDevNames); | 
|  | pdm = GlobalLock(lppd->hDevMode); | 
|  | if(pdn) | 
|  | name = (WCHAR*)pdn + pdn->wDeviceOffset; | 
|  | else if(pdm) | 
|  | name = pdm->dmDeviceName; | 
|  | PRINTDLG_SetUpPrinterListComboW(hDlg, comboID, name); | 
|  | if(pdm) GlobalUnlock(lppd->hDevMode); | 
|  | if(pdn) GlobalUnlock(lppd->hDevNames); | 
|  |  | 
|  | /* Now find selected printer and update rest of dlg */ | 
|  | /* ansi is ok here */ | 
|  | name = HeapAlloc(GetProcessHeap(),0,256*sizeof(WCHAR)); | 
|  | if (GetDlgItemTextW(hDlg, comboID, name, 255)) | 
|  | PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); | 
|  | HeapFree(GetProcessHeap(),0,name); | 
|  | } else { | 
|  | /* else use default printer */ | 
|  | WCHAR name[200]; | 
|  | DWORD dwBufLen = sizeof(name) / sizeof(WCHAR); | 
|  | BOOL ret = GetDefaultPrinterW(name, &dwBufLen); | 
|  |  | 
|  | if (ret) | 
|  | PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); | 
|  | else | 
|  | FIXME("No default printer found, expect problems!\n"); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                              PRINTDLG_WMCommand               [internal] | 
|  | */ | 
|  | static LRESULT PRINTDLG_WMCommandA(HWND hDlg, WPARAM wParam, | 
|  | PRINT_PTRA* PrintStructures) | 
|  | { | 
|  | LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; | 
|  | UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; | 
|  | LPDEVMODEA lpdm = PrintStructures->lpDevMode; | 
|  |  | 
|  | switch (LOWORD(wParam))  { | 
|  | case IDOK: | 
|  | TRACE(" OK button was hit\n"); | 
|  | if (!PRINTDLG_UpdatePrintDlgA(hDlg, PrintStructures)) { | 
|  | FIXME("Update printdlg was not successful!\n"); | 
|  | return(FALSE); | 
|  | } | 
|  | EndDialog(hDlg, TRUE); | 
|  | return(TRUE); | 
|  |  | 
|  | case IDCANCEL: | 
|  | TRACE(" CANCEL button was hit\n"); | 
|  | EndDialog(hDlg, FALSE); | 
|  | return(FALSE); | 
|  |  | 
|  | case pshHelp: | 
|  | TRACE(" HELP button was hit\n"); | 
|  | SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID, | 
|  | (WPARAM) hDlg, (LPARAM) lppd); | 
|  | break; | 
|  |  | 
|  | case chx2:                         /* collate pages checkbox */ | 
|  | if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) | 
|  | SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hCollateIcon); | 
|  | else | 
|  | SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hNoCollateIcon); | 
|  | break; | 
|  | case edt1:                         /* from page nr editbox */ | 
|  | case edt2:                         /* to page nr editbox */ | 
|  | if (HIWORD(wParam)==EN_CHANGE) { | 
|  | WORD nToPage; | 
|  | WORD nFromPage; | 
|  | nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); | 
|  | nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE); | 
|  | if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad3); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case edt3: | 
|  | if(HIWORD(wParam) == EN_CHANGE) { | 
|  | INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); | 
|  | if(copies <= 1) | 
|  | EnableWindow(GetDlgItem(hDlg, chx2), FALSE); | 
|  | else | 
|  | EnableWindow(GetDlgItem(hDlg, chx2), TRUE); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case psh2:                       /* Properties button */ | 
|  | { | 
|  | HANDLE hPrinter; | 
|  | char   PrinterName[256]; | 
|  |  | 
|  | GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255); | 
|  | if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) { | 
|  | FIXME(" Call to OpenPrinter did not succeed!\n"); | 
|  | break; | 
|  | } | 
|  | DocumentPropertiesA(hDlg, hPrinter, PrinterName, | 
|  | PrintStructures->lpDevMode, | 
|  | PrintStructures->lpDevMode, | 
|  | DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); | 
|  | ClosePrinter(hPrinter); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case rad1: /* Paperorientation */ | 
|  | if (lppd->Flags & PD_PRINTSETUP) | 
|  | { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; | 
|  | SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)(PrintStructures->hPortraitIcon)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case rad2: /* Paperorientation */ | 
|  | if (lppd->Flags & PD_PRINTSETUP) | 
|  | { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; | 
|  | SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)(PrintStructures->hLandscapeIcon)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT16 */ | 
|  | if (PrinterComboID != LOWORD(wParam)) { | 
|  | break; | 
|  | } | 
|  | /* FALLTHROUGH */ | 
|  | case cmb4:                         /* Printer combobox */ | 
|  | if (HIWORD(wParam)==CBN_SELCHANGE) { | 
|  | char   PrinterName[256]; | 
|  | GetDlgItemTextA(hDlg, LOWORD(wParam), PrinterName, 255); | 
|  | PRINTDLG_ChangePrinterA(hDlg, PrinterName, PrintStructures); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case cmb2: /* Papersize */ | 
|  | { | 
|  | DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0); | 
|  | if(Sel != CB_ERR) | 
|  | lpdm->u1.s1.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2, | 
|  | CB_GETITEMDATA, | 
|  | Sel, 0); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case cmb3: /* Bin */ | 
|  | { | 
|  | DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0); | 
|  | if(Sel != CB_ERR) | 
|  | lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3, | 
|  | CB_GETITEMDATA, Sel, | 
|  | 0); | 
|  | } | 
|  | break; | 
|  | } | 
|  | if(lppd->Flags & PD_PRINTSETUP) { | 
|  | switch (LOWORD(wParam)) { | 
|  | case rad1:                         /* orientation */ | 
|  | case rad2: | 
|  | if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { | 
|  | if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; | 
|  | SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hPortraitIcon); | 
|  | SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hPortraitIcon); | 
|  | } | 
|  | } else { | 
|  | if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; | 
|  | SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hLandscapeIcon); | 
|  | SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hLandscapeIcon); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static LRESULT PRINTDLG_WMCommandW(HWND hDlg, WPARAM wParam, | 
|  | PRINT_PTRW* PrintStructures) | 
|  | { | 
|  | LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; | 
|  | UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; | 
|  | LPDEVMODEW lpdm = PrintStructures->lpDevMode; | 
|  |  | 
|  | switch (LOWORD(wParam))  { | 
|  | case IDOK: | 
|  | TRACE(" OK button was hit\n"); | 
|  | if (!PRINTDLG_UpdatePrintDlgW(hDlg, PrintStructures)) { | 
|  | FIXME("Update printdlg was not successful!\n"); | 
|  | return(FALSE); | 
|  | } | 
|  | EndDialog(hDlg, TRUE); | 
|  | return(TRUE); | 
|  |  | 
|  | case IDCANCEL: | 
|  | TRACE(" CANCEL button was hit\n"); | 
|  | EndDialog(hDlg, FALSE); | 
|  | return(FALSE); | 
|  |  | 
|  | case pshHelp: | 
|  | TRACE(" HELP button was hit\n"); | 
|  | SendMessageW(lppd->hwndOwner, PrintStructures->HelpMessageID, | 
|  | (WPARAM) hDlg, (LPARAM) lppd); | 
|  | break; | 
|  |  | 
|  | case chx2:                         /* collate pages checkbox */ | 
|  | if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) | 
|  | SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hCollateIcon); | 
|  | else | 
|  | SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hNoCollateIcon); | 
|  | break; | 
|  | case edt1:                         /* from page nr editbox */ | 
|  | case edt2:                         /* to page nr editbox */ | 
|  | if (HIWORD(wParam)==EN_CHANGE) { | 
|  | WORD nToPage; | 
|  | WORD nFromPage; | 
|  | nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); | 
|  | nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE); | 
|  | if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) | 
|  | CheckRadioButton(hDlg, rad1, rad3, rad3); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case edt3: | 
|  | if(HIWORD(wParam) == EN_CHANGE) { | 
|  | INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); | 
|  | if(copies <= 1) | 
|  | EnableWindow(GetDlgItem(hDlg, chx2), FALSE); | 
|  | else | 
|  | EnableWindow(GetDlgItem(hDlg, chx2), TRUE); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case psh2:                       /* Properties button */ | 
|  | { | 
|  | HANDLE hPrinter; | 
|  | WCHAR  PrinterName[256]; | 
|  |  | 
|  | if (!GetDlgItemTextW(hDlg, PrinterComboID, PrinterName, 255)) break; | 
|  | if (!OpenPrinterW(PrinterName, &hPrinter, NULL)) { | 
|  | FIXME(" Call to OpenPrinter did not succeed!\n"); | 
|  | break; | 
|  | } | 
|  | DocumentPropertiesW(hDlg, hPrinter, PrinterName, | 
|  | PrintStructures->lpDevMode, | 
|  | PrintStructures->lpDevMode, | 
|  | DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); | 
|  | ClosePrinter(hPrinter); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case rad1: /* Paperorientation */ | 
|  | if (lppd->Flags & PD_PRINTSETUP) | 
|  | { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; | 
|  | SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)(PrintStructures->hPortraitIcon)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case rad2: /* Paperorientation */ | 
|  | if (lppd->Flags & PD_PRINTSETUP) | 
|  | { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; | 
|  | SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)(PrintStructures->hLandscapeIcon)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case cmb1: /* Printer Combobox in PRINT SETUP */ | 
|  | /* FALLTHROUGH */ | 
|  | case cmb4:                         /* Printer combobox */ | 
|  | if (HIWORD(wParam)==CBN_SELCHANGE) { | 
|  | WCHAR   PrinterName[256]; | 
|  | GetDlgItemTextW(hDlg, LOWORD(wParam), PrinterName, 255); | 
|  | PRINTDLG_ChangePrinterW(hDlg, PrinterName, PrintStructures); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case cmb2: /* Papersize */ | 
|  | { | 
|  | DWORD Sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); | 
|  | if(Sel != CB_ERR) | 
|  | lpdm->u1.s1.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2, | 
|  | CB_GETITEMDATA, | 
|  | Sel, 0); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case cmb3: /* Bin */ | 
|  | { | 
|  | DWORD Sel = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); | 
|  | if(Sel != CB_ERR) | 
|  | lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageW(hDlg, cmb3, | 
|  | CB_GETITEMDATA, Sel, | 
|  | 0); | 
|  | } | 
|  | break; | 
|  | } | 
|  | if(lppd->Flags & PD_PRINTSETUP) { | 
|  | switch (LOWORD(wParam)) { | 
|  | case rad1:                         /* orientation */ | 
|  | case rad2: | 
|  | if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { | 
|  | if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; | 
|  | SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hPortraitIcon); | 
|  | SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hPortraitIcon); | 
|  | } | 
|  | } else { | 
|  | if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) { | 
|  | lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; | 
|  | SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hLandscapeIcon); | 
|  | SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, | 
|  | (LPARAM)PrintStructures->hLandscapeIcon); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PrintDlgProcA			[internal] | 
|  | */ | 
|  | static INT_PTR CALLBACK PrintDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, | 
|  | LPARAM lParam) | 
|  | { | 
|  | PRINT_PTRA* PrintStructures; | 
|  | INT_PTR res = FALSE; | 
|  |  | 
|  | if (uMsg!=WM_INITDIALOG) { | 
|  | PrintStructures = GetPropW(hDlg, printdlg_prop); | 
|  | if (!PrintStructures) | 
|  | return FALSE; | 
|  | } else { | 
|  | PrintStructures = (PRINT_PTRA*) lParam; | 
|  | SetPropW(hDlg, printdlg_prop, PrintStructures); | 
|  | if(!check_printer_setup(hDlg)) | 
|  | { | 
|  | EndDialog(hDlg,FALSE); | 
|  | return FALSE; | 
|  | } | 
|  | res = PRINTDLG_WMInitDialog(hDlg, PrintStructures); | 
|  |  | 
|  | if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) | 
|  | res = PrintStructures->lpPrintDlg->lpfnPrintHook( | 
|  | hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg | 
|  | ); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { | 
|  | res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, | 
|  | lParam); | 
|  | if(res) return res; | 
|  | } | 
|  |  | 
|  | switch (uMsg) { | 
|  | case WM_COMMAND: | 
|  | return PRINTDLG_WMCommandA(hDlg, wParam, PrintStructures); | 
|  |  | 
|  | case WM_DESTROY: | 
|  | DestroyIcon(PrintStructures->hCollateIcon); | 
|  | DestroyIcon(PrintStructures->hNoCollateIcon); | 
|  | DestroyIcon(PrintStructures->hPortraitIcon); | 
|  | DestroyIcon(PrintStructures->hLandscapeIcon); | 
|  | if(PrintStructures->hwndUpDown) | 
|  | DestroyWindow(PrintStructures->hwndUpDown); | 
|  | return FALSE; | 
|  | } | 
|  | return res; | 
|  | } | 
|  |  | 
|  | static INT_PTR CALLBACK PrintDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, | 
|  | LPARAM lParam) | 
|  | { | 
|  | PRINT_PTRW* PrintStructures; | 
|  | INT_PTR res = FALSE; | 
|  |  | 
|  | if (uMsg!=WM_INITDIALOG) { | 
|  | PrintStructures = GetPropW(hDlg, printdlg_prop); | 
|  | if (!PrintStructures) | 
|  | return FALSE; | 
|  | } else { | 
|  | PrintStructures = (PRINT_PTRW*) lParam; | 
|  | SetPropW(hDlg, printdlg_prop, PrintStructures); | 
|  | if(!check_printer_setup(hDlg)) | 
|  | { | 
|  | EndDialog(hDlg,FALSE); | 
|  | return FALSE; | 
|  | } | 
|  | res = PRINTDLG_WMInitDialogW(hDlg, PrintStructures); | 
|  |  | 
|  | if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) | 
|  | res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { | 
|  | res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, lParam); | 
|  | if(res) return res; | 
|  | } | 
|  |  | 
|  | switch (uMsg) { | 
|  | case WM_COMMAND: | 
|  | return PRINTDLG_WMCommandW(hDlg, wParam, PrintStructures); | 
|  |  | 
|  | case WM_DESTROY: | 
|  | DestroyIcon(PrintStructures->hCollateIcon); | 
|  | DestroyIcon(PrintStructures->hNoCollateIcon); | 
|  | DestroyIcon(PrintStructures->hPortraitIcon); | 
|  | DestroyIcon(PrintStructures->hLandscapeIcon); | 
|  | if(PrintStructures->hwndUpDown) | 
|  | DestroyWindow(PrintStructures->hwndUpDown); | 
|  | return FALSE; | 
|  | } | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /************************************************************ | 
|  | * | 
|  | *      PRINTDLG_GetDlgTemplate | 
|  | * | 
|  | */ | 
|  | static HGLOBAL PRINTDLG_GetDlgTemplateA(const PRINTDLGA *lppd) | 
|  | { | 
|  | HRSRC hResInfo; | 
|  | HGLOBAL hDlgTmpl; | 
|  |  | 
|  | if (lppd->Flags & PD_PRINTSETUP) { | 
|  | if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { | 
|  | hDlgTmpl = lppd->hSetupTemplate; | 
|  | } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { | 
|  | hResInfo = FindResourceA(lppd->hInstance, | 
|  | lppd->lpSetupTemplateName, (LPSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); | 
|  | } else { | 
|  | hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP", | 
|  | (LPSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); | 
|  | } | 
|  | } else { | 
|  | if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { | 
|  | hDlgTmpl = lppd->hPrintTemplate; | 
|  | } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { | 
|  | hResInfo = FindResourceA(lppd->hInstance, | 
|  | lppd->lpPrintTemplateName, | 
|  | (LPSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); | 
|  | } else { | 
|  | hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32", | 
|  | (LPSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); | 
|  | } | 
|  | } | 
|  | return hDlgTmpl; | 
|  | } | 
|  |  | 
|  | static HGLOBAL PRINTDLG_GetDlgTemplateW(const PRINTDLGW *lppd) | 
|  | { | 
|  | HRSRC hResInfo; | 
|  | HGLOBAL hDlgTmpl; | 
|  | static const WCHAR xpsetup[] = { 'P','R','I','N','T','3','2','_','S','E','T','U','P',0}; | 
|  | static const WCHAR xprint[] = { 'P','R','I','N','T','3','2',0}; | 
|  |  | 
|  | if (lppd->Flags & PD_PRINTSETUP) { | 
|  | if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { | 
|  | hDlgTmpl = lppd->hSetupTemplate; | 
|  | } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { | 
|  | hResInfo = FindResourceW(lppd->hInstance, | 
|  | lppd->lpSetupTemplateName, (LPWSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); | 
|  | } else { | 
|  | hResInfo = FindResourceW(COMDLG32_hInstance, xpsetup, (LPWSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); | 
|  | } | 
|  | } else { | 
|  | if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { | 
|  | hDlgTmpl = lppd->hPrintTemplate; | 
|  | } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { | 
|  | hResInfo = FindResourceW(lppd->hInstance, | 
|  | lppd->lpPrintTemplateName, | 
|  | (LPWSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); | 
|  | } else { | 
|  | hResInfo = FindResourceW(COMDLG32_hInstance, xprint, (LPWSTR)RT_DIALOG); | 
|  | hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); | 
|  | } | 
|  | } | 
|  | return hDlgTmpl; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * | 
|  | *      PRINTDLG_CreateDC | 
|  | * | 
|  | */ | 
|  | static BOOL PRINTDLG_CreateDCA(LPPRINTDLGA lppd) | 
|  | { | 
|  | DEVNAMES *pdn = GlobalLock(lppd->hDevNames); | 
|  | DEVMODEA *pdm = GlobalLock(lppd->hDevMode); | 
|  |  | 
|  | if(lppd->Flags & PD_RETURNDC) { | 
|  | lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset, | 
|  | (char*)pdn + pdn->wDeviceOffset, | 
|  | (char*)pdn + pdn->wOutputOffset, | 
|  | pdm ); | 
|  | } else if(lppd->Flags & PD_RETURNIC) { | 
|  | lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset, | 
|  | (char*)pdn + pdn->wDeviceOffset, | 
|  | (char*)pdn + pdn->wOutputOffset, | 
|  | pdm ); | 
|  | } | 
|  | GlobalUnlock(lppd->hDevNames); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | return lppd->hDC ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static BOOL PRINTDLG_CreateDCW(LPPRINTDLGW lppd) | 
|  | { | 
|  | DEVNAMES *pdn = GlobalLock(lppd->hDevNames); | 
|  | DEVMODEW *pdm = GlobalLock(lppd->hDevMode); | 
|  |  | 
|  | if(lppd->Flags & PD_RETURNDC) { | 
|  | lppd->hDC = CreateDCW((WCHAR*)pdn + pdn->wDriverOffset, | 
|  | (WCHAR*)pdn + pdn->wDeviceOffset, | 
|  | (WCHAR*)pdn + pdn->wOutputOffset, | 
|  | pdm ); | 
|  | } else if(lppd->Flags & PD_RETURNIC) { | 
|  | lppd->hDC = CreateICW((WCHAR*)pdn + pdn->wDriverOffset, | 
|  | (WCHAR*)pdn + pdn->wDeviceOffset, | 
|  | (WCHAR*)pdn + pdn->wOutputOffset, | 
|  | pdm ); | 
|  | } | 
|  | GlobalUnlock(lppd->hDevNames); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | return lppd->hDC ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PrintDlgA   (COMDLG32.@) | 
|  | * | 
|  | *  Displays the PRINT dialog box, which enables the user to specify | 
|  | *  specific properties of the print job. | 
|  | * | 
|  | * PARAMS | 
|  | *  lppd  [IO] ptr to PRINTDLG32 struct | 
|  | * | 
|  | * RETURNS | 
|  | *  nonzero if the user pressed the OK button | 
|  | *  zero    if the user cancelled the window or an error occurred | 
|  | * | 
|  | * BUGS | 
|  | *  PrintDlg: | 
|  | *  * The Collate Icons do not display, even though they are in the code. | 
|  | *  * The Properties Button(s) should call DocumentPropertiesA(). | 
|  | */ | 
|  |  | 
|  | BOOL WINAPI PrintDlgA(LPPRINTDLGA lppd) | 
|  | { | 
|  | BOOL      bRet = FALSE; | 
|  | LPVOID    ptr; | 
|  | HINSTANCE hInst; | 
|  |  | 
|  | if (!lppd) | 
|  | { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if(TRACE_ON(commdlg)) { | 
|  | char flagstr[1000] = ""; | 
|  | const struct pd_flags *pflag = pd_flags; | 
|  | for( ; pflag->name; pflag++) { | 
|  | if(lppd->Flags & pflag->flag) | 
|  | strcat(flagstr, pflag->name); | 
|  | } | 
|  | TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" | 
|  | "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" | 
|  | "flags %08x (%s)\n", | 
|  | lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, | 
|  | lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, | 
|  | lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); | 
|  | } | 
|  |  | 
|  | if(lppd->lStructSize != sizeof(PRINTDLGA)) { | 
|  | WARN("structure size failure !!!\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if(lppd->Flags & PD_RETURNDEFAULT) { | 
|  | PRINTER_INFO_2A *pbuf; | 
|  | DRIVER_INFO_3A	*dbuf; | 
|  | HANDLE hprn; | 
|  | DWORD needed; | 
|  |  | 
|  | if(lppd->hDevMode || lppd->hDevNames) { | 
|  | WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  | if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { | 
|  | WARN("Can't find default printer\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | GetPrinterA(hprn, 2, NULL, 0, &needed); | 
|  | pbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); | 
|  |  | 
|  | GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); | 
|  | dbuf = HeapAlloc(GetProcessHeap(),0,needed); | 
|  | if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { | 
|  | ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n", | 
|  | GetLastError(),pbuf->pPrinterName); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | PRINTDLG_CreateDevNames(&(lppd->hDevNames), | 
|  | dbuf->pDriverPath, | 
|  | pbuf->pPrinterName, | 
|  | pbuf->pPortName); | 
|  | lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | ptr = GlobalLock(lppd->hDevMode); | 
|  | memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | bRet = TRUE; | 
|  | } else { | 
|  | HGLOBAL hDlgTmpl; | 
|  | PRINT_PTRA *PrintStructures; | 
|  |  | 
|  | /* load Dialog resources, | 
|  | * depending on Flags indicates Print32 or Print32_setup dialog | 
|  | */ | 
|  | hDlgTmpl = PRINTDLG_GetDlgTemplateA(lppd); | 
|  | if (!hDlgTmpl) { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  | ptr = LockResource( hDlgTmpl ); | 
|  | if (!ptr) { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | sizeof(PRINT_PTRA)); | 
|  | PrintStructures->lpPrintDlg = lppd; | 
|  |  | 
|  | /* and create & process the dialog . | 
|  | * -1 is failure, 0 is broken hwnd, everything else is ok. | 
|  | */ | 
|  | hInst = COMDLG32_hInstance; | 
|  | if (lppd->Flags & (PD_ENABLESETUPTEMPLATE | PD_ENABLEPRINTTEMPLATE)) hInst = lppd->hInstance; | 
|  | bRet = (0<DialogBoxIndirectParamA(hInst, ptr, lppd->hwndOwner, | 
|  | PrintDlgProcA, | 
|  | (LPARAM)PrintStructures)); | 
|  |  | 
|  | if(bRet) { | 
|  | DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn; | 
|  | PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo; | 
|  | DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo; | 
|  |  | 
|  | if (lppd->hDevMode == 0) { | 
|  | TRACE(" No hDevMode yet... Need to create my own\n"); | 
|  | lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, | 
|  | lpdm->dmSize + lpdm->dmDriverExtra); | 
|  | } else { | 
|  | lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, | 
|  | lpdm->dmSize + lpdm->dmDriverExtra, | 
|  | GMEM_MOVEABLE); | 
|  | } | 
|  | lpdmReturn = GlobalLock(lppd->hDevMode); | 
|  | memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); | 
|  |  | 
|  | PRINTDLG_CreateDevNames(&(lppd->hDevNames), | 
|  | di->pDriverPath, | 
|  | pi->pPrinterName, | 
|  | pi->pPortName | 
|  | ); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures); | 
|  | } | 
|  | if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) | 
|  | bRet = PRINTDLG_CreateDCA(lppd); | 
|  |  | 
|  | TRACE("exit! (%d)\n", bRet); | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PrintDlgW   (COMDLG32.@) | 
|  | * | 
|  | * See PrintDlgA. | 
|  | */ | 
|  | BOOL WINAPI PrintDlgW(LPPRINTDLGW lppd) | 
|  | { | 
|  | BOOL      bRet = FALSE; | 
|  | LPVOID    ptr; | 
|  | HINSTANCE hInst; | 
|  |  | 
|  | if (!lppd) | 
|  | { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if(TRACE_ON(commdlg)) { | 
|  | char flagstr[1000] = ""; | 
|  | const struct pd_flags *pflag = pd_flags; | 
|  | for( ; pflag->name; pflag++) { | 
|  | if(lppd->Flags & pflag->flag) | 
|  | strcat(flagstr, pflag->name); | 
|  | } | 
|  | TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" | 
|  | "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" | 
|  | "flags %08x (%s)\n", | 
|  | lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, | 
|  | lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, | 
|  | lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); | 
|  | } | 
|  |  | 
|  | if(lppd->lStructSize != sizeof(PRINTDLGW)) { | 
|  | WARN("structure size failure !!!\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if(lppd->Flags & PD_RETURNDEFAULT) { | 
|  | PRINTER_INFO_2W *pbuf; | 
|  | DRIVER_INFO_3W	*dbuf; | 
|  | HANDLE hprn; | 
|  | DWORD needed; | 
|  |  | 
|  | if(lppd->hDevMode || lppd->hDevNames) { | 
|  | WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  | if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { | 
|  | WARN("Can't find default printer\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | GetPrinterW(hprn, 2, NULL, 0, &needed); | 
|  | pbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed); | 
|  |  | 
|  | GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); | 
|  | dbuf = HeapAlloc(GetProcessHeap(),0,needed); | 
|  | if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { | 
|  | ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n", | 
|  | GetLastError(),debugstr_w(pbuf->pPrinterName)); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), | 
|  | dbuf->pDriverPath, | 
|  | pbuf->pPrinterName, | 
|  | pbuf->pPortName); | 
|  | lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | ptr = GlobalLock(lppd->hDevMode); | 
|  | memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | bRet = TRUE; | 
|  | } else { | 
|  | HGLOBAL hDlgTmpl; | 
|  | PRINT_PTRW *PrintStructures; | 
|  |  | 
|  | /* load Dialog resources, | 
|  | * depending on Flags indicates Print32 or Print32_setup dialog | 
|  | */ | 
|  | hDlgTmpl = PRINTDLG_GetDlgTemplateW(lppd); | 
|  | if (!hDlgTmpl) { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  | ptr = LockResource( hDlgTmpl ); | 
|  | if (!ptr) { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | sizeof(PRINT_PTRW)); | 
|  | PrintStructures->lpPrintDlg = lppd; | 
|  |  | 
|  | /* and create & process the dialog . | 
|  | * -1 is failure, 0 is broken hwnd, everything else is ok. | 
|  | */ | 
|  | hInst = COMDLG32_hInstance; | 
|  | if (lppd->Flags & (PD_ENABLESETUPTEMPLATE | PD_ENABLEPRINTTEMPLATE)) hInst = lppd->hInstance; | 
|  | bRet = (0<DialogBoxIndirectParamW(hInst, ptr, lppd->hwndOwner, | 
|  | PrintDlgProcW, | 
|  | (LPARAM)PrintStructures)); | 
|  |  | 
|  | if(bRet) { | 
|  | DEVMODEW *lpdm = PrintStructures->lpDevMode, *lpdmReturn; | 
|  | PRINTER_INFO_2W *pi = PrintStructures->lpPrinterInfo; | 
|  | DRIVER_INFO_3W *di = PrintStructures->lpDriverInfo; | 
|  |  | 
|  | if (lppd->hDevMode == 0) { | 
|  | TRACE(" No hDevMode yet... Need to create my own\n"); | 
|  | lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, | 
|  | lpdm->dmSize + lpdm->dmDriverExtra); | 
|  | } else { | 
|  | WORD locks; | 
|  | if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) { | 
|  | WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); | 
|  | while(locks--) { | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | TRACE("Now got %d locks\n", locks); | 
|  | } | 
|  | } | 
|  | lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, | 
|  | lpdm->dmSize + lpdm->dmDriverExtra, | 
|  | GMEM_MOVEABLE); | 
|  | } | 
|  | lpdmReturn = GlobalLock(lppd->hDevMode); | 
|  | memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); | 
|  |  | 
|  | if (lppd->hDevNames != 0) { | 
|  | WORD locks; | 
|  | if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) { | 
|  | WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); | 
|  | while(locks--) | 
|  | GlobalUnlock(lppd->hDevNames); | 
|  | } | 
|  | } | 
|  | PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), | 
|  | di->pDriverPath, | 
|  | pi->pPrinterName, | 
|  | pi->pPortName | 
|  | ); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); | 
|  | HeapFree(GetProcessHeap(), 0, PrintStructures); | 
|  | } | 
|  | if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) | 
|  | bRet = PRINTDLG_CreateDCW(lppd); | 
|  |  | 
|  | TRACE("exit! (%d)\n", bRet); | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * | 
|  | *          PageSetupDlg | 
|  | * rad1 - portrait | 
|  | * rad2 - landscape | 
|  | * cmb1 - printer select (not in standard dialog template) | 
|  | * cmb2 - paper size | 
|  | * cmb3 - source (tray?) | 
|  | * edt4 - border left | 
|  | * edt5 - border top | 
|  | * edt6 - border right | 
|  | * edt7 - border bottom | 
|  | * psh3 - "Printer..." | 
|  | */ | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | BOOL unicode; | 
|  | union | 
|  | { | 
|  | LPPAGESETUPDLGA dlga; | 
|  | LPPAGESETUPDLGW dlgw; | 
|  | } u; | 
|  | HWND hDlg;                /* Page Setup dialog handle */ | 
|  | RECT rtDrawRect;          /* Drawing rect for page */ | 
|  | } pagesetup_data; | 
|  |  | 
|  | static inline DWORD pagesetup_get_flags(const pagesetup_data *data) | 
|  | { | 
|  | return data->u.dlgw->Flags; | 
|  | } | 
|  |  | 
|  | static inline BOOL is_metric(const pagesetup_data *data) | 
|  | { | 
|  | return pagesetup_get_flags(data) & PSD_INHUNDREDTHSOFMILLIMETERS; | 
|  | } | 
|  |  | 
|  | static inline LONG tenths_mm_to_size(const pagesetup_data *data, LONG size) | 
|  | { | 
|  | if (is_metric(data)) | 
|  | return 10 * size; | 
|  | else | 
|  | return 10 * size * 100 / 254; | 
|  | } | 
|  |  | 
|  | static inline LONG thousandths_inch_to_size(const pagesetup_data *data, LONG size) | 
|  | { | 
|  | if (is_metric(data)) | 
|  | return size * 254 / 100; | 
|  | else | 
|  | return size; | 
|  | } | 
|  |  | 
|  | static WCHAR get_decimal_sep(void) | 
|  | { | 
|  | static WCHAR sep; | 
|  |  | 
|  | if(!sep) | 
|  | { | 
|  | WCHAR buf[2] = {'.',0}; | 
|  | GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buf, sizeof(buf) / sizeof(buf[0])); | 
|  | sep = buf[0]; | 
|  | } | 
|  | return sep; | 
|  | } | 
|  |  | 
|  | static void size2str(const pagesetup_data *data, DWORD size, LPWSTR strout) | 
|  | { | 
|  | WCHAR integer_fmt[] = {'%','d',0}; | 
|  | WCHAR hundredths_fmt[] = {'%','d','%','c','%','0','2','d',0}; | 
|  | WCHAR thousandths_fmt[] = {'%','d','%','c','%','0','3','d',0}; | 
|  |  | 
|  | /* FIXME use LOCALE_SDECIMAL when the edit parsing code can cope */ | 
|  |  | 
|  | if (is_metric(data)) | 
|  | { | 
|  | if(size % 100) | 
|  | wsprintfW(strout, hundredths_fmt, size / 100, get_decimal_sep(), size % 100); | 
|  | else | 
|  | wsprintfW(strout, integer_fmt, size / 100); | 
|  | } | 
|  | else | 
|  | { | 
|  | if(size % 1000) | 
|  | wsprintfW(strout, thousandths_fmt, size / 1000, get_decimal_sep(), size % 1000); | 
|  | else | 
|  | wsprintfW(strout, integer_fmt, size / 1000); | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline BOOL is_default_metric(void) | 
|  | { | 
|  | DWORD system; | 
|  | GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, | 
|  | (LPWSTR)&system, sizeof(system)); | 
|  | return system == 0; | 
|  | } | 
|  |  | 
|  | /********************************************** | 
|  | *           rotate_rect | 
|  | * Cyclically permute the four members of rc | 
|  | * If sense is TRUE l -> t -> r -> b | 
|  | * otherwise        l <- t <- r <- b | 
|  | */ | 
|  | static inline void rotate_rect(RECT *rc, BOOL sense) | 
|  | { | 
|  | INT tmp; | 
|  | if(sense) | 
|  | { | 
|  | tmp        = rc->bottom; | 
|  | rc->bottom = rc->right; | 
|  | rc->right  = rc->top; | 
|  | rc->top    = rc->left; | 
|  | rc->left   = tmp; | 
|  | } | 
|  | else | 
|  | { | 
|  | tmp        = rc->left; | 
|  | rc->left   = rc->top; | 
|  | rc->top    = rc->right; | 
|  | rc->right  = rc->bottom; | 
|  | rc->bottom = tmp; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void pagesetup_set_orientation(pagesetup_data *data, WORD orient) | 
|  | { | 
|  | DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); | 
|  |  | 
|  | assert(orient == DMORIENT_PORTRAIT || orient == DMORIENT_LANDSCAPE); | 
|  |  | 
|  | if(data->unicode) | 
|  | dm->u1.s1.dmOrientation = orient; | 
|  | else | 
|  | { | 
|  | DEVMODEA *dmA = (DEVMODEA *)dm; | 
|  | dmA->u1.s1.dmOrientation = orient; | 
|  | } | 
|  | GlobalUnlock(data->u.dlgw->hDevMode); | 
|  | } | 
|  |  | 
|  | static WORD pagesetup_get_orientation(const pagesetup_data *data) | 
|  | { | 
|  | DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); | 
|  | WORD orient; | 
|  |  | 
|  | if(data->unicode) | 
|  | orient = dm->u1.s1.dmOrientation; | 
|  | else | 
|  | { | 
|  | DEVMODEA *dmA = (DEVMODEA *)dm; | 
|  | orient = dmA->u1.s1.dmOrientation; | 
|  | } | 
|  | GlobalUnlock(data->u.dlgw->hDevMode); | 
|  | return orient; | 
|  | } | 
|  |  | 
|  | static void pagesetup_set_papersize(pagesetup_data *data, WORD paper) | 
|  | { | 
|  | DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); | 
|  |  | 
|  | if(data->unicode) | 
|  | dm->u1.s1.dmPaperSize = paper; | 
|  | else | 
|  | { | 
|  | DEVMODEA *dmA = (DEVMODEA *)dm; | 
|  | dmA->u1.s1.dmPaperSize = paper; | 
|  | } | 
|  | GlobalUnlock(data->u.dlgw->hDevMode); | 
|  | } | 
|  |  | 
|  | static WORD pagesetup_get_papersize(const pagesetup_data *data) | 
|  | { | 
|  | DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); | 
|  | WORD paper; | 
|  |  | 
|  | if(data->unicode) | 
|  | paper = dm->u1.s1.dmPaperSize; | 
|  | else | 
|  | { | 
|  | DEVMODEA *dmA = (DEVMODEA *)dm; | 
|  | paper = dmA->u1.s1.dmPaperSize; | 
|  | } | 
|  | GlobalUnlock(data->u.dlgw->hDevMode); | 
|  | return paper; | 
|  | } | 
|  |  | 
|  | static void pagesetup_set_defaultsource(pagesetup_data *data, WORD source) | 
|  | { | 
|  | DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); | 
|  |  | 
|  | if(data->unicode) | 
|  | dm->u1.s1.dmDefaultSource = source; | 
|  | else | 
|  | { | 
|  | DEVMODEA *dmA = (DEVMODEA *)dm; | 
|  | dmA->u1.s1.dmDefaultSource = source; | 
|  | } | 
|  | GlobalUnlock(data->u.dlgw->hDevMode); | 
|  | } | 
|  |  | 
|  | typedef enum | 
|  | { | 
|  | devnames_driver_name, | 
|  | devnames_device_name, | 
|  | devnames_output_name | 
|  | } devnames_name; | 
|  |  | 
|  |  | 
|  | static inline WORD get_devname_offset(const DEVNAMES *dn, devnames_name which) | 
|  | { | 
|  | switch(which) | 
|  | { | 
|  | case devnames_driver_name: return dn->wDriverOffset; | 
|  | case devnames_device_name: return dn->wDeviceOffset; | 
|  | case devnames_output_name: return dn->wOutputOffset; | 
|  | } | 
|  | ERR("Souldn't be here\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static WCHAR *pagesetup_get_a_devname(const pagesetup_data *data, devnames_name which) | 
|  | { | 
|  | DEVNAMES *dn; | 
|  | WCHAR *name; | 
|  |  | 
|  | dn = GlobalLock(data->u.dlgw->hDevNames); | 
|  | if(data->unicode) | 
|  | name = strdupW((WCHAR *)dn + get_devname_offset(dn, which)); | 
|  | else | 
|  | { | 
|  | int len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, NULL, 0); | 
|  | name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, name, len); | 
|  | } | 
|  | GlobalUnlock(data->u.dlgw->hDevNames); | 
|  | return name; | 
|  | } | 
|  |  | 
|  | static WCHAR *pagesetup_get_drvname(const pagesetup_data *data) | 
|  | { | 
|  | return pagesetup_get_a_devname(data, devnames_driver_name); | 
|  | } | 
|  |  | 
|  | static WCHAR *pagesetup_get_devname(const pagesetup_data *data) | 
|  | { | 
|  | return pagesetup_get_a_devname(data, devnames_device_name); | 
|  | } | 
|  |  | 
|  | static WCHAR *pagesetup_get_portname(const pagesetup_data *data) | 
|  | { | 
|  | return pagesetup_get_a_devname(data, devnames_output_name); | 
|  | } | 
|  |  | 
|  | static void pagesetup_release_a_devname(const pagesetup_data *data, WCHAR *name) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, name); | 
|  | } | 
|  |  | 
|  | static void pagesetup_set_devnames(pagesetup_data *data, LPCWSTR drv, LPCWSTR devname, LPCWSTR port) | 
|  | { | 
|  | DEVNAMES *dn; | 
|  | WCHAR def[256]; | 
|  | DWORD len = sizeof(DEVNAMES), drv_len, dev_len, port_len; | 
|  |  | 
|  | if(data->unicode) | 
|  | { | 
|  | drv_len  = (strlenW(drv) + 1) * sizeof(WCHAR); | 
|  | dev_len  = (strlenW(devname) + 1) * sizeof(WCHAR); | 
|  | port_len = (strlenW(port) + 1) * sizeof(WCHAR); | 
|  | } | 
|  | else | 
|  | { | 
|  | drv_len = WideCharToMultiByte(CP_ACP, 0, drv, -1, NULL, 0, NULL, NULL); | 
|  | dev_len = WideCharToMultiByte(CP_ACP, 0, devname, -1, NULL, 0, NULL, NULL); | 
|  | port_len = WideCharToMultiByte(CP_ACP, 0, port, -1, NULL, 0, NULL, NULL); | 
|  | } | 
|  | len += drv_len + dev_len + port_len; | 
|  |  | 
|  | if(data->u.dlgw->hDevNames) | 
|  | data->u.dlgw->hDevNames = GlobalReAlloc(data->u.dlgw->hDevNames, len, GMEM_MOVEABLE); | 
|  | else | 
|  | data->u.dlgw->hDevNames = GlobalAlloc(GMEM_MOVEABLE, len); | 
|  |  | 
|  | dn = GlobalLock(data->u.dlgw->hDevNames); | 
|  |  | 
|  | if(data->unicode) | 
|  | { | 
|  | WCHAR *ptr = (WCHAR *)(dn + 1); | 
|  | len = sizeof(DEVNAMES) / sizeof(WCHAR); | 
|  | dn->wDriverOffset = len; | 
|  | strcpyW(ptr, drv); | 
|  | ptr += drv_len / sizeof(WCHAR); | 
|  | len += drv_len / sizeof(WCHAR); | 
|  | dn->wDeviceOffset = len; | 
|  | strcpyW(ptr, devname); | 
|  | ptr += dev_len / sizeof(WCHAR); | 
|  | len += dev_len / sizeof(WCHAR); | 
|  | dn->wOutputOffset = len; | 
|  | strcpyW(ptr, port); | 
|  | } | 
|  | else | 
|  | { | 
|  | char *ptr = (char *)(dn + 1); | 
|  | len = sizeof(DEVNAMES); | 
|  | dn->wDriverOffset = len; | 
|  | WideCharToMultiByte(CP_ACP, 0, drv, -1, ptr, drv_len, NULL, NULL); | 
|  | ptr += drv_len; | 
|  | len += drv_len; | 
|  | dn->wDeviceOffset = len; | 
|  | WideCharToMultiByte(CP_ACP, 0, devname, -1, ptr, dev_len, NULL, NULL); | 
|  | ptr += dev_len; | 
|  | len += dev_len; | 
|  | dn->wOutputOffset = len; | 
|  | WideCharToMultiByte(CP_ACP, 0, port, -1, ptr, port_len, NULL, NULL); | 
|  | } | 
|  |  | 
|  | dn->wDefault = 0; | 
|  | len = sizeof(def) / sizeof(def[0]); | 
|  | GetDefaultPrinterW(def, &len); | 
|  | if(!lstrcmpW(def, devname)) | 
|  | dn->wDefault = 1; | 
|  |  | 
|  | GlobalUnlock(data->u.dlgw->hDevNames); | 
|  | } | 
|  |  | 
|  | static DEVMODEW *pagesetup_get_devmode(const pagesetup_data *data) | 
|  | { | 
|  | DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); | 
|  | DEVMODEW *ret; | 
|  |  | 
|  | if(data->unicode) | 
|  | { | 
|  | /* We make a copy even in the unicode case because the ptr | 
|  | may get passed back to us in pagesetup_set_devmode. */ | 
|  | ret = HeapAlloc(GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra); | 
|  | memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra); | 
|  | } | 
|  | else | 
|  | ret = GdiConvertToDevmodeW((DEVMODEA *)dm); | 
|  |  | 
|  | GlobalUnlock(data->u.dlgw->hDevMode); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void pagesetup_release_devmode(const pagesetup_data *data, DEVMODEW *dm) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, dm); | 
|  | } | 
|  |  | 
|  | static void pagesetup_set_devmode(pagesetup_data *data, DEVMODEW *dm) | 
|  | { | 
|  | DEVMODEA *dmA = NULL; | 
|  | void *src, *dst; | 
|  | DWORD size; | 
|  |  | 
|  | if(data->unicode) | 
|  | { | 
|  | size = dm->dmSize + dm->dmDriverExtra; | 
|  | src = dm; | 
|  | } | 
|  | else | 
|  | { | 
|  | dmA = convert_to_devmodeA(dm); | 
|  | size = dmA->dmSize + dmA->dmDriverExtra; | 
|  | src = dmA; | 
|  | } | 
|  |  | 
|  | if(data->u.dlgw->hDevMode) | 
|  | data->u.dlgw->hDevMode = GlobalReAlloc(data->u.dlgw->hDevMode, size, | 
|  | GMEM_MOVEABLE); | 
|  | else | 
|  | data->u.dlgw->hDevMode = GlobalAlloc(GMEM_MOVEABLE, size); | 
|  |  | 
|  | dst = GlobalLock(data->u.dlgw->hDevMode); | 
|  | memcpy(dst, src, size); | 
|  | GlobalUnlock(data->u.dlgw->hDevMode); | 
|  | HeapFree(GetProcessHeap(), 0, dmA); | 
|  | } | 
|  |  | 
|  | static inline POINT *pagesetup_get_papersize_pt(const pagesetup_data *data) | 
|  | { | 
|  | return &data->u.dlgw->ptPaperSize; | 
|  | } | 
|  |  | 
|  | static inline RECT *pagesetup_get_margin_rect(const pagesetup_data *data) | 
|  | { | 
|  | return &data->u.dlgw->rtMargin; | 
|  | } | 
|  |  | 
|  | typedef enum | 
|  | { | 
|  | page_setup_hook, | 
|  | page_paint_hook | 
|  | } hook_type; | 
|  |  | 
|  | static inline LPPAGESETUPHOOK pagesetup_get_hook(const pagesetup_data *data, hook_type which) | 
|  | { | 
|  | switch(which) | 
|  | { | 
|  | case page_setup_hook: return data->u.dlgw->lpfnPageSetupHook; | 
|  | case page_paint_hook: return data->u.dlgw->lpfnPagePaintHook; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* This should only be used in calls to hook procs so we return the ptr | 
|  | already cast to LPARAM */ | 
|  | static inline LPARAM pagesetup_get_dlg_struct(const pagesetup_data *data) | 
|  | { | 
|  | return (LPARAM)data->u.dlgw; | 
|  | } | 
|  |  | 
|  | static inline void swap_point(POINT *pt) | 
|  | { | 
|  | LONG tmp = pt->x; | 
|  | pt->x = pt->y; | 
|  | pt->y = tmp; | 
|  | } | 
|  |  | 
|  | static BOOL pagesetup_update_papersize(pagesetup_data *data) | 
|  | { | 
|  | DEVMODEW *dm; | 
|  | LPWSTR devname, portname; | 
|  | int i, num; | 
|  | WORD *words = NULL, paperword; | 
|  | POINT *points = NULL; | 
|  | BOOL retval = FALSE; | 
|  |  | 
|  | dm       = pagesetup_get_devmode(data); | 
|  | devname  = pagesetup_get_devname(data); | 
|  | portname = pagesetup_get_portname(data); | 
|  |  | 
|  | num = DeviceCapabilitiesW(devname, portname, DC_PAPERS, NULL, dm); | 
|  | if (num <= 0) | 
|  | { | 
|  | FIXME("No papernames found for %s/%s\n", debugstr_w(devname), debugstr_w(portname)); | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | words = HeapAlloc(GetProcessHeap(), 0, num * sizeof(WORD)); | 
|  | points = HeapAlloc(GetProcessHeap(), 0, num * sizeof(POINT)); | 
|  |  | 
|  | if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERS, (LPWSTR)words, dm)) | 
|  | { | 
|  | FIXME("Number of returned words is not %d\n", num); | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERSIZE, (LPWSTR)points, dm)) | 
|  | { | 
|  | FIXME("Number of returned sizes is not %d\n", num); | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | paperword = pagesetup_get_papersize(data); | 
|  |  | 
|  | for (i = 0; i < num; i++) | 
|  | if (words[i] == paperword) | 
|  | break; | 
|  |  | 
|  | if (i == num) | 
|  | { | 
|  | FIXME("Papersize %d not found in list?\n", paperword); | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | /* this is _10ths_ of a millimeter */ | 
|  | pagesetup_get_papersize_pt(data)->x = tenths_mm_to_size(data, points[i].x); | 
|  | pagesetup_get_papersize_pt(data)->y = tenths_mm_to_size(data, points[i].y); | 
|  |  | 
|  | if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) | 
|  | swap_point(pagesetup_get_papersize_pt(data)); | 
|  |  | 
|  | retval = TRUE; | 
|  |  | 
|  | end: | 
|  | HeapFree(GetProcessHeap(), 0, words); | 
|  | HeapFree(GetProcessHeap(), 0, points); | 
|  | pagesetup_release_a_devname(data, portname); | 
|  | pagesetup_release_a_devname(data, devname); | 
|  | pagesetup_release_devmode(data, dm); | 
|  |  | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | /********************************************************************************************** | 
|  | * pagesetup_change_printer | 
|  | * | 
|  | * Redefines hDevMode and hDevNames HANDLES and initialises it. | 
|  | * | 
|  | */ | 
|  | static BOOL pagesetup_change_printer(LPWSTR name, pagesetup_data *data) | 
|  | { | 
|  | HANDLE hprn; | 
|  | DWORD needed; | 
|  | PRINTER_INFO_2W *prn_info = NULL; | 
|  | DRIVER_INFO_3W *drv_info = NULL; | 
|  | DEVMODEW *dm = NULL; | 
|  | BOOL retval = FALSE; | 
|  |  | 
|  | if(!OpenPrinterW(name, &hprn, NULL)) | 
|  | { | 
|  | ERR("Can't open printer %s\n", debugstr_w(name)); | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | GetPrinterW(hprn, 2, NULL, 0, &needed); | 
|  | prn_info = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | GetPrinterW(hprn, 2, (LPBYTE)prn_info, needed, &needed); | 
|  | GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); | 
|  | drv_info = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | if(!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)drv_info, needed, &needed)) | 
|  | { | 
|  | ERR("GetPrinterDriverA failed for %s, fix your config!\n", debugstr_w(prn_info->pPrinterName)); | 
|  | goto end; | 
|  | } | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | needed = DocumentPropertiesW(0, 0, name, NULL, NULL, 0); | 
|  | if(needed == -1) | 
|  | { | 
|  | ERR("DocumentProperties fails on %s\n", debugstr_w(name)); | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | dm = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | DocumentPropertiesW(0, 0, name, dm, NULL, DM_OUT_BUFFER); | 
|  |  | 
|  | pagesetup_set_devmode(data, dm); | 
|  | pagesetup_set_devnames(data, drv_info->pDriverPath, prn_info->pPrinterName, | 
|  | prn_info->pPortName); | 
|  |  | 
|  | retval = TRUE; | 
|  | end: | 
|  | HeapFree(GetProcessHeap(), 0, dm); | 
|  | HeapFree(GetProcessHeap(), 0, prn_info); | 
|  | HeapFree(GetProcessHeap(), 0, drv_info); | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | /**************************************************************************************** | 
|  | *  pagesetup_init_combos | 
|  | * | 
|  | *  Fills Printers, Paper and Source combos | 
|  | * | 
|  | */ | 
|  | static void pagesetup_init_combos(HWND hDlg, pagesetup_data *data) | 
|  | { | 
|  | DEVMODEW *dm; | 
|  | LPWSTR devname, portname; | 
|  |  | 
|  | dm       = pagesetup_get_devmode(data); | 
|  | devname  = pagesetup_get_devname(data); | 
|  | portname = pagesetup_get_portname(data); | 
|  |  | 
|  | PRINTDLG_SetUpPrinterListComboW(hDlg, cmb1, devname); | 
|  | PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, devname, portname, dm); | 
|  | PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, devname, portname, dm); | 
|  |  | 
|  | pagesetup_release_a_devname(data, portname); | 
|  | pagesetup_release_a_devname(data, devname); | 
|  | pagesetup_release_devmode(data, dm); | 
|  | } | 
|  |  | 
|  |  | 
|  | /**************************************************************************************** | 
|  | *  pagesetup_change_printer_dialog | 
|  | * | 
|  | *  Pops up another dialog that lets the user pick another printer. | 
|  | * | 
|  | *  For now we display the PrintDlg, this should display a striped down version of it. | 
|  | */ | 
|  | static void pagesetup_change_printer_dialog(HWND hDlg, pagesetup_data *data) | 
|  | { | 
|  | PRINTDLGW prnt; | 
|  | LPWSTR drvname, devname, portname; | 
|  | DEVMODEW *tmp_dm, *dm; | 
|  |  | 
|  | memset(&prnt, 0, sizeof(prnt)); | 
|  | prnt.lStructSize = sizeof(prnt); | 
|  | prnt.Flags     = 0; | 
|  | prnt.hwndOwner = hDlg; | 
|  |  | 
|  | drvname = pagesetup_get_drvname(data); | 
|  | devname = pagesetup_get_devname(data); | 
|  | portname = pagesetup_get_portname(data); | 
|  | prnt.hDevNames = 0; | 
|  | PRINTDLG_CreateDevNamesW(&prnt.hDevNames, drvname, devname, portname); | 
|  | pagesetup_release_a_devname(data, portname); | 
|  | pagesetup_release_a_devname(data, devname); | 
|  | pagesetup_release_a_devname(data, drvname); | 
|  |  | 
|  | tmp_dm = pagesetup_get_devmode(data); | 
|  | prnt.hDevMode = GlobalAlloc(GMEM_MOVEABLE, tmp_dm->dmSize + tmp_dm->dmDriverExtra); | 
|  | dm = GlobalLock(prnt.hDevMode); | 
|  | memcpy(dm, tmp_dm, tmp_dm->dmSize + tmp_dm->dmDriverExtra); | 
|  | GlobalUnlock(prnt.hDevMode); | 
|  | pagesetup_release_devmode(data, tmp_dm); | 
|  |  | 
|  | if (PrintDlgW(&prnt)) | 
|  | { | 
|  | DEVMODEW *dm = GlobalLock(prnt.hDevMode); | 
|  | DEVNAMES *dn = GlobalLock(prnt.hDevNames); | 
|  |  | 
|  | pagesetup_set_devnames(data, (WCHAR*)dn + dn->wDriverOffset, | 
|  | (WCHAR*)dn + dn->wDeviceOffset, (WCHAR *)dn + dn->wOutputOffset); | 
|  | pagesetup_set_devmode(data, dm); | 
|  | GlobalUnlock(prnt.hDevNames); | 
|  | GlobalUnlock(prnt.hDevMode); | 
|  | pagesetup_init_combos(hDlg, data); | 
|  | } | 
|  |  | 
|  | GlobalFree(prnt.hDevMode); | 
|  | GlobalFree(prnt.hDevNames); | 
|  |  | 
|  | } | 
|  |  | 
|  | /****************************************************************************************** | 
|  | * pagesetup_change_preview | 
|  | * | 
|  | * Changes paper preview size / position | 
|  | * | 
|  | */ | 
|  | static void pagesetup_change_preview(const pagesetup_data *data) | 
|  | { | 
|  | LONG width, height, x, y; | 
|  | RECT tmp; | 
|  | const int shadow = 4; | 
|  |  | 
|  | if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) | 
|  | { | 
|  | width  = data->rtDrawRect.right - data->rtDrawRect.left; | 
|  | height = pagesetup_get_papersize_pt(data)->y * width / pagesetup_get_papersize_pt(data)->x; | 
|  | } | 
|  | else | 
|  | { | 
|  | height = data->rtDrawRect.bottom - data->rtDrawRect.top; | 
|  | width  = pagesetup_get_papersize_pt(data)->x * height / pagesetup_get_papersize_pt(data)->y; | 
|  | } | 
|  | x = (data->rtDrawRect.right + data->rtDrawRect.left - width) / 2; | 
|  | y = (data->rtDrawRect.bottom + data->rtDrawRect.top - height) / 2; | 
|  | TRACE("draw rect %s x=%d, y=%d, w=%d, h=%d\n", | 
|  | wine_dbgstr_rect(&data->rtDrawRect), x, y, width, height); | 
|  |  | 
|  | MoveWindow(GetDlgItem(data->hDlg, rct2), x + width, y + shadow, shadow, height, FALSE); | 
|  | MoveWindow(GetDlgItem(data->hDlg, rct3), x + shadow, y + height, width, shadow, FALSE); | 
|  | MoveWindow(GetDlgItem(data->hDlg, rct1), x, y, width, height, FALSE); | 
|  |  | 
|  | tmp = data->rtDrawRect; | 
|  | tmp.right  += shadow; | 
|  | tmp.bottom += shadow; | 
|  | InvalidateRect(data->hDlg, &tmp, TRUE); | 
|  | } | 
|  |  | 
|  | static inline LONG *element_from_margin_id(RECT *rc, WORD id) | 
|  | { | 
|  | switch(id) | 
|  | { | 
|  | case edt4: return &rc->left; | 
|  | case edt5: return &rc->top; | 
|  | case edt6: return &rc->right; | 
|  | case edt7: return &rc->bottom; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static void update_margin_edits(HWND hDlg, const pagesetup_data *data, WORD id) | 
|  | { | 
|  | WCHAR str[100]; | 
|  | WORD idx; | 
|  |  | 
|  | for(idx = edt4; idx <= edt7; idx++) | 
|  | { | 
|  | if(id == 0 || id == idx) | 
|  | { | 
|  | size2str(data, *element_from_margin_id(pagesetup_get_margin_rect(data), idx), str); | 
|  | SetDlgItemTextW(hDlg, idx, str); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void margin_edit_notification(HWND hDlg, const pagesetup_data *data, WORD msg, WORD id) | 
|  | { | 
|  | switch (msg) | 
|  | { | 
|  | case EN_CHANGE: | 
|  | { | 
|  | WCHAR buf[10]; | 
|  | LONG val = 0; | 
|  | LONG *value = element_from_margin_id(pagesetup_get_margin_rect(data), id); | 
|  |  | 
|  | if (GetDlgItemTextW(hDlg, id, buf, sizeof(buf) / sizeof(buf[0])) != 0) | 
|  | { | 
|  | WCHAR *end; | 
|  | WCHAR decimal = get_decimal_sep(); | 
|  |  | 
|  | val = strtolW(buf, &end, 10); | 
|  | if(end != buf || *end == decimal) | 
|  | { | 
|  | int mult = is_metric(data) ? 100 : 1000; | 
|  | val *= mult; | 
|  | if(*end == decimal) | 
|  | { | 
|  | while(mult > 1) | 
|  | { | 
|  | end++; | 
|  | mult /= 10; | 
|  | if(isdigitW(*end)) | 
|  | val += (*end - '0') * mult; | 
|  | else | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | *value = val; | 
|  | return; | 
|  | } | 
|  |  | 
|  | case EN_KILLFOCUS: | 
|  | update_margin_edits(hDlg, data, id); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void set_margin_groupbox_title(HWND hDlg, const pagesetup_data *data) | 
|  | { | 
|  | WCHAR title[256]; | 
|  |  | 
|  | if(LoadStringW(COMDLG32_hInstance, is_metric(data) ? PD32_MARGINS_IN_MILLIMETERS : PD32_MARGINS_IN_INCHES, | 
|  | title, sizeof(title)/sizeof(title[0]))) | 
|  | SetDlgItemTextW(hDlg, grp4, title); | 
|  | } | 
|  |  | 
|  | static void pagesetup_update_orientation_buttons(HWND hDlg, const pagesetup_data *data) | 
|  | { | 
|  | if (pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) | 
|  | CheckRadioButton(hDlg, rad1, rad2, rad2); | 
|  | else | 
|  | CheckRadioButton(hDlg, rad1, rad2, rad1); | 
|  | } | 
|  |  | 
|  | /**************************************************************************************** | 
|  | *  pagesetup_printer_properties | 
|  | * | 
|  | *  Handle invocation of the 'Properties' button (not present in the default template). | 
|  | */ | 
|  | static void pagesetup_printer_properties(HWND hDlg, pagesetup_data *data) | 
|  | { | 
|  | HANDLE hprn; | 
|  | LPWSTR devname; | 
|  | DEVMODEW *dm; | 
|  | LRESULT count; | 
|  | int i; | 
|  |  | 
|  | devname = pagesetup_get_devname(data); | 
|  |  | 
|  | if (!OpenPrinterW(devname, &hprn, NULL)) | 
|  | { | 
|  | FIXME("Call to OpenPrinter did not succeed!\n"); | 
|  | pagesetup_release_a_devname(data, devname); | 
|  | return; | 
|  | } | 
|  |  | 
|  | dm = pagesetup_get_devmode(data); | 
|  | DocumentPropertiesW(hDlg, hprn, devname, dm, dm, DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); | 
|  | pagesetup_set_devmode(data, dm); | 
|  | pagesetup_release_devmode(data, dm); | 
|  | pagesetup_release_a_devname(data, devname); | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | /* Changing paper */ | 
|  | pagesetup_update_papersize(data); | 
|  | pagesetup_update_orientation_buttons(hDlg, data); | 
|  |  | 
|  | /* Changing paper preview */ | 
|  | pagesetup_change_preview(data); | 
|  |  | 
|  | /* Selecting paper in combo */ | 
|  | count = SendDlgItemMessageW(hDlg, cmb2, CB_GETCOUNT, 0, 0); | 
|  | if(count != CB_ERR) | 
|  | { | 
|  | WORD paperword = pagesetup_get_papersize(data); | 
|  | for(i = 0; i < count; i++) | 
|  | { | 
|  | if(SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0) == paperword) { | 
|  | SendDlgItemMessageW(hDlg, cmb2, CB_SETCURSEL, i, 0); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /******************************************************************************** | 
|  | * pagesetup_wm_command | 
|  | * process WM_COMMAND message for PageSetupDlg | 
|  | * | 
|  | * PARAMS | 
|  | *  hDlg 	[in] 	Main dialog HANDLE | 
|  | *  wParam 	[in]	WM_COMMAND wParam | 
|  | *  lParam	[in]	WM_COMMAND lParam | 
|  | *  pda		[in/out] ptr to PageSetupDataA | 
|  | */ | 
|  |  | 
|  | static BOOL pagesetup_wm_command(HWND hDlg, WPARAM wParam, LPARAM lParam, pagesetup_data *data) | 
|  | { | 
|  | WORD msg = HIWORD(wParam); | 
|  | WORD id  = LOWORD(wParam); | 
|  |  | 
|  | TRACE("loword (lparam) %d, wparam 0x%lx, lparam %08lx\n", | 
|  | LOWORD(lParam),wParam,lParam); | 
|  | switch (id)  { | 
|  | case IDOK: | 
|  | EndDialog(hDlg, TRUE); | 
|  | return TRUE ; | 
|  |  | 
|  | case IDCANCEL: | 
|  | EndDialog(hDlg, FALSE); | 
|  | return FALSE ; | 
|  |  | 
|  | case psh3: /* Printer... */ | 
|  | pagesetup_change_printer_dialog(hDlg, data); | 
|  | return TRUE; | 
|  |  | 
|  | case rad1: /* Portrait */ | 
|  | case rad2: /* Landscape */ | 
|  | if((id == rad1 && pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) || | 
|  | (id == rad2 && pagesetup_get_orientation(data) == DMORIENT_PORTRAIT)) | 
|  | { | 
|  | pagesetup_set_orientation(data, (id == rad1) ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE); | 
|  | pagesetup_update_papersize(data); | 
|  | rotate_rect(pagesetup_get_margin_rect(data), (id == rad2)); | 
|  | update_margin_edits(hDlg, data, 0); | 
|  | pagesetup_change_preview(data); | 
|  | } | 
|  | break; | 
|  | case cmb1: /* Printer combo */ | 
|  | if(msg == CBN_SELCHANGE) | 
|  | { | 
|  | WCHAR name[256]; | 
|  | GetDlgItemTextW(hDlg, id, name, sizeof(name) / sizeof(name[0])); | 
|  | pagesetup_change_printer(name, data); | 
|  | pagesetup_init_combos(hDlg, data); | 
|  | } | 
|  | break; | 
|  | case cmb2: /* Paper combo */ | 
|  | if(msg == CBN_SELCHANGE) | 
|  | { | 
|  | DWORD paperword = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, | 
|  | SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0), 0); | 
|  | if (paperword != CB_ERR) | 
|  | { | 
|  | pagesetup_set_papersize(data, paperword); | 
|  | pagesetup_update_papersize(data); | 
|  | pagesetup_change_preview(data); | 
|  | } else | 
|  | FIXME("could not get dialog text for papersize cmbbox?\n"); | 
|  | } | 
|  | break; | 
|  | case cmb3: /* Paper Source */ | 
|  | if(msg == CBN_SELCHANGE) | 
|  | { | 
|  | WORD source = SendDlgItemMessageW(hDlg, cmb3, CB_GETITEMDATA, | 
|  | SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0), 0); | 
|  | pagesetup_set_defaultsource(data, source); | 
|  | } | 
|  | break; | 
|  | case psh2: /* Printer Properties button */ | 
|  | pagesetup_printer_properties(hDlg, data); | 
|  | break; | 
|  | case edt4: | 
|  | case edt5: | 
|  | case edt6: | 
|  | case edt7: | 
|  | margin_edit_notification(hDlg, data, msg, id); | 
|  | break; | 
|  | } | 
|  | InvalidateRect(GetDlgItem(hDlg, rct1), NULL, TRUE); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           default_page_paint_hook | 
|  | * Default hook paint procedure that receives WM_PSD_* messages from the dialog box | 
|  | * whenever the sample page is redrawn. | 
|  | */ | 
|  | static UINT_PTR default_page_paint_hook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, | 
|  | const pagesetup_data *data) | 
|  | { | 
|  | LPRECT lprc = (LPRECT) lParam; | 
|  | HDC hdc = (HDC) wParam; | 
|  | HPEN hpen, holdpen; | 
|  | LOGFONTW lf; | 
|  | HFONT hfont, holdfont; | 
|  | INT oldbkmode; | 
|  | TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER); | 
|  | /* Call user paint hook if enable */ | 
|  | if (pagesetup_get_flags(data) & PSD_ENABLEPAGEPAINTHOOK) | 
|  | if (pagesetup_get_hook(data, page_paint_hook)(hwndDlg, uMsg, wParam, lParam)) | 
|  | return TRUE; | 
|  |  | 
|  | switch (uMsg) { | 
|  | /* LPPAGESETUPDLG in lParam */ | 
|  | case WM_PSD_PAGESETUPDLG: | 
|  | /* Inform about the sample page rectangle */ | 
|  | case WM_PSD_FULLPAGERECT: | 
|  | /* Inform about the margin rectangle */ | 
|  | case WM_PSD_MINMARGINRECT: | 
|  | return FALSE; | 
|  |  | 
|  | /* Draw dashed rectangle showing margins */ | 
|  | case WM_PSD_MARGINRECT: | 
|  | hpen = CreatePen(PS_DASH, 1, GetSysColor(COLOR_3DSHADOW)); | 
|  | holdpen = SelectObject(hdc, hpen); | 
|  | Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); | 
|  | DeleteObject(SelectObject(hdc, holdpen)); | 
|  | return TRUE; | 
|  | /* Draw the fake document */ | 
|  | case WM_PSD_GREEKTEXTRECT: | 
|  | /* select a nice scalable font, because we want the text really small */ | 
|  | SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); | 
|  | lf.lfHeight = 6; /* value chosen based on visual effect */ | 
|  | hfont = CreateFontIndirectW(&lf); | 
|  | holdfont = SelectObject(hdc, hfont); | 
|  |  | 
|  | /* if text not loaded, then do so now */ | 
|  | if (wszFakeDocumentText[0] == '\0') | 
|  | LoadStringW(COMDLG32_hInstance, | 
|  | IDS_FAKEDOCTEXT, | 
|  | wszFakeDocumentText, | 
|  | sizeof(wszFakeDocumentText)/sizeof(wszFakeDocumentText[0])); | 
|  |  | 
|  | oldbkmode = SetBkMode(hdc, TRANSPARENT); | 
|  | DrawTextW(hdc, wszFakeDocumentText, -1, lprc, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); | 
|  | SetBkMode(hdc, oldbkmode); | 
|  |  | 
|  | DeleteObject(SelectObject(hdc, holdfont)); | 
|  | return TRUE; | 
|  |  | 
|  | /* Envelope stamp */ | 
|  | case WM_PSD_ENVSTAMPRECT: | 
|  | /* Return address */ | 
|  | case WM_PSD_YAFULLPAGERECT: | 
|  | FIXME("envelope/stamp is not implemented\n"); | 
|  | return FALSE; | 
|  | default: | 
|  | FIXME("Unknown message %x\n",uMsg); | 
|  | return FALSE; | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           PagePaintProc | 
|  | * The main paint procedure for the PageSetupDlg function. | 
|  | * The Page Setup dialog box includes an image of a sample page that shows how | 
|  | * the user's selections affect the appearance of the printed output. | 
|  | * The image consists of a rectangle that represents the selected paper | 
|  | * or envelope type, with a dotted-line rectangle representing | 
|  | * the current margins, and partial (Greek text) characters | 
|  | * to show how text looks on the printed page. | 
|  | * | 
|  | * The following messages in the order sends to user hook procedure: | 
|  | *   WM_PSD_PAGESETUPDLG    Draw the contents of the sample page | 
|  | *   WM_PSD_FULLPAGERECT    Inform about the bounding rectangle | 
|  | *   WM_PSD_MINMARGINRECT   Inform about the margin rectangle (min margin?) | 
|  | *   WM_PSD_MARGINRECT      Draw the margin rectangle | 
|  | *   WM_PSD_GREEKTEXTRECT   Draw the Greek text inside the margin rectangle | 
|  | * If any of first three messages returns TRUE, painting done. | 
|  | * | 
|  | * PARAMS: | 
|  | *   hWnd   [in] Handle to the Page Setup dialog box | 
|  | *   uMsg   [in] Received message | 
|  | * | 
|  | * TODO: | 
|  | *   WM_PSD_ENVSTAMPRECT    Draw in the envelope-stamp rectangle (for envelopes only) | 
|  | *   WM_PSD_YAFULLPAGERECT  Draw the return address portion (for envelopes and other paper sizes) | 
|  | * | 
|  | * RETURNS: | 
|  | *   FALSE if all done correctly | 
|  | * | 
|  | */ | 
|  |  | 
|  |  | 
|  | static LRESULT CALLBACK | 
|  | PRINTDLG_PagePaintProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | PAINTSTRUCT ps; | 
|  | RECT rcClient, rcMargin; | 
|  | HPEN hpen, holdpen; | 
|  | HDC hdc; | 
|  | HBRUSH hbrush, holdbrush; | 
|  | pagesetup_data *data; | 
|  | int papersize=0, orientation=0; /* FIXME: set this values for user paint hook */ | 
|  | double scalx, scaly; | 
|  |  | 
|  | if (uMsg != WM_PAINT) | 
|  | return CallWindowProcA(lpfnStaticWndProc, hWnd, uMsg, wParam, lParam); | 
|  |  | 
|  | /* Processing WM_PAINT message */ | 
|  | data = GetPropW(hWnd, pagesetupdlg_prop); | 
|  | if (!data) { | 
|  | WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); | 
|  | return FALSE; | 
|  | } | 
|  | if (default_page_paint_hook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation), | 
|  | pagesetup_get_dlg_struct(data), data)) | 
|  | return FALSE; | 
|  |  | 
|  | hdc = BeginPaint(hWnd, &ps); | 
|  | GetClientRect(hWnd, &rcClient); | 
|  |  | 
|  | scalx = rcClient.right  / (double)pagesetup_get_papersize_pt(data)->x; | 
|  | scaly = rcClient.bottom / (double)pagesetup_get_papersize_pt(data)->y; | 
|  | rcMargin = rcClient; | 
|  |  | 
|  | rcMargin.left   += pagesetup_get_margin_rect(data)->left   * scalx; | 
|  | rcMargin.top    += pagesetup_get_margin_rect(data)->top    * scaly; | 
|  | rcMargin.right  -= pagesetup_get_margin_rect(data)->right  * scalx; | 
|  | rcMargin.bottom -= pagesetup_get_margin_rect(data)->bottom * scaly; | 
|  |  | 
|  | /* if the space is too small then we make sure to not draw anything */ | 
|  | rcMargin.left = min(rcMargin.left, rcMargin.right); | 
|  | rcMargin.top = min(rcMargin.top, rcMargin.bottom); | 
|  |  | 
|  | if (!default_page_paint_hook(hWnd, WM_PSD_FULLPAGERECT, (WPARAM)hdc, (LPARAM)&rcClient, data) && | 
|  | !default_page_paint_hook(hWnd, WM_PSD_MINMARGINRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data) ) | 
|  | { | 
|  | /* fill background */ | 
|  | hbrush = GetSysColorBrush(COLOR_3DHIGHLIGHT); | 
|  | FillRect(hdc, &rcClient, hbrush); | 
|  | holdbrush = SelectObject(hdc, hbrush); | 
|  |  | 
|  | hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); | 
|  | holdpen = SelectObject(hdc, hpen); | 
|  |  | 
|  | /* paint left edge */ | 
|  | MoveToEx(hdc, rcClient.left, rcClient.top, NULL); | 
|  | LineTo(hdc, rcClient.left, rcClient.bottom-1); | 
|  |  | 
|  | /* paint top edge */ | 
|  | MoveToEx(hdc, rcClient.left, rcClient.top, NULL); | 
|  | LineTo(hdc, rcClient.right, rcClient.top); | 
|  |  | 
|  | hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW)); | 
|  | DeleteObject(SelectObject(hdc, hpen)); | 
|  |  | 
|  | /* paint right edge */ | 
|  | MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL); | 
|  | LineTo(hdc, rcClient.right-1, rcClient.bottom); | 
|  |  | 
|  | /* paint bottom edge */ | 
|  | MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL); | 
|  | LineTo(hdc, rcClient.right, rcClient.bottom-1); | 
|  |  | 
|  | DeleteObject(SelectObject(hdc, holdpen)); | 
|  | DeleteObject(SelectObject(hdc, holdbrush)); | 
|  |  | 
|  | default_page_paint_hook(hWnd, WM_PSD_MARGINRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data); | 
|  |  | 
|  | /* give text a bit of a space from the frame */ | 
|  | rcMargin.left += 2; | 
|  | rcMargin.top += 2; | 
|  | rcMargin.right -= 2; | 
|  | rcMargin.bottom -= 2; | 
|  |  | 
|  | /* if the space is too small then we make sure to not draw anything */ | 
|  | rcMargin.left = min(rcMargin.left, rcMargin.right); | 
|  | rcMargin.top = min(rcMargin.top, rcMargin.bottom); | 
|  |  | 
|  | default_page_paint_hook(hWnd, WM_PSD_GREEKTEXTRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data); | 
|  | } | 
|  |  | 
|  | EndPaint(hWnd, &ps); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /******************************************************* | 
|  | * The margin edit controls are subclassed to filter | 
|  | * anything other than numbers and the decimal separator. | 
|  | */ | 
|  | static LRESULT CALLBACK pagesetup_margin_editproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | 
|  | { | 
|  | if (msg == WM_CHAR) | 
|  | { | 
|  | WCHAR decimal = get_decimal_sep(); | 
|  | WCHAR wc = (WCHAR)wparam; | 
|  | if(!isdigitW(wc) && wc != decimal && wc != VK_BACK) return 0; | 
|  | } | 
|  | return CallWindowProcW(edit_wndproc, hwnd, msg, wparam, lparam); | 
|  | } | 
|  |  | 
|  | static void subclass_margin_edits(HWND hDlg) | 
|  | { | 
|  | int id; | 
|  | WNDPROC old_proc; | 
|  |  | 
|  | for(id = edt4; id <= edt7; id++) | 
|  | { | 
|  | old_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hDlg, id), | 
|  | GWLP_WNDPROC, | 
|  | (ULONG_PTR)pagesetup_margin_editproc); | 
|  | InterlockedCompareExchangePointer((void**)&edit_wndproc, old_proc, NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           pagesetup_dlg_proc | 
|  | * | 
|  | * Message handler for PageSetupDlg | 
|  | */ | 
|  | static INT_PTR CALLBACK pagesetup_dlg_proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | pagesetup_data *data; | 
|  | INT_PTR		res = FALSE; | 
|  | HWND 		hDrawWnd; | 
|  |  | 
|  | if (uMsg == WM_INITDIALOG) { /*Init dialog*/ | 
|  | data = (pagesetup_data *)lParam; | 
|  | data->hDlg = hDlg; | 
|  |  | 
|  | hDrawWnd = GetDlgItem(hDlg, rct1); | 
|  | TRACE("set property to %p\n", data); | 
|  | SetPropW(hDlg, pagesetupdlg_prop, data); | 
|  | SetPropW(hDrawWnd, pagesetupdlg_prop, data); | 
|  | GetWindowRect(hDrawWnd, &data->rtDrawRect); /* Calculating rect in client coordinates where paper draws */ | 
|  | ScreenToClient(hDlg, (LPPOINT)&data->rtDrawRect); | 
|  | ScreenToClient(hDlg, (LPPOINT)(&data->rtDrawRect.right)); | 
|  | lpfnStaticWndProc = (WNDPROC)SetWindowLongPtrW( | 
|  | hDrawWnd, | 
|  | GWLP_WNDPROC, | 
|  | (ULONG_PTR)PRINTDLG_PagePaintProc); | 
|  |  | 
|  | /* FIXME: Paint hook. Must it be at begin of initialization or at end? */ | 
|  | res = TRUE; | 
|  | if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK) | 
|  | { | 
|  | if (!pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam, | 
|  | pagesetup_get_dlg_struct(data))) | 
|  | FIXME("Setup page hook failed?\n"); | 
|  | } | 
|  |  | 
|  | /* if printer button disabled */ | 
|  | if (pagesetup_get_flags(data) & PSD_DISABLEPRINTER) | 
|  | EnableWindow(GetDlgItem(hDlg, psh3), FALSE); | 
|  | /* if margin edit boxes disabled */ | 
|  | if (pagesetup_get_flags(data) & PSD_DISABLEMARGINS) | 
|  | { | 
|  | EnableWindow(GetDlgItem(hDlg, edt4), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, edt5), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, edt6), FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg, edt7), FALSE); | 
|  | } | 
|  |  | 
|  | /* Set orientation radiobuttons properly */ | 
|  | pagesetup_update_orientation_buttons(hDlg, data); | 
|  |  | 
|  | /* if orientation disabled */ | 
|  | if (pagesetup_get_flags(data) & PSD_DISABLEORIENTATION) | 
|  | { | 
|  | EnableWindow(GetDlgItem(hDlg,rad1),FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg,rad2),FALSE); | 
|  | } | 
|  |  | 
|  | /* We fill them out enabled or not */ | 
|  | if (!(pagesetup_get_flags(data) & PSD_MARGINS)) | 
|  | { | 
|  | /* default is 1 inch */ | 
|  | LONG size = thousandths_inch_to_size(data, 1000); | 
|  | SetRect(pagesetup_get_margin_rect(data), size, size, size, size); | 
|  | } | 
|  | update_margin_edits(hDlg, data, 0); | 
|  | subclass_margin_edits(hDlg); | 
|  | set_margin_groupbox_title(hDlg, data); | 
|  |  | 
|  | /* if paper disabled */ | 
|  | if (pagesetup_get_flags(data) & PSD_DISABLEPAPER) | 
|  | { | 
|  | EnableWindow(GetDlgItem(hDlg,cmb2),FALSE); | 
|  | EnableWindow(GetDlgItem(hDlg,cmb3),FALSE); | 
|  | } | 
|  |  | 
|  | /* filling combos: printer, paper, source. selecting current printer (from DEVMODEA) */ | 
|  | pagesetup_init_combos(hDlg, data); | 
|  | pagesetup_update_papersize(data); | 
|  | pagesetup_set_defaultsource(data, DMBIN_FORMSOURCE); /* FIXME: This is the auto select bin. Is this correct? */ | 
|  |  | 
|  | /* Drawing paper prev */ | 
|  | pagesetup_change_preview(data); | 
|  | return TRUE; | 
|  | } else { | 
|  | data = GetPropW(hDlg, pagesetupdlg_prop); | 
|  | if (!data) | 
|  | { | 
|  | WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); | 
|  | return FALSE; | 
|  | } | 
|  | if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK) | 
|  | { | 
|  | res = pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam, lParam); | 
|  | if (res) return res; | 
|  | } | 
|  | } | 
|  | switch (uMsg) { | 
|  | case WM_COMMAND: | 
|  | return pagesetup_wm_command(hDlg, wParam, lParam, data); | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static WCHAR *get_default_printer(void) | 
|  | { | 
|  | WCHAR *name = NULL; | 
|  | DWORD len = 0; | 
|  |  | 
|  | GetDefaultPrinterW(NULL, &len); | 
|  | if(len) | 
|  | { | 
|  | name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | GetDefaultPrinterW(name, &len); | 
|  | } | 
|  | return name; | 
|  | } | 
|  |  | 
|  | static void pagesetup_dump_dlg_struct(const pagesetup_data *data) | 
|  | { | 
|  | if(TRACE_ON(commdlg)) | 
|  | { | 
|  | char flagstr[1000] = ""; | 
|  | const struct pd_flags *pflag = psd_flags; | 
|  | for( ; pflag->name; pflag++) | 
|  | { | 
|  | if(pagesetup_get_flags(data) & pflag->flag) | 
|  | { | 
|  | strcat(flagstr, pflag->name); | 
|  | strcat(flagstr, "|"); | 
|  | } | 
|  | } | 
|  | TRACE("%s: (%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" | 
|  | "hinst %p, flags %08x (%s)\n", | 
|  | data->unicode ? "unicode" : "ansi", | 
|  | data->u.dlgw, data->u.dlgw->hwndOwner, data->u.dlgw->hDevMode, | 
|  | data->u.dlgw->hDevNames, data->u.dlgw->hInstance, | 
|  | pagesetup_get_flags(data), flagstr); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void *pagesetup_get_template(pagesetup_data *data) | 
|  | { | 
|  | HRSRC res; | 
|  | HGLOBAL tmpl_handle; | 
|  |  | 
|  | if(pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) | 
|  | { | 
|  | tmpl_handle = data->u.dlgw->hPageSetupTemplate; | 
|  | } | 
|  | else if(pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPTEMPLATE) | 
|  | { | 
|  | if(data->unicode) | 
|  | res = FindResourceW(data->u.dlgw->hInstance, | 
|  | data->u.dlgw->lpPageSetupTemplateName, MAKEINTRESOURCEW(RT_DIALOG)); | 
|  | else | 
|  | res = FindResourceA(data->u.dlga->hInstance, | 
|  | data->u.dlga->lpPageSetupTemplateName, MAKEINTRESOURCEA(RT_DIALOG)); | 
|  | tmpl_handle = LoadResource(data->u.dlgw->hInstance, res); | 
|  | } | 
|  | else | 
|  | { | 
|  | res = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(PAGESETUPDLGORD), | 
|  | MAKEINTRESOURCEW(RT_DIALOG)); | 
|  | tmpl_handle = LoadResource(COMDLG32_hInstance, res); | 
|  | } | 
|  | return LockResource(tmpl_handle); | 
|  | } | 
|  |  | 
|  | static BOOL pagesetup_common(pagesetup_data *data) | 
|  | { | 
|  | BOOL ret; | 
|  | void *tmpl; | 
|  |  | 
|  | if(!pagesetup_get_dlg_struct(data)) | 
|  | { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | pagesetup_dump_dlg_struct(data); | 
|  |  | 
|  | if(data->u.dlgw->lStructSize != sizeof(PAGESETUPDLGW)) | 
|  | { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if ((pagesetup_get_flags(data) & PSD_ENABLEPAGEPAINTHOOK) && | 
|  | (pagesetup_get_hook(data, page_paint_hook) == NULL)) | 
|  | { | 
|  | COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if(!(pagesetup_get_flags(data) & (PSD_INTHOUSANDTHSOFINCHES | PSD_INHUNDREDTHSOFMILLIMETERS))) | 
|  | data->u.dlgw->Flags |= is_default_metric() ? | 
|  | PSD_INHUNDREDTHSOFMILLIMETERS : PSD_INTHOUSANDTHSOFINCHES; | 
|  |  | 
|  | if (!data->u.dlgw->hDevMode || !data->u.dlgw->hDevNames) | 
|  | { | 
|  | WCHAR *def = get_default_printer(); | 
|  | if(!def) | 
|  | { | 
|  | if (!(pagesetup_get_flags(data) & PSD_NOWARNING)) | 
|  | { | 
|  | WCHAR errstr[256]; | 
|  | LoadStringW(COMDLG32_hInstance, PD32_NO_DEFAULT_PRINTER, errstr, 255); | 
|  | MessageBoxW(data->u.dlgw->hwndOwner, errstr, 0, MB_OK | MB_ICONERROR); | 
|  | } | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); | 
|  | return FALSE; | 
|  | } | 
|  | pagesetup_change_printer(def, data); | 
|  | HeapFree(GetProcessHeap(), 0, def); | 
|  | } | 
|  |  | 
|  | if (pagesetup_get_flags(data) & PSD_RETURNDEFAULT) | 
|  | { | 
|  | pagesetup_update_papersize(data); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | tmpl = pagesetup_get_template(data); | 
|  |  | 
|  | ret = DialogBoxIndirectParamW(data->u.dlgw->hInstance, tmpl, | 
|  | data->u.dlgw->hwndOwner, | 
|  | pagesetup_dlg_proc, (LPARAM)data) > 0; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *            PageSetupDlgA  (COMDLG32.@) | 
|  | * | 
|  | *  Displays the PAGE SETUP dialog box, which enables the user to specify | 
|  | *  specific properties of a printed page such as | 
|  | *  size, source, orientation and the width of the page margins. | 
|  | * | 
|  | * PARAMS | 
|  | *  setupdlg [IO] PAGESETUPDLGA struct | 
|  | * | 
|  | * RETURNS | 
|  | *  TRUE    if the user pressed the OK button | 
|  | *  FALSE   if the user cancelled the window or an error occurred | 
|  | * | 
|  | * NOTES | 
|  | *    The values of hDevMode and hDevNames are filled on output and can be | 
|  | *    changed in PAGESETUPDLG when they are passed in PageSetupDlg. | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg) | 
|  | { | 
|  | pagesetup_data data; | 
|  |  | 
|  | data.unicode = FALSE; | 
|  | data.u.dlga  = setupdlg; | 
|  |  | 
|  | return pagesetup_common(&data); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *            PageSetupDlgW  (COMDLG32.@) | 
|  | * | 
|  | * See PageSetupDlgA. | 
|  | */ | 
|  | BOOL WINAPI PageSetupDlgW(LPPAGESETUPDLGW setupdlg) | 
|  | { | 
|  | pagesetup_data data; | 
|  |  | 
|  | data.unicode = TRUE; | 
|  | data.u.dlgw  = setupdlg; | 
|  |  | 
|  | return pagesetup_common(&data); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * PrintDlgExA (COMDLG32.@) | 
|  | * | 
|  | * See PrintDlgExW. | 
|  | * | 
|  | * BUGS | 
|  | *   Only a Stub | 
|  | * | 
|  | */ | 
|  | HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lppd) | 
|  | { | 
|  | DWORD     ret = E_FAIL; | 
|  | LPVOID    ptr; | 
|  |  | 
|  | FIXME("(%p) not fully implemented\n", lppd); | 
|  | if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXA))) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if (!IsWindow(lppd->hwndOwner)) | 
|  | return E_HANDLE; | 
|  |  | 
|  | if (lppd->Flags & PD_RETURNDEFAULT) | 
|  | { | 
|  | PRINTER_INFO_2A *pbuf; | 
|  | DRIVER_INFO_2A  *dbuf; | 
|  | HANDLE hprn; | 
|  | DWORD needed = 1024; | 
|  | BOOL bRet; | 
|  |  | 
|  | if (lppd->hDevMode || lppd->hDevNames) | 
|  | { | 
|  | WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | return E_INVALIDARG; | 
|  | } | 
|  | if (!PRINTDLG_OpenDefaultPrinter(&hprn)) | 
|  | { | 
|  | WARN("Can't find default printer\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | pbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); | 
|  | if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | pbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); | 
|  | } | 
|  | if (!bRet) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | ClosePrinter(hprn); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | needed = 1024; | 
|  | dbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed); | 
|  | if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | dbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed); | 
|  | } | 
|  | if (!bRet) | 
|  | { | 
|  | ERR("GetPrinterDriverŠ failed, last error %d, fix your config for printer %s!\n", | 
|  | GetLastError(), pbuf->pPrinterName); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | ClosePrinter(hprn); | 
|  | return E_FAIL; | 
|  | } | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | PRINTDLG_CreateDevNames(&(lppd->hDevNames), | 
|  | dbuf->pDriverPath, | 
|  | pbuf->pPrinterName, | 
|  | pbuf->pPortName); | 
|  | lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | if (lppd->hDevMode) | 
|  | { | 
|  | ptr = GlobalLock(lppd->hDevMode); | 
|  | if (ptr) | 
|  | { | 
|  | memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | ret = S_OK; | 
|  | } | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * PrintDlgExW (COMDLG32.@) | 
|  | * | 
|  | * Display the property sheet style PRINT dialog box | 
|  | * | 
|  | * PARAMS | 
|  | *  lppd  [IO] ptr to PRINTDLGEX struct | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: S_OK | 
|  | *  Failure: One of the following COM error codes: | 
|  | *    E_OUTOFMEMORY Insufficient memory. | 
|  | *    E_INVALIDARG  One or more arguments are invalid. | 
|  | *    E_POINTER     Invalid pointer. | 
|  | *    E_HANDLE      Invalid handle. | 
|  | *    E_FAIL        Unspecified error. | 
|  | * | 
|  | * NOTES | 
|  | * This Dialog enables the user to specify specific properties of the print job. | 
|  | * The property sheet can also have additional application-specific and | 
|  | * driver-specific property pages. | 
|  | * | 
|  | * BUGS | 
|  | *   Not fully implemented | 
|  | * | 
|  | */ | 
|  | HRESULT WINAPI PrintDlgExW(LPPRINTDLGEXW lppd) | 
|  | { | 
|  | DWORD     ret = E_FAIL; | 
|  | LPVOID    ptr; | 
|  |  | 
|  | FIXME("(%p) not fully implemented\n", lppd); | 
|  |  | 
|  | if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXW))) { | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | if (!IsWindow(lppd->hwndOwner)) { | 
|  | return E_HANDLE; | 
|  | } | 
|  |  | 
|  | if (lppd->Flags & PD_RETURNDEFAULT) { | 
|  | PRINTER_INFO_2W *pbuf; | 
|  | DRIVER_INFO_2W  *dbuf; | 
|  | HANDLE hprn; | 
|  | DWORD needed = 1024; | 
|  | BOOL bRet; | 
|  |  | 
|  | if (lppd->hDevMode || lppd->hDevNames) { | 
|  | WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | return E_INVALIDARG; | 
|  | } | 
|  | if (!PRINTDLG_OpenDefaultPrinter(&hprn)) { | 
|  | WARN("Can't find default printer\n"); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | pbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed); | 
|  | if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | pbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed); | 
|  | } | 
|  | if (!bRet) { | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | ClosePrinter(hprn); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | needed = 1024; | 
|  | dbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed); | 
|  | if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | dbuf = HeapAlloc(GetProcessHeap(), 0, needed); | 
|  | bRet = GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed); | 
|  | } | 
|  | if (!bRet) { | 
|  | ERR("GetPrinterDriverW failed, last error %d, fix your config for printer %s!\n", | 
|  | GetLastError(), debugstr_w(pbuf->pPrinterName)); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); | 
|  | ClosePrinter(hprn); | 
|  | return E_FAIL; | 
|  | } | 
|  | ClosePrinter(hprn); | 
|  |  | 
|  | PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), | 
|  | dbuf->pDriverPath, | 
|  | pbuf->pPrinterName, | 
|  | pbuf->pPortName); | 
|  | lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | if (lppd->hDevMode) { | 
|  | ptr = GlobalLock(lppd->hDevMode); | 
|  | if (ptr) { | 
|  | memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + | 
|  | pbuf->pDevMode->dmDriverExtra); | 
|  | GlobalUnlock(lppd->hDevMode); | 
|  | ret = S_OK; | 
|  | } | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, pbuf); | 
|  | HeapFree(GetProcessHeap(), 0, dbuf); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } |