1 /* 2 * COMMDLG - Print Dialog 3 * 4 * Copyright 1994 Martin Ayotte 5 * Copyright 1996 Albrecht Kleine 6 * Copyright 1999 Klaas van Gend 7 * Copyright 2000 Huw D M Davies 8 * Copyright 2010 Vitaly Perov 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24 #include <ctype.h> 25 #include <stdlib.h> 26 #include <stdarg.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <assert.h> 30 31 #define COBJMACROS 32 #define NONAMELESSUNION 33 #define NONAMELESSSTRUCT 34 #include "windef.h" 35 #include "winbase.h" 36 #include "wingdi.h" 37 #include "winuser.h" 38 #include "winspool.h" 39 #include "winerror.h" 40 #include "objbase.h" 41 #include "commdlg.h" 42 43 #include "wine/unicode.h" 44 #include "wine/debug.h" 45 46 #include "dlgs.h" 47 #include "cderr.h" 48 #include "cdlg.h" 49 50 WINE_DEFAULT_DEBUG_CHANNEL(commdlg); 51 52 /* Yes these constants are the same, but we're just copying win98 */ 53 #define UPDOWN_ID 0x270f 54 #define MAX_COPIES 9999 55 56 /* This PRINTDLGA internal structure stores 57 * pointers to several throughout useful structures. 58 */ 59 60 typedef struct 61 { 62 LPDEVMODEA lpDevMode; 63 LPPRINTDLGA lpPrintDlg; 64 LPPRINTER_INFO_2A lpPrinterInfo; 65 LPDRIVER_INFO_3A lpDriverInfo; 66 UINT HelpMessageID; 67 HICON hCollateIcon; /* PrintDlg only */ 68 HICON hNoCollateIcon; /* PrintDlg only */ 69 HICON hPortraitIcon; /* PrintSetupDlg only */ 70 HICON hLandscapeIcon; /* PrintSetupDlg only */ 71 HWND hwndUpDown; 72 } PRINT_PTRA; 73 74 typedef struct 75 { 76 LPDEVMODEW lpDevMode; 77 LPPRINTDLGW lpPrintDlg; 78 LPPRINTER_INFO_2W lpPrinterInfo; 79 LPDRIVER_INFO_3W lpDriverInfo; 80 UINT HelpMessageID; 81 HICON hCollateIcon; /* PrintDlg only */ 82 HICON hNoCollateIcon; /* PrintDlg only */ 83 HICON hPortraitIcon; /* PrintSetupDlg only */ 84 HICON hLandscapeIcon; /* PrintSetupDlg only */ 85 HWND hwndUpDown; 86 } PRINT_PTRW; 87 88 /* Debugging info */ 89 struct pd_flags 90 { 91 DWORD flag; 92 LPCSTR name; 93 }; 94 95 static const struct pd_flags psd_flags[] = { 96 {PSD_MINMARGINS,"PSD_MINMARGINS"}, 97 {PSD_MARGINS,"PSD_MARGINS"}, 98 {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"}, 99 {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"}, 100 {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"}, 101 {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"}, 102 {PSD_NOWARNING,"PSD_NOWARNING"}, 103 {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"}, 104 {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"}, 105 {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"}, 106 {PSD_SHOWHELP,"PSD_SHOWHELP"}, 107 {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"}, 108 {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"}, 109 {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"}, 110 {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"}, 111 {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"}, 112 {-1, NULL} 113 }; 114 115 static const struct pd_flags pd_flags[] = { 116 {PD_SELECTION, "PD_SELECTION "}, 117 {PD_PAGENUMS, "PD_PAGENUMS "}, 118 {PD_NOSELECTION, "PD_NOSELECTION "}, 119 {PD_NOPAGENUMS, "PD_NOPAGENUMS "}, 120 {PD_COLLATE, "PD_COLLATE "}, 121 {PD_PRINTTOFILE, "PD_PRINTTOFILE "}, 122 {PD_PRINTSETUP, "PD_PRINTSETUP "}, 123 {PD_NOWARNING, "PD_NOWARNING "}, 124 {PD_RETURNDC, "PD_RETURNDC "}, 125 {PD_RETURNIC, "PD_RETURNIC "}, 126 {PD_RETURNDEFAULT, "PD_RETURNDEFAULT "}, 127 {PD_SHOWHELP, "PD_SHOWHELP "}, 128 {PD_ENABLEPRINTHOOK, "PD_ENABLEPRINTHOOK "}, 129 {PD_ENABLESETUPHOOK, "PD_ENABLESETUPHOOK "}, 130 {PD_ENABLEPRINTTEMPLATE, "PD_ENABLEPRINTTEMPLATE "}, 131 {PD_ENABLESETUPTEMPLATE, "PD_ENABLESETUPTEMPLATE "}, 132 {PD_ENABLEPRINTTEMPLATEHANDLE, "PD_ENABLEPRINTTEMPLATEHANDLE "}, 133 {PD_ENABLESETUPTEMPLATEHANDLE, "PD_ENABLESETUPTEMPLATEHANDLE "}, 134 {PD_USEDEVMODECOPIES, "PD_USEDEVMODECOPIES[ANDCOLLATE] "}, 135 {PD_DISABLEPRINTTOFILE, "PD_DISABLEPRINTTOFILE "}, 136 {PD_HIDEPRINTTOFILE, "PD_HIDEPRINTTOFILE "}, 137 {PD_NONETWORKBUTTON, "PD_NONETWORKBUTTON "}, 138 {-1, NULL} 139 }; 140 /* address of wndproc for subclassed Static control */ 141 static WNDPROC lpfnStaticWndProc; 142 static WNDPROC edit_wndproc; 143 /* the text of the fake document to render for the Page Setup dialog */ 144 static WCHAR wszFakeDocumentText[1024]; 145 static const WCHAR pd32_collateW[] = { 'P', 'D', '3', '2', '_', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; 146 static const WCHAR pd32_nocollateW[] = { 'P', 'D', '3', '2', '_', 'N', 'O', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; 147 static const WCHAR pd32_portraitW[] = { 'P', 'D', '3', '2', '_', 'P', 'O', 'R', 'T', 'R', 'A', 'I', 'T', 0 }; 148 static const WCHAR pd32_landscapeW[] = { 'P', 'D', '3', '2', '_', 'L', 'A', 'N', 'D', 'S', 'C', 'A', 'P', 'E', 0 }; 149 static const WCHAR printdlg_prop[] = {'_','_','W','I','N','E','_','P','R','I','N','T','D','L','G','D','A','T','A',0}; 150 static const WCHAR pagesetupdlg_prop[] = { '_', '_', 'W', 'I', 'N', 'E', '_', 'P', 'A', 'G', 'E', 151 'S', 'E', 'T', 'U', 'P', 'D', 'L', 'G', 'D', 'A', 'T', 'A', 0 }; 152 153 154 static LPWSTR strdupW(LPCWSTR p) 155 { 156 LPWSTR ret; 157 DWORD len; 158 159 if(!p) return NULL; 160 len = (strlenW(p) + 1) * sizeof(WCHAR); 161 ret = HeapAlloc(GetProcessHeap(), 0, len); 162 memcpy(ret, p, len); 163 return ret; 164 } 165 166 /*********************************************************************** 167 * get_driver_info [internal] 168 * 169 * get DRIVER_INFO_3W for the current printer handle, 170 * alloc the buffer, when needed 171 */ 172 static DRIVER_INFO_3W * get_driver_infoW(HANDLE hprn) 173 { 174 DRIVER_INFO_3W *di3 = NULL; 175 DWORD needed = 0; 176 BOOL res; 177 178 res = GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); 179 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { 180 di3 = HeapAlloc(GetProcessHeap(), 0, needed); 181 res = GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)di3, needed, &needed); 182 } 183 184 if (res) 185 return di3; 186 187 TRACE("GetPrinterDriverW failed with %u\n", GetLastError()); 188 HeapFree(GetProcessHeap(), 0, di3); 189 return NULL; 190 } 191 192 static DRIVER_INFO_3A * get_driver_infoA(HANDLE hprn) 193 { 194 DRIVER_INFO_3A *di3 = NULL; 195 DWORD needed = 0; 196 BOOL res; 197 198 res = GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); 199 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { 200 di3 = HeapAlloc(GetProcessHeap(), 0, needed); 201 res = GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)di3, needed, &needed); 202 } 203 204 if (res) 205 return di3; 206 207 TRACE("GetPrinterDriverA failed with %u\n", GetLastError()); 208 HeapFree(GetProcessHeap(), 0, di3); 209 return NULL; 210 } 211 212 213 /*********************************************************************** 214 * get_printer_info [internal] 215 * 216 * get PRINTER_INFO_2W for the current printer handle, 217 * alloc the buffer, when needed 218 */ 219 static PRINTER_INFO_2W * get_printer_infoW(HANDLE hprn) 220 { 221 PRINTER_INFO_2W *pi2 = NULL; 222 DWORD needed = 0; 223 BOOL res; 224 225 res = GetPrinterW(hprn, 2, NULL, 0, &needed); 226 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { 227 pi2 = HeapAlloc(GetProcessHeap(), 0, needed); 228 res = GetPrinterW(hprn, 2, (LPBYTE)pi2, needed, &needed); 229 } 230 231 if (res) 232 return pi2; 233 234 TRACE("GetPrinterW failed with %u\n", GetLastError()); 235 HeapFree(GetProcessHeap(), 0, pi2); 236 return NULL; 237 } 238 239 static PRINTER_INFO_2A * get_printer_infoA(HANDLE hprn) 240 { 241 PRINTER_INFO_2A *pi2 = NULL; 242 DWORD needed = 0; 243 BOOL res; 244 245 res = GetPrinterA(hprn, 2, NULL, 0, &needed); 246 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { 247 pi2 = HeapAlloc(GetProcessHeap(), 0, needed); 248 res = GetPrinterA(hprn, 2, (LPBYTE)pi2, needed, &needed); 249 } 250 251 if (res) 252 return pi2; 253 254 TRACE("GetPrinterA failed with %u\n", GetLastError()); 255 HeapFree(GetProcessHeap(), 0, pi2); 256 return NULL; 257 } 258 259 260 /*********************************************************************** 261 * update_devmode_handle [internal] 262 * 263 * update a devmode handle for the given DEVMODE, alloc the buffer, when needed 264 */ 265 static HGLOBAL update_devmode_handleW(HGLOBAL hdm, DEVMODEW *dm) 266 { 267 SIZE_T size = GlobalSize(hdm); 268 LPVOID ptr; 269 270 /* Increase / alloc the global memory block, when needed */ 271 if ((dm->dmSize + dm->dmDriverExtra) > size) { 272 if (hdm) 273 hdm = GlobalReAlloc(hdm, dm->dmSize + dm->dmDriverExtra, 0); 274 else 275 hdm = GlobalAlloc(GMEM_MOVEABLE, dm->dmSize + dm->dmDriverExtra); 276 } 277 278 if (hdm) { 279 ptr = GlobalLock(hdm); 280 if (ptr) { 281 memcpy(ptr, dm, dm->dmSize + dm->dmDriverExtra); 282 GlobalUnlock(hdm); 283 } 284 else 285 { 286 GlobalFree(hdm); 287 hdm = NULL; 288 } 289 } 290 return hdm; 291 } 292 293 static HGLOBAL update_devmode_handleA(HGLOBAL hdm, DEVMODEA *dm) 294 { 295 SIZE_T size = GlobalSize(hdm); 296 LPVOID ptr; 297 298 /* Increase / alloc the global memory block, when needed */ 299 if ((dm->dmSize + dm->dmDriverExtra) > size) { 300 if (hdm) 301 hdm = GlobalReAlloc(hdm, dm->dmSize + dm->dmDriverExtra, 0); 302 else 303 hdm = GlobalAlloc(GMEM_MOVEABLE, dm->dmSize + dm->dmDriverExtra); 304 } 305 306 if (hdm) { 307 ptr = GlobalLock(hdm); 308 if (ptr) { 309 memcpy(ptr, dm, dm->dmSize + dm->dmDriverExtra); 310 GlobalUnlock(hdm); 311 } 312 else 313 { 314 GlobalFree(hdm); 315 hdm = NULL; 316 } 317 } 318 return hdm; 319 } 320 321 /*********************************************************** 322 * convert_to_devmodeA 323 * 324 * Creates an ansi copy of supplied devmode 325 */ 326 static DEVMODEA *convert_to_devmodeA(const DEVMODEW *dmW) 327 { 328 DEVMODEA *dmA; 329 DWORD size; 330 331 if (!dmW) return NULL; 332 size = dmW->dmSize - CCHDEVICENAME - 333 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0); 334 335 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra); 336 if (!dmA) return NULL; 337 338 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, 339 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL); 340 341 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) 342 { 343 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion, 344 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion)); 345 } 346 else 347 { 348 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion, 349 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion)); 350 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, 351 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL); 352 353 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels)); 354 } 355 356 dmA->dmSize = size; 357 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra); 358 return dmA; 359 } 360 361 /*********************************************************************** 362 * PRINTDLG_OpenDefaultPrinter 363 * 364 * Returns a winspool printer handle to the default printer in *hprn 365 * Caller must call ClosePrinter on the handle 366 * 367 * Returns TRUE on success else FALSE 368 */ 369 static BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn) 370 { 371 WCHAR buf[260]; 372 DWORD dwBufLen = sizeof(buf) / sizeof(buf[0]); 373 BOOL res; 374 if(!GetDefaultPrinterW(buf, &dwBufLen)) 375 return FALSE; 376 res = OpenPrinterW(buf, hprn, NULL); 377 if (!res) 378 WARN("Could not open printer %s\n", debugstr_w(buf)); 379 return res; 380 } 381 382 /*********************************************************************** 383 * PRINTDLG_SetUpPrinterListCombo 384 * 385 * Initializes printer list combox. 386 * hDlg: HWND of dialog 387 * id: Control id of combo 388 * name: Name of printer to select 389 * 390 * Initializes combo with list of available printers. Selects printer 'name' 391 * If name is NULL or does not exist select the default printer. 392 * 393 * Returns number of printers added to list. 394 */ 395 static INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name) 396 { 397 DWORD needed, num; 398 INT i; 399 LPPRINTER_INFO_2A pi; 400 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); 401 pi = HeapAlloc(GetProcessHeap(), 0, needed); 402 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, 403 &num); 404 405 SendDlgItemMessageA(hDlg, id, CB_RESETCONTENT, 0, 0); 406 407 for(i = 0; i < num; i++) { 408 SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0, 409 (LPARAM)pi[i].pPrinterName ); 410 } 411 HeapFree(GetProcessHeap(), 0, pi); 412 if(!name || 413 (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, 414 (LPARAM)name)) == CB_ERR) { 415 416 char buf[260]; 417 DWORD dwBufLen = sizeof(buf); 418 if (name != NULL) 419 WARN("Can't find %s in printer list so trying to find default\n", 420 debugstr_a(name)); 421 if(!GetDefaultPrinterA(buf, &dwBufLen)) 422 return num; 423 i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); 424 if(i == CB_ERR) 425 FIXME("Can't find default printer in printer list\n"); 426 } 427 SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0); 428 return num; 429 } 430 431 static INT PRINTDLG_SetUpPrinterListComboW(HWND hDlg, UINT id, LPCWSTR name) 432 { 433 DWORD needed, num; 434 INT i; 435 LPPRINTER_INFO_2W pi; 436 EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); 437 pi = HeapAlloc(GetProcessHeap(), 0, needed); 438 EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, 439 &num); 440 441 for(i = 0; i < num; i++) { 442 SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0, 443 (LPARAM)pi[i].pPrinterName ); 444 } 445 HeapFree(GetProcessHeap(), 0, pi); 446 if(!name || 447 (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, 448 (LPARAM)name)) == CB_ERR) { 449 WCHAR buf[260]; 450 DWORD dwBufLen = sizeof(buf)/sizeof(buf[0]); 451 if (name != NULL) 452 WARN("Can't find %s in printer list so trying to find default\n", 453 debugstr_w(name)); 454 if(!GetDefaultPrinterW(buf, &dwBufLen)) 455 return num; 456 i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); 457 if(i == CB_ERR) 458 TRACE("Can't find default printer in printer list\n"); 459 } 460 SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0); 461 return num; 462 } 463 464 /*********************************************************************** 465 * PRINTDLG_CreateDevNames [internal] 466 * 467 * 468 * creates a DevNames structure. 469 * 470 * (NB. when we handle unicode the offsets will be in wchars). 471 */ 472 static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, const char* DeviceDriverName, 473 const char* DeviceName, const char* OutputPort) 474 { 475 long size; 476 char* pDevNamesSpace; 477 char* pTempPtr; 478 LPDEVNAMES lpDevNames; 479 char buf[260]; 480 DWORD dwBufLen = sizeof(buf); 481 const char *p; 482 483 p = strrchr( DeviceDriverName, '\\' ); 484 if (p) DeviceDriverName = p + 1; 485 486 size = strlen(DeviceDriverName) + 1 487 + strlen(DeviceName) + 1 488 + strlen(OutputPort) + 1 489 + sizeof(DEVNAMES); 490 491 if(*hmem) 492 *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); 493 else 494 *hmem = GlobalAlloc(GMEM_MOVEABLE, size); 495 if (*hmem == 0) 496 return FALSE; 497 498 pDevNamesSpace = GlobalLock(*hmem); 499 lpDevNames = (LPDEVNAMES) pDevNamesSpace; 500 501 pTempPtr = pDevNamesSpace + sizeof(DEVNAMES); 502 strcpy(pTempPtr, DeviceDriverName); 503 lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; 504 505 pTempPtr += strlen(DeviceDriverName) + 1; 506 strcpy(pTempPtr, DeviceName); 507 lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; 508 509 pTempPtr += strlen(DeviceName) + 1; 510 strcpy(pTempPtr, OutputPort); 511 lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; 512 513 GetDefaultPrinterA(buf, &dwBufLen); 514 lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0; 515 GlobalUnlock(*hmem); 516 return TRUE; 517 } 518 519 static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName, 520 LPCWSTR DeviceName, LPCWSTR OutputPort) 521 { 522 long size; 523 LPWSTR pDevNamesSpace; 524 LPWSTR pTempPtr; 525 LPDEVNAMES lpDevNames; 526 WCHAR bufW[260]; 527 DWORD dwBufLen = sizeof(bufW) / sizeof(WCHAR); 528 const WCHAR *p; 529 530 p = strrchrW( DeviceDriverName, '\\' ); 531 if (p) DeviceDriverName = p + 1; 532 533 size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2 534 + sizeof(WCHAR)*lstrlenW(DeviceName) + 2 535 + sizeof(WCHAR)*lstrlenW(OutputPort) + 2 536 + sizeof(DEVNAMES); 537 538 if(*hmem) 539 *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); 540 else 541 *hmem = GlobalAlloc(GMEM_MOVEABLE, size); 542 if (*hmem == 0) 543 return FALSE; 544 545 pDevNamesSpace = GlobalLock(*hmem); 546 lpDevNames = (LPDEVNAMES) pDevNamesSpace; 547 548 pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1); 549 lstrcpyW(pTempPtr, DeviceDriverName); 550 lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; 551 552 pTempPtr += lstrlenW(DeviceDriverName) + 1; 553 lstrcpyW(pTempPtr, DeviceName); 554 lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; 555 556 pTempPtr += lstrlenW(DeviceName) + 1; 557 lstrcpyW(pTempPtr, OutputPort); 558 lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; 559 560 GetDefaultPrinterW(bufW, &dwBufLen); 561 lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0; 562 GlobalUnlock(*hmem); 563 return TRUE; 564 } 565 566 /*********************************************************************** 567 * PRINTDLG_UpdatePrintDlg [internal] 568 * 569 * 570 * updates the PrintDlg structure for return values. 571 * 572 * RETURNS 573 * FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values) 574 * TRUE if successful. 575 */ 576 static BOOL PRINTDLG_UpdatePrintDlgA(HWND hDlg, 577 PRINT_PTRA* PrintStructures) 578 { 579 LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; 580 PDEVMODEA lpdm = PrintStructures->lpDevMode; 581 LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo; 582 583 584 if(!lpdm) { 585 FIXME("No lpdm ptr?\n"); 586 return FALSE; 587 } 588 589 590 if(!(lppd->Flags & PD_PRINTSETUP)) { 591 /* check whether nFromPage and nToPage are within range defined by 592 * nMinPage and nMaxPage 593 */ 594 if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ 595 WORD nToPage; 596 WORD nFromPage; 597 BOOL translated; 598 nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); 599 nToPage = GetDlgItemInt(hDlg, edt2, &translated, FALSE); 600 601 /* if no ToPage value is entered, use the FromPage value */ 602 if(!translated) nToPage = nFromPage; 603 604 if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || 605 nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { 606 WCHAR resourcestr[256]; 607 WCHAR resultstr[256]; 608 LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, resourcestr, 255); 609 wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage); 610 LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, resourcestr, 255); 611 MessageBoxW(hDlg, resultstr, resourcestr, MB_OK | MB_ICONWARNING); 612 return FALSE; 613 } 614 lppd->nFromPage = nFromPage; 615 lppd->nToPage = nToPage; 616 lppd->Flags |= PD_PAGENUMS; 617 } 618 else 619 lppd->Flags &= ~PD_PAGENUMS; 620 621 if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */ 622 lppd->Flags |= PD_SELECTION; 623 else 624 lppd->Flags &= ~PD_SELECTION; 625 626 if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ 627 static char file[] = "FILE:"; 628 lppd->Flags |= PD_PRINTTOFILE; 629 pi->pPortName = file; 630 } 631 632 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ 633 FIXME("Collate lppd not yet implemented as output\n"); 634 } 635 636 /* set PD_Collate and nCopies */ 637 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { 638 /* The application doesn't support multiple copies or collate... 639 */ 640 lppd->Flags &= ~PD_COLLATE; 641 lppd->nCopies = 1; 642 /* if the printer driver supports it... store info there 643 * otherwise no collate & multiple copies ! 644 */ 645 if (lpdm->dmFields & DM_COLLATE) 646 lpdm->dmCollate = 647 (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); 648 if (lpdm->dmFields & DM_COPIES) 649 lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); 650 } else { 651 /* Application is responsible for multiple copies */ 652 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) 653 lppd->Flags |= PD_COLLATE; 654 else 655 lppd->Flags &= ~PD_COLLATE; 656 lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); 657 /* multiple copies already included in the document. Driver must print only one copy */ 658 lpdm->u1.s1.dmCopies = 1; 659 } 660 661 /* Print quality, PrintDlg16 */ 662 if(GetDlgItem(hDlg, cmb1)) 663 { 664 HWND hQuality = GetDlgItem(hDlg, cmb1); 665 int Sel = SendMessageA(hQuality, CB_GETCURSEL, 0, 0); 666 667 if(Sel != CB_ERR) 668 { 669 LONG dpi = SendMessageA(hQuality, CB_GETITEMDATA, Sel, 0); 670 lpdm->dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION; 671 lpdm->u1.s1.dmPrintQuality = LOWORD(dpi); 672 lpdm->dmYResolution = HIWORD(dpi); 673 } 674 } 675 } 676 return TRUE; 677 } 678 679 static BOOL PRINTDLG_UpdatePrintDlgW(HWND hDlg, 680 PRINT_PTRW* PrintStructures) 681 { 682 LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; 683 PDEVMODEW lpdm = PrintStructures->lpDevMode; 684 LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo; 685 686 687 if(!lpdm) { 688 FIXME("No lpdm ptr?\n"); 689 return FALSE; 690 } 691 692 693 if(!(lppd->Flags & PD_PRINTSETUP)) { 694 /* check whether nFromPage and nToPage are within range defined by 695 * nMinPage and nMaxPage 696 */ 697 if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ 698 WORD nToPage; 699 WORD nFromPage; 700 BOOL translated; 701 nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); 702 nToPage = GetDlgItemInt(hDlg, edt2, &translated, FALSE); 703 704 /* if no ToPage value is entered, use the FromPage value */ 705 if(!translated) nToPage = nFromPage; 706 707 if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || 708 nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { 709 WCHAR resourcestr[256]; 710 WCHAR resultstr[256]; 711 DWORD_PTR args[2]; 712 LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, 713 resourcestr, 255); 714 args[0] = lppd->nMinPage; 715 args[1] = lppd->nMaxPage; 716 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, 717 resourcestr, 0, 0, resultstr, 718 sizeof(resultstr)/sizeof(*resultstr), 719 (__ms_va_list*)args); 720 LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, 721 resourcestr, 255); 722 MessageBoxW(hDlg, resultstr, resourcestr, 723 MB_OK | MB_ICONWARNING); 724 return FALSE; 725 } 726 lppd->nFromPage = nFromPage; 727 lppd->nToPage = nToPage; 728 lppd->Flags |= PD_PAGENUMS; 729 } 730 else 731 lppd->Flags &= ~PD_PAGENUMS; 732 733 if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */ 734 lppd->Flags |= PD_SELECTION; 735 else 736 lppd->Flags &= ~PD_SELECTION; 737 738 if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ 739 static WCHAR file[] = {'F','I','L','E',':',0}; 740 lppd->Flags |= PD_PRINTTOFILE; 741 pi->pPortName = file; 742 } 743 744 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ 745 FIXME("Collate lppd not yet implemented as output\n"); 746 } 747 748 /* set PD_Collate and nCopies */ 749 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { 750 /* The application doesn't support multiple copies or collate... 751 */ 752 lppd->Flags &= ~PD_COLLATE; 753 lppd->nCopies = 1; 754 /* if the printer driver supports it... store info there 755 * otherwise no collate & multiple copies ! 756 */ 757 if (lpdm->dmFields & DM_COLLATE) 758 lpdm->dmCollate = 759 (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); 760 if (lpdm->dmFields & DM_COPIES) 761 lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); 762 } else { 763 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) 764 lppd->Flags |= PD_COLLATE; 765 else 766 lppd->Flags &= ~PD_COLLATE; 767 lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); 768 } 769 } 770 return TRUE; 771 } 772 773 /************************************************************************ 774 * PRINTDLG_SetUpPaperComboBox 775 * 776 * Initialize either the papersize or inputslot combos of the Printer Setup 777 * dialog. We store the associated word (eg DMPAPER_A4) as the item data. 778 * We also try to re-select the old selection. 779 */ 780 static BOOL PRINTDLG_SetUpPaperComboBoxA(HWND hDlg, 781 int nIDComboBox, 782 char* PrinterName, 783 char* PortName, 784 LPDEVMODEA dm) 785 { 786 int i; 787 int NrOfEntries; 788 char* Names; 789 WORD* Words; 790 DWORD Sel, old_Sel; 791 WORD oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */ 792 int NamesSize; 793 int fwCapability_Names; 794 int fwCapability_Words; 795 796 TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox); 797 798 /* query the dialog box for the current selected value */ 799 Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); 800 if(Sel != CB_ERR) { 801 /* we enter here only if a different printer is selected after 802 * the Print Setup dialog is opened. The current settings are 803 * stored into the newly selected printer. 804 */ 805 oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, 806 Sel, 0); 807 if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */ 808 oldWord = 0; /* There's no point in trying to keep custom 809 paper / bin sizes across printers */ 810 } 811 812 if (dm) 813 newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource; 814 815 if (nIDComboBox == cmb2) { 816 NamesSize = 64; 817 fwCapability_Names = DC_PAPERNAMES; 818 fwCapability_Words = DC_PAPERS; 819 } else { 820 nIDComboBox = cmb3; 821 NamesSize = 24; 822 fwCapability_Names = DC_BINNAMES; 823 fwCapability_Words = DC_BINS; 824 } 825 826 NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, 827 fwCapability_Names, NULL, dm); 828 if (NrOfEntries == 0) 829 WARN("no Name Entries found!\n"); 830 else if (NrOfEntries < 0) 831 return FALSE; 832 833 if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm) 834 != NrOfEntries) { 835 ERR("Number of caps is different\n"); 836 NrOfEntries = 0; 837 } 838 839 Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize); 840 Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); 841 DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Names, Names, dm); 842 NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, 843 fwCapability_Words, (LPSTR)Words, dm); 844 845 /* reset any current content in the combobox */ 846 SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); 847 848 /* store new content */ 849 for (i = 0; i < NrOfEntries; i++) { 850 DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0, 851 (LPARAM)(&Names[i*NamesSize]) ); 852 SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos, 853 Words[i]); 854 } 855 856 /* Look for old selection or the new default. 857 Can't do this is previous loop since item order will change as more items are added */ 858 Sel = 0; 859 old_Sel = NrOfEntries; 860 for (i = 0; i < NrOfEntries; i++) { 861 if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == 862 oldWord) { 863 old_Sel = i; 864 break; 865 } 866 if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord) 867 Sel = i; 868 } 869 870 if(old_Sel < NrOfEntries) 871 { 872 if (dm) 873 { 874 if(nIDComboBox == cmb2) 875 dm->u1.s1.dmPaperSize = oldWord; 876 else 877 dm->u1.s1.dmDefaultSource = oldWord; 878 } 879 Sel = old_Sel; 880 } 881 882 SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); 883 884 HeapFree(GetProcessHeap(),0,Words); 885 HeapFree(GetProcessHeap(),0,Names); 886 return TRUE; 887 } 888 889 static BOOL PRINTDLG_SetUpPaperComboBoxW(HWND hDlg, 890 int nIDComboBox, 891 const WCHAR* PrinterName, 892 const WCHAR* PortName, 893 LPDEVMODEW dm) 894 { 895 int i; 896 int NrOfEntries; 897 WCHAR* Names; 898 WORD* Words; 899 DWORD Sel, old_Sel; 900 WORD oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */ 901 int NamesSize; 902 int fwCapability_Names; 903 int fwCapability_Words; 904 905 TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox); 906 907 /* query the dialog box for the current selected value */ 908 Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); 909 if(Sel != CB_ERR) { 910 /* we enter here only if a different printer is selected after 911 * the Print Setup dialog is opened. The current settings are 912 * stored into the newly selected printer. 913 */ 914 oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, 915 Sel, 0); 916 917 if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */ 918 oldWord = 0; /* There's no point in trying to keep custom 919 paper / bin sizes across printers */ 920 } 921 922 if (dm) 923 newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource; 924 925 if (nIDComboBox == cmb2) { 926 NamesSize = 64; 927 fwCapability_Names = DC_PAPERNAMES; 928 fwCapability_Words = DC_PAPERS; 929 } else { 930 nIDComboBox = cmb3; 931 NamesSize = 24; 932 fwCapability_Names = DC_BINNAMES; 933 fwCapability_Words = DC_BINS; 934 } 935 936 NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, 937 fwCapability_Names, NULL, dm); 938 if (NrOfEntries == 0) 939 WARN("no Name Entries found!\n"); 940 else if (NrOfEntries < 0) 941 return FALSE; 942 943 if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm) 944 != NrOfEntries) { 945 ERR("Number of caps is different\n"); 946 NrOfEntries = 0; 947 } 948 949 Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize); 950 Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); 951 DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Names, Names, dm); 952 NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, 953 fwCapability_Words, Words, dm); 954 955 /* reset any current content in the combobox */ 956 SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); 957 958 /* store new content */ 959 for (i = 0; i < NrOfEntries; i++) { 960 DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0, 961 (LPARAM)(&Names[i*NamesSize]) ); 962 SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos, 963 Words[i]); 964 } 965 966 /* Look for old selection or the new default. 967 Can't do this is previous loop since item order will change as more items are added */ 968 Sel = 0; 969 old_Sel = NrOfEntries; 970 for (i = 0; i < NrOfEntries; i++) { 971 if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == 972 oldWord) { 973 old_Sel = i; 974 break; 975 } 976 if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord) 977 Sel = i; 978 } 979 980 if(old_Sel < NrOfEntries) 981 { 982 if (dm) 983 { 984 if(nIDComboBox == cmb2) 985 dm->u1.s1.dmPaperSize = oldWord; 986 else 987 dm->u1.s1.dmDefaultSource = oldWord; 988 } 989 Sel = old_Sel; 990 } 991 992 SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); 993 994 HeapFree(GetProcessHeap(),0,Words); 995 HeapFree(GetProcessHeap(),0,Names); 996 return TRUE; 997 } 998 999 1000 /*********************************************************************** 1001 * PRINTDLG_UpdatePrinterInfoTexts [internal] 1002 */ 1003 static void PRINTDLG_UpdatePrinterInfoTextsA(HWND hDlg, const PRINTER_INFO_2A *pi) 1004 { 1005 char StatusMsg[256]; 1006 char ResourceString[256]; 1007 int i; 1008 1009 /* Status Message */ 1010 StatusMsg[0]='\0'; 1011 1012 /* add all status messages */ 1013 for (i = 0; i < 25; i++) { 1014 if (pi->Status & (1<<i)) { 1015 LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i, 1016 ResourceString, 255); 1017 strcat(StatusMsg,ResourceString); 1018 } 1019 } 1020 /* append "ready" */ 1021 /* FIXME: status==ready must only be appended if really so. 1022 but how to detect? */ 1023 LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY, 1024 ResourceString, 255); 1025 strcat(StatusMsg,ResourceString); 1026 SetDlgItemTextA(hDlg, stc12, StatusMsg); 1027 1028 /* set all other printer info texts */ 1029 SetDlgItemTextA(hDlg, stc11, pi->pDriverName); 1030 1031 if (pi->pLocation != NULL && pi->pLocation[0] != '\0') 1032 SetDlgItemTextA(hDlg, stc14, pi->pLocation); 1033 else 1034 SetDlgItemTextA(hDlg, stc14, pi->pPortName); 1035 SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : ""); 1036 return; 1037 } 1038 1039 static void PRINTDLG_UpdatePrinterInfoTextsW(HWND hDlg, const PRINTER_INFO_2W *pi) 1040 { 1041 WCHAR StatusMsg[256]; 1042 WCHAR ResourceString[256]; 1043 static const WCHAR emptyW[] = {0}; 1044 int i; 1045 1046 /* Status Message */ 1047 StatusMsg[0]='\0'; 1048 1049 /* add all status messages */ 1050 for (i = 0; i < 25; i++) { 1051 if (pi->Status & (1<<i)) { 1052 LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i, 1053 ResourceString, 255); 1054 lstrcatW(StatusMsg,ResourceString); 1055 } 1056 } 1057 /* append "ready" */ 1058 /* FIXME: status==ready must only be appended if really so. 1059 but how to detect? */ 1060 LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY, 1061 ResourceString, 255); 1062 lstrcatW(StatusMsg,ResourceString); 1063 SetDlgItemTextW(hDlg, stc12, StatusMsg); 1064 1065 /* set all other printer info texts */ 1066 SetDlgItemTextW(hDlg, stc11, pi->pDriverName); 1067 if (pi->pLocation != NULL && pi->pLocation[0] != '\0') 1068 SetDlgItemTextW(hDlg, stc14, pi->pLocation); 1069 else 1070 SetDlgItemTextW(hDlg, stc14, pi->pPortName); 1071 SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW); 1072 } 1073 1074 1075 /******************************************************************* 1076 * 1077 * PRINTDLG_ChangePrinter 1078 * 1079 */ 1080 static BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, PRINT_PTRA *PrintStructures) 1081 { 1082 LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; 1083 LPDEVMODEA lpdm = NULL; 1084 LONG dmSize; 1085 DWORD needed; 1086 HANDLE hprn; 1087 1088 HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); 1089 HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); 1090 if(!OpenPrinterA(name, &hprn, NULL)) { 1091 ERR("Can't open printer %s\n", name); 1092 return FALSE; 1093 } 1094 GetPrinterA(hprn, 2, NULL, 0, &needed); 1095 PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed); 1096 GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, 1097 &needed); 1098 GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); 1099 PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed); 1100 if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, 1101 needed, &needed)) { 1102 ERR("GetPrinterDriverA failed for %s, fix your config!\n",PrintStructures->lpPrinterInfo->pPrinterName); 1103 return FALSE; 1104 } 1105 ClosePrinter(hprn); 1106 1107 PRINTDLG_UpdatePrinterInfoTextsA(hDlg, PrintStructures->lpPrinterInfo); 1108 1109 HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); 1110 PrintStructures->lpDevMode = NULL; 1111 1112 dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0); 1113 if(dmSize == -1) { 1114 ERR("DocumentProperties fails on %s\n", debugstr_a(name)); 1115 return FALSE; 1116 } 1117 PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); 1118 dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL, 1119 DM_OUT_BUFFER); 1120 if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && 1121 !lstrcmpA( (LPSTR) lpdm->dmDeviceName, 1122 (LPSTR) PrintStructures->lpDevMode->dmDeviceName)) { 1123 /* Supplied devicemode matches current printer so try to use it */ 1124 DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm, 1125 DM_OUT_BUFFER | DM_IN_BUFFER); 1126 } 1127 if(lpdm) 1128 GlobalUnlock(lppd->hDevMode); 1129 1130 lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */ 1131 1132 if(!(lppd->Flags & PD_PRINTSETUP)) { 1133 /* Print range (All/Range/Selection) */ 1134 if(lppd->nFromPage != 0xffff) 1135 SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); 1136 if(lppd->nToPage != 0xffff) 1137 SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); 1138 1139 CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */ 1140 if (lppd->Flags & PD_NOSELECTION) 1141 EnableWindow(GetDlgItem(hDlg, rad2), FALSE); 1142 else 1143 if (lppd->Flags & PD_SELECTION) 1144 CheckRadioButton(hDlg, rad1, rad3, rad2); 1145 if (lppd->Flags & PD_NOPAGENUMS) { 1146 EnableWindow(GetDlgItem(hDlg, rad3), FALSE); 1147 EnableWindow(GetDlgItem(hDlg, stc2),FALSE); 1148 EnableWindow(GetDlgItem(hDlg, edt1), FALSE); 1149 EnableWindow(GetDlgItem(hDlg, stc3),FALSE); 1150 EnableWindow(GetDlgItem(hDlg, edt2), FALSE); 1151 } else { 1152 if (lppd->Flags & PD_PAGENUMS) 1153 CheckRadioButton(hDlg, rad1, rad3, rad3); 1154 } 1155 1156 /* Collate pages 1157 * 1158 * FIXME: The ico3 is not displayed for some reason. I don't know why. 1159 */ 1160 if (lppd->Flags & PD_COLLATE) { 1161 SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1162 (LPARAM)PrintStructures->hCollateIcon); 1163 CheckDlgButton(hDlg, chx2, 1); 1164 } else { 1165 SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1166 (LPARAM)PrintStructures->hNoCollateIcon); 1167 CheckDlgButton(hDlg, chx2, 0); 1168 } 1169 1170 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { 1171 /* if printer doesn't support it: no Collate */ 1172 if (!(lpdm->dmFields & DM_COLLATE)) { 1173 EnableWindow(GetDlgItem(hDlg, chx2), FALSE); 1174 EnableWindow(GetDlgItem(hDlg, ico3), FALSE); 1175 } 1176 } 1177 1178 /* nCopies */ 1179 { 1180 INT copies; 1181 if (lppd->hDevMode == 0) 1182 copies = lppd->nCopies; 1183 else 1184 copies = lpdm->u1.s1.dmCopies; 1185 if(copies == 0) copies = 1; 1186 else if(copies < 0) copies = MAX_COPIES; 1187 SetDlgItemInt(hDlg, edt3, copies, FALSE); 1188 } 1189 1190 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { 1191 /* if printer doesn't support it: no nCopies */ 1192 if (!(lpdm->dmFields & DM_COPIES)) { 1193 EnableWindow(GetDlgItem(hDlg, edt3), FALSE); 1194 EnableWindow(GetDlgItem(hDlg, stc5), FALSE); 1195 } 1196 } 1197 1198 /* print to file */ 1199 CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); 1200 if (lppd->Flags & PD_DISABLEPRINTTOFILE) 1201 EnableWindow(GetDlgItem(hDlg, chx1), FALSE); 1202 if (lppd->Flags & PD_HIDEPRINTTOFILE) 1203 ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); 1204 1205 /* Fill print quality combo, PrintDlg16 */ 1206 if(GetDlgItem(hDlg, cmb1)) 1207 { 1208 DWORD numResolutions = DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName, 1209 PrintStructures->lpPrinterInfo->pPortName, 1210 DC_ENUMRESOLUTIONS, NULL, lpdm); 1211 1212 if(numResolutions != -1) 1213 { 1214 HWND hQuality = GetDlgItem(hDlg, cmb1); 1215 LONG* Resolutions; 1216 char buf[255]; 1217 DWORD i; 1218 int dpiX, dpiY; 1219 HDC hPrinterDC = CreateDCA(PrintStructures->lpPrinterInfo->pDriverName, 1220 PrintStructures->lpPrinterInfo->pPrinterName, 1221 0, lpdm); 1222 1223 Resolutions = HeapAlloc(GetProcessHeap(), 0, numResolutions*sizeof(LONG)*2); 1224 DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName, 1225 PrintStructures->lpPrinterInfo->pPortName, 1226 DC_ENUMRESOLUTIONS, (LPSTR)Resolutions, lpdm); 1227 1228 dpiX = GetDeviceCaps(hPrinterDC, LOGPIXELSX); 1229 dpiY = GetDeviceCaps(hPrinterDC, LOGPIXELSY); 1230 DeleteDC(hPrinterDC); 1231 1232 SendMessageA(hQuality, CB_RESETCONTENT, 0, 0); 1233 for(i = 0; i < (numResolutions * 2); i += 2) 1234 { 1235 BOOL IsDefault = FALSE; 1236 LRESULT Index; 1237 1238 if(Resolutions[i] == Resolutions[i+1]) 1239 { 1240 if(dpiX == Resolutions[i]) 1241 IsDefault = TRUE; 1242 sprintf(buf, "%d dpi", Resolutions[i]); 1243 } else 1244 { 1245 if(dpiX == Resolutions[i] && dpiY == Resolutions[i+1]) 1246 IsDefault = TRUE; 1247 sprintf(buf, "%d dpi x %d dpi", Resolutions[i], Resolutions[i+1]); 1248 } 1249 1250 Index = SendMessageA(hQuality, CB_ADDSTRING, 0, (LPARAM)buf); 1251 1252 if(IsDefault) 1253 SendMessageA(hQuality, CB_SETCURSEL, Index, 0); 1254 1255 SendMessageA(hQuality, CB_SETITEMDATA, Index, MAKELONG(dpiX,dpiY)); 1256 } 1257 HeapFree(GetProcessHeap(), 0, Resolutions); 1258 } 1259 } 1260 } else { /* PD_PRINTSETUP */ 1261 BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT); 1262 1263 PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb2, 1264 PrintStructures->lpPrinterInfo->pPrinterName, 1265 PrintStructures->lpPrinterInfo->pPortName, 1266 lpdm); 1267 PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb3, 1268 PrintStructures->lpPrinterInfo->pPrinterName, 1269 PrintStructures->lpPrinterInfo->pPortName, 1270 lpdm); 1271 CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); 1272 SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1273 (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : 1274 PrintStructures->hLandscapeIcon)); 1275 1276 } 1277 1278 /* help button */ 1279 if ((lppd->Flags & PD_SHOWHELP)==0) { 1280 /* hide if PD_SHOWHELP not specified */ 1281 ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); 1282 } 1283 return TRUE; 1284 } 1285 1286 static BOOL PRINTDLG_ChangePrinterW(HWND hDlg, WCHAR *name, 1287 PRINT_PTRW *PrintStructures) 1288 { 1289 LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; 1290 LPDEVMODEW lpdm = NULL; 1291 LONG dmSize; 1292 DWORD needed; 1293 HANDLE hprn; 1294 1295 HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); 1296 HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); 1297 if(!OpenPrinterW(name, &hprn, NULL)) { 1298 ERR("Can't open printer %s\n", debugstr_w(name)); 1299 return FALSE; 1300 } 1301 GetPrinterW(hprn, 2, NULL, 0, &needed); 1302 PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed); 1303 GetPrinterW(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, 1304 &needed); 1305 GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); 1306 PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed); 1307 if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, 1308 needed, &needed)) { 1309 ERR("GetPrinterDriverA failed for %s, fix your config!\n",debugstr_w(PrintStructures->lpPrinterInfo->pPrinterName)); 1310 return FALSE; 1311 } 1312 ClosePrinter(hprn); 1313 1314 PRINTDLG_UpdatePrinterInfoTextsW(hDlg, PrintStructures->lpPrinterInfo); 1315 1316 HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); 1317 PrintStructures->lpDevMode = NULL; 1318 1319 dmSize = DocumentPropertiesW(0, 0, name, NULL, NULL, 0); 1320 if(dmSize == -1) { 1321 ERR("DocumentProperties fails on %s\n", debugstr_w(name)); 1322 return FALSE; 1323 } 1324 PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); 1325 dmSize = DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, NULL, 1326 DM_OUT_BUFFER); 1327 if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && 1328 !lstrcmpW(lpdm->dmDeviceName, 1329 PrintStructures->lpDevMode->dmDeviceName)) { 1330 /* Supplied devicemode matches current printer so try to use it */ 1331 DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, lpdm, 1332 DM_OUT_BUFFER | DM_IN_BUFFER); 1333 } 1334 if(lpdm) 1335 GlobalUnlock(lppd->hDevMode); 1336 1337 lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */ 1338 1339 if(!(lppd->Flags & PD_PRINTSETUP)) { 1340 /* Print range (All/Range/Selection) */ 1341 if(lppd->nFromPage != 0xffff) 1342 SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); 1343 if(lppd->nToPage != 0xffff) 1344 SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); 1345 1346 CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */ 1347 if (lppd->Flags & PD_NOSELECTION) 1348 EnableWindow(GetDlgItem(hDlg, rad2), FALSE); 1349 else 1350 if (lppd->Flags & PD_SELECTION) 1351 CheckRadioButton(hDlg, rad1, rad3, rad2); 1352 if (lppd->Flags & PD_NOPAGENUMS) { 1353 EnableWindow(GetDlgItem(hDlg, rad3), FALSE); 1354 EnableWindow(GetDlgItem(hDlg, stc2),FALSE); 1355 EnableWindow(GetDlgItem(hDlg, edt1), FALSE); 1356 EnableWindow(GetDlgItem(hDlg, stc3),FALSE); 1357 EnableWindow(GetDlgItem(hDlg, edt2), FALSE); 1358 } else { 1359 if (lppd->Flags & PD_PAGENUMS) 1360 CheckRadioButton(hDlg, rad1, rad3, rad3); 1361 } 1362 1363 /* Collate pages 1364 * 1365 * FIXME: The ico3 is not displayed for some reason. I don't know why. 1366 */ 1367 if (lppd->Flags & PD_COLLATE) { 1368 SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1369 (LPARAM)PrintStructures->hCollateIcon); 1370 CheckDlgButton(hDlg, chx2, 1); 1371 } else { 1372 SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1373 (LPARAM)PrintStructures->hNoCollateIcon); 1374 CheckDlgButton(hDlg, chx2, 0); 1375 } 1376 1377 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { 1378 /* if printer doesn't support it: no Collate */ 1379 if (!(lpdm->dmFields & DM_COLLATE)) { 1380 EnableWindow(GetDlgItem(hDlg, chx2), FALSE); 1381 EnableWindow(GetDlgItem(hDlg, ico3), FALSE); 1382 } 1383 } 1384 1385 /* nCopies */ 1386 { 1387 INT copies; 1388 if (lppd->hDevMode == 0) 1389 copies = lppd->nCopies; 1390 else 1391 copies = lpdm->u1.s1.dmCopies; 1392 if(copies == 0) copies = 1; 1393 else if(copies < 0) copies = MAX_COPIES; 1394 SetDlgItemInt(hDlg, edt3, copies, FALSE); 1395 } 1396 1397 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { 1398 /* if printer doesn't support it: no nCopies */ 1399 if (!(lpdm->dmFields & DM_COPIES)) { 1400 EnableWindow(GetDlgItem(hDlg, edt3), FALSE); 1401 EnableWindow(GetDlgItem(hDlg, stc5), FALSE); 1402 } 1403 } 1404 1405 /* print to file */ 1406 CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); 1407 if (lppd->Flags & PD_DISABLEPRINTTOFILE) 1408 EnableWindow(GetDlgItem(hDlg, chx1), FALSE); 1409 if (lppd->Flags & PD_HIDEPRINTTOFILE) 1410 ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); 1411 1412 } else { /* PD_PRINTSETUP */ 1413 BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT); 1414 1415 PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, 1416 PrintStructures->lpPrinterInfo->pPrinterName, 1417 PrintStructures->lpPrinterInfo->pPortName, 1418 lpdm); 1419 PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, 1420 PrintStructures->lpPrinterInfo->pPrinterName, 1421 PrintStructures->lpPrinterInfo->pPortName, 1422 lpdm); 1423 CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); 1424 SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1425 (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : 1426 PrintStructures->hLandscapeIcon)); 1427 1428 } 1429 1430 /* help button */ 1431 if ((lppd->Flags & PD_SHOWHELP)==0) { 1432 /* hide if PD_SHOWHELP not specified */ 1433 ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); 1434 } 1435 return TRUE; 1436 } 1437 1438 /*********************************************************************** 1439 * check_printer_setup [internal] 1440 */ 1441 static LRESULT check_printer_setup(HWND hDlg) 1442 { 1443 DWORD needed,num; 1444 WCHAR resourcestr[256],resultstr[256]; 1445 1446 EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); 1447 if(needed == 0) 1448 { 1449 EnumPrintersW(PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &num); 1450 } 1451 if(needed > 0) 1452 return TRUE; 1453 else 1454 { 1455 LoadStringW(COMDLG32_hInstance, PD32_NO_DEVICES,resultstr, 255); 1456 LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,resourcestr, 255); 1457 MessageBoxW(hDlg, resultstr, resourcestr,MB_OK | MB_ICONWARNING); 1458 return FALSE; 1459 } 1460 } 1461 1462 /*********************************************************************** 1463 * PRINTDLG_WMInitDialog [internal] 1464 */ 1465 static LRESULT PRINTDLG_WMInitDialog(HWND hDlg, 1466 PRINT_PTRA* PrintStructures) 1467 { 1468 LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; 1469 DEVNAMES *pdn; 1470 DEVMODEA *pdm; 1471 char *name = NULL; 1472 UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; 1473 1474 /* load Collate ICONs */ 1475 /* We load these with LoadImage because they are not a standard 1476 size and we don't want them rescaled */ 1477 PrintStructures->hCollateIcon = 1478 LoadImageA(COMDLG32_hInstance, "PD32_COLLATE", IMAGE_ICON, 0, 0, 0); 1479 PrintStructures->hNoCollateIcon = 1480 LoadImageA(COMDLG32_hInstance, "PD32_NOCOLLATE", IMAGE_ICON, 0, 0, 0); 1481 1482 /* These can be done with LoadIcon */ 1483 PrintStructures->hPortraitIcon = 1484 LoadIconA(COMDLG32_hInstance, "PD32_PORTRAIT"); 1485 PrintStructures->hLandscapeIcon = 1486 LoadIconA(COMDLG32_hInstance, "PD32_LANDSCAPE"); 1487 1488 /* display the collate/no_collate icon */ 1489 SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1490 (LPARAM)PrintStructures->hNoCollateIcon); 1491 1492 if(PrintStructures->hCollateIcon == 0 || 1493 PrintStructures->hNoCollateIcon == 0 || 1494 PrintStructures->hPortraitIcon == 0 || 1495 PrintStructures->hLandscapeIcon == 0) { 1496 ERR("no icon in resource file\n"); 1497 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 1498 EndDialog(hDlg, FALSE); 1499 } 1500 1501 /* 1502 * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message 1503 * must be registered and the Help button must be shown. 1504 */ 1505 if (lppd->Flags & PD_SHOWHELP) { 1506 if((PrintStructures->HelpMessageID = 1507 RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) { 1508 COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); 1509 return FALSE; 1510 } 1511 } else 1512 PrintStructures->HelpMessageID = 0; 1513 1514 if(!(lppd->Flags &PD_PRINTSETUP)) { 1515 PrintStructures->hwndUpDown = 1516 CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | 1517 UDS_NOTHOUSANDS | UDS_ARROWKEYS | 1518 UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, 1519 hDlg, UPDOWN_ID, COMDLG32_hInstance, 1520 GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); 1521 } 1522 1523 /* FIXME: I allow more freedom than either Win95 or WinNT, 1524 * which do not agree on what errors should be thrown or not 1525 * in case nToPage or nFromPage is out-of-range. 1526 */ 1527 if (lppd->nMaxPage < lppd->nMinPage) 1528 lppd->nMaxPage = lppd->nMinPage; 1529 if (lppd->nMinPage == lppd->nMaxPage) 1530 lppd->Flags |= PD_NOPAGENUMS; 1531 if (lppd->nToPage < lppd->nMinPage) 1532 lppd->nToPage = lppd->nMinPage; 1533 if (lppd->nToPage > lppd->nMaxPage) 1534 lppd->nToPage = lppd->nMaxPage; 1535 if (lppd->nFromPage < lppd->nMinPage) 1536 lppd->nFromPage = lppd->nMinPage; 1537 if (lppd->nFromPage > lppd->nMaxPage) 1538 lppd->nFromPage = lppd->nMaxPage; 1539 1540 /* if we have the combo box, fill it */ 1541 if (GetDlgItem(hDlg,comboID)) { 1542 /* Fill Combobox 1543 */ 1544 pdn = GlobalLock(lppd->hDevNames); 1545 pdm = GlobalLock(lppd->hDevMode); 1546 if(pdn) 1547 name = (char*)pdn + pdn->wDeviceOffset; 1548 else if(pdm) 1549 name = (char*)pdm->dmDeviceName; 1550 PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name); 1551 if(pdm) GlobalUnlock(lppd->hDevMode); 1552 if(pdn) GlobalUnlock(lppd->hDevNames); 1553 1554 /* Now find selected printer and update rest of dlg */ 1555 name = HeapAlloc(GetProcessHeap(),0,256); 1556 if (GetDlgItemTextA(hDlg, comboID, name, 255)) 1557 PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); 1558 HeapFree(GetProcessHeap(),0,name); 1559 } else { 1560 /* else use default printer */ 1561 char name[200]; 1562 DWORD dwBufLen = sizeof(name); 1563 BOOL ret = GetDefaultPrinterA(name, &dwBufLen); 1564 1565 if (ret) 1566 PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); 1567 else 1568 FIXME("No default printer found, expect problems!\n"); 1569 } 1570 return TRUE; 1571 } 1572 1573 static LRESULT PRINTDLG_WMInitDialogW(HWND hDlg, 1574 PRINT_PTRW* PrintStructures) 1575 { 1576 LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; 1577 DEVNAMES *pdn; 1578 DEVMODEW *pdm; 1579 WCHAR *name = NULL; 1580 UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; 1581 1582 /* load Collate ICONs */ 1583 /* We load these with LoadImage because they are not a standard 1584 size and we don't want them rescaled */ 1585 PrintStructures->hCollateIcon = 1586 LoadImageW(COMDLG32_hInstance, pd32_collateW, IMAGE_ICON, 0, 0, 0); 1587 PrintStructures->hNoCollateIcon = 1588 LoadImageW(COMDLG32_hInstance, pd32_nocollateW, IMAGE_ICON, 0, 0, 0); 1589 1590 /* These can be done with LoadIcon */ 1591 PrintStructures->hPortraitIcon = 1592 LoadIconW(COMDLG32_hInstance, pd32_portraitW); 1593 PrintStructures->hLandscapeIcon = 1594 LoadIconW(COMDLG32_hInstance, pd32_landscapeW); 1595 1596 /* display the collate/no_collate icon */ 1597 SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1598 (LPARAM)PrintStructures->hNoCollateIcon); 1599 1600 if(PrintStructures->hCollateIcon == 0 || 1601 PrintStructures->hNoCollateIcon == 0 || 1602 PrintStructures->hPortraitIcon == 0 || 1603 PrintStructures->hLandscapeIcon == 0) { 1604 ERR("no icon in resource file\n"); 1605 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 1606 EndDialog(hDlg, FALSE); 1607 } 1608 1609 /* 1610 * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message 1611 * must be registered and the Help button must be shown. 1612 */ 1613 if (lppd->Flags & PD_SHOWHELP) { 1614 if((PrintStructures->HelpMessageID = 1615 RegisterWindowMessageW(HELPMSGSTRINGW)) == 0) { 1616 COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); 1617 return FALSE; 1618 } 1619 } else 1620 PrintStructures->HelpMessageID = 0; 1621 1622 if(!(lppd->Flags &PD_PRINTSETUP)) { 1623 PrintStructures->hwndUpDown = 1624 CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | 1625 UDS_NOTHOUSANDS | UDS_ARROWKEYS | 1626 UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, 1627 hDlg, UPDOWN_ID, COMDLG32_hInstance, 1628 GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); 1629 } 1630 1631 /* FIXME: I allow more freedom than either Win95 or WinNT, 1632 * which do not agree to what errors should be thrown or not 1633 * in case nToPage or nFromPage is out-of-range. 1634 */ 1635 if (lppd->nMaxPage < lppd->nMinPage) 1636 lppd->nMaxPage = lppd->nMinPage; 1637 if (lppd->nMinPage == lppd->nMaxPage) 1638 lppd->Flags |= PD_NOPAGENUMS; 1639 if (lppd->nToPage < lppd->nMinPage) 1640 lppd->nToPage = lppd->nMinPage; 1641 if (lppd->nToPage > lppd->nMaxPage) 1642 lppd->nToPage = lppd->nMaxPage; 1643 if (lppd->nFromPage < lppd->nMinPage) 1644 lppd->nFromPage = lppd->nMinPage; 1645 if (lppd->nFromPage > lppd->nMaxPage) 1646 lppd->nFromPage = lppd->nMaxPage; 1647 1648 /* if we have the combo box, fill it */ 1649 if (GetDlgItem(hDlg,comboID)) { 1650 /* Fill Combobox 1651 */ 1652 pdn = GlobalLock(lppd->hDevNames); 1653 pdm = GlobalLock(lppd->hDevMode); 1654 if(pdn) 1655 name = (WCHAR*)pdn + pdn->wDeviceOffset; 1656 else if(pdm) 1657 name = pdm->dmDeviceName; 1658 PRINTDLG_SetUpPrinterListComboW(hDlg, comboID, name); 1659 if(pdm) GlobalUnlock(lppd->hDevMode); 1660 if(pdn) GlobalUnlock(lppd->hDevNames); 1661 1662 /* Now find selected printer and update rest of dlg */ 1663 /* ansi is ok here */ 1664 name = HeapAlloc(GetProcessHeap(),0,256*sizeof(WCHAR)); 1665 if (GetDlgItemTextW(hDlg, comboID, name, 255)) 1666 PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); 1667 HeapFree(GetProcessHeap(),0,name); 1668 } else { 1669 /* else use default printer */ 1670 WCHAR name[200]; 1671 DWORD dwBufLen = sizeof(name) / sizeof(WCHAR); 1672 BOOL ret = GetDefaultPrinterW(name, &dwBufLen); 1673 1674 if (ret) 1675 PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); 1676 else 1677 FIXME("No default printer found, expect problems!\n"); 1678 } 1679 return TRUE; 1680 } 1681 1682 /*********************************************************************** 1683 * PRINTDLG_WMCommand [internal] 1684 */ 1685 static LRESULT PRINTDLG_WMCommandA(HWND hDlg, WPARAM wParam, 1686 PRINT_PTRA* PrintStructures) 1687 { 1688 LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; 1689 UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; 1690 LPDEVMODEA lpdm = PrintStructures->lpDevMode; 1691 1692 switch (LOWORD(wParam)) { 1693 case IDOK: 1694 TRACE(" OK button was hit\n"); 1695 if (!PRINTDLG_UpdatePrintDlgA(hDlg, PrintStructures)) { 1696 FIXME("Update printdlg was not successful!\n"); 1697 return(FALSE); 1698 } 1699 EndDialog(hDlg, TRUE); 1700 return(TRUE); 1701 1702 case IDCANCEL: 1703 TRACE(" CANCEL button was hit\n"); 1704 EndDialog(hDlg, FALSE); 1705 return(FALSE); 1706 1707 case pshHelp: 1708 TRACE(" HELP button was hit\n"); 1709 SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID, 1710 (WPARAM) hDlg, (LPARAM) lppd); 1711 break; 1712 1713 case chx2: /* collate pages checkbox */ 1714 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) 1715 SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1716 (LPARAM)PrintStructures->hCollateIcon); 1717 else 1718 SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1719 (LPARAM)PrintStructures->hNoCollateIcon); 1720 break; 1721 case edt1: /* from page nr editbox */ 1722 case edt2: /* to page nr editbox */ 1723 if (HIWORD(wParam)==EN_CHANGE) { 1724 WORD nToPage; 1725 WORD nFromPage; 1726 nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); 1727 nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); 1728 if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) 1729 CheckRadioButton(hDlg, rad1, rad3, rad3); 1730 } 1731 break; 1732 1733 case edt3: 1734 if(HIWORD(wParam) == EN_CHANGE) { 1735 INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); 1736 if(copies <= 1) 1737 EnableWindow(GetDlgItem(hDlg, chx2), FALSE); 1738 else 1739 EnableWindow(GetDlgItem(hDlg, chx2), TRUE); 1740 } 1741 break; 1742 1743 case psh2: /* Properties button */ 1744 { 1745 HANDLE hPrinter; 1746 char PrinterName[256]; 1747 1748 GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255); 1749 if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) { 1750 FIXME(" Call to OpenPrinter did not succeed!\n"); 1751 break; 1752 } 1753 DocumentPropertiesA(hDlg, hPrinter, PrinterName, 1754 PrintStructures->lpDevMode, 1755 PrintStructures->lpDevMode, 1756 DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); 1757 ClosePrinter(hPrinter); 1758 break; 1759 } 1760 1761 case rad1: /* Paperorientation */ 1762 if (lppd->Flags & PD_PRINTSETUP) 1763 { 1764 lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; 1765 SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1766 (LPARAM)(PrintStructures->hPortraitIcon)); 1767 } 1768 break; 1769 1770 case rad2: /* Paperorientation */ 1771 if (lppd->Flags & PD_PRINTSETUP) 1772 { 1773 lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; 1774 SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1775 (LPARAM)(PrintStructures->hLandscapeIcon)); 1776 } 1777 break; 1778 1779 case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT16 */ 1780 if (PrinterComboID != LOWORD(wParam)) { 1781 break; 1782 } 1783 /* FALLTHROUGH */ 1784 case cmb4: /* Printer combobox */ 1785 if (HIWORD(wParam)==CBN_SELCHANGE) { 1786 char *PrinterName; 1787 INT index = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETCURSEL, 0, 0); 1788 INT length = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXTLEN, index, 0); 1789 PrinterName = HeapAlloc(GetProcessHeap(),0,length+1); 1790 SendDlgItemMessageA(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName); 1791 PRINTDLG_ChangePrinterA(hDlg, PrinterName, PrintStructures); 1792 HeapFree(GetProcessHeap(),0,PrinterName); 1793 } 1794 break; 1795 1796 case cmb2: /* Papersize */ 1797 { 1798 DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0); 1799 if(Sel != CB_ERR) { 1800 lpdm->u1.s1.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2, 1801 CB_GETITEMDATA, 1802 Sel, 0); 1803 GetDlgItemTextA(hDlg, cmb2, (char *)lpdm->dmFormName, CCHFORMNAME); 1804 } 1805 } 1806 break; 1807 1808 case cmb3: /* Bin */ 1809 { 1810 DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0); 1811 if(Sel != CB_ERR) 1812 lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3, 1813 CB_GETITEMDATA, Sel, 1814 0); 1815 } 1816 break; 1817 } 1818 if(lppd->Flags & PD_PRINTSETUP) { 1819 switch (LOWORD(wParam)) { 1820 case rad1: /* orientation */ 1821 case rad2: 1822 if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { 1823 if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) { 1824 lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; 1825 SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, 1826 (LPARAM)PrintStructures->hPortraitIcon); 1827 SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1828 (LPARAM)PrintStructures->hPortraitIcon); 1829 } 1830 } else { 1831 if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) { 1832 lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; 1833 SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, 1834 (LPARAM)PrintStructures->hLandscapeIcon); 1835 SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1836 (LPARAM)PrintStructures->hLandscapeIcon); 1837 } 1838 } 1839 break; 1840 } 1841 } 1842 return FALSE; 1843 } 1844 1845 static LRESULT PRINTDLG_WMCommandW(HWND hDlg, WPARAM wParam, 1846 PRINT_PTRW* PrintStructures) 1847 { 1848 LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; 1849 UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; 1850 LPDEVMODEW lpdm = PrintStructures->lpDevMode; 1851 1852 switch (LOWORD(wParam)) { 1853 case IDOK: 1854 TRACE(" OK button was hit\n"); 1855 if (!PRINTDLG_UpdatePrintDlgW(hDlg, PrintStructures)) { 1856 FIXME("Update printdlg was not successful!\n"); 1857 return(FALSE); 1858 } 1859 EndDialog(hDlg, TRUE); 1860 return(TRUE); 1861 1862 case IDCANCEL: 1863 TRACE(" CANCEL button was hit\n"); 1864 EndDialog(hDlg, FALSE); 1865 return(FALSE); 1866 1867 case pshHelp: 1868 TRACE(" HELP button was hit\n"); 1869 SendMessageW(lppd->hwndOwner, PrintStructures->HelpMessageID, 1870 (WPARAM) hDlg, (LPARAM) lppd); 1871 break; 1872 1873 case chx2: /* collate pages checkbox */ 1874 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) 1875 SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1876 (LPARAM)PrintStructures->hCollateIcon); 1877 else 1878 SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON, 1879 (LPARAM)PrintStructures->hNoCollateIcon); 1880 break; 1881 case edt1: /* from page nr editbox */ 1882 case edt2: /* to page nr editbox */ 1883 if (HIWORD(wParam)==EN_CHANGE) { 1884 WORD nToPage; 1885 WORD nFromPage; 1886 nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); 1887 nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); 1888 if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) 1889 CheckRadioButton(hDlg, rad1, rad3, rad3); 1890 } 1891 break; 1892 1893 case edt3: 1894 if(HIWORD(wParam) == EN_CHANGE) { 1895 INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); 1896 if(copies <= 1) 1897 EnableWindow(GetDlgItem(hDlg, chx2), FALSE); 1898 else 1899 EnableWindow(GetDlgItem(hDlg, chx2), TRUE); 1900 } 1901 break; 1902 1903 case psh2: /* Properties button */ 1904 { 1905 HANDLE hPrinter; 1906 WCHAR PrinterName[256]; 1907 1908 if (!GetDlgItemTextW(hDlg, PrinterComboID, PrinterName, 255)) break; 1909 if (!OpenPrinterW(PrinterName, &hPrinter, NULL)) { 1910 FIXME(" Call to OpenPrinter did not succeed!\n"); 1911 break; 1912 } 1913 DocumentPropertiesW(hDlg, hPrinter, PrinterName, 1914 PrintStructures->lpDevMode, 1915 PrintStructures->lpDevMode, 1916 DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); 1917 ClosePrinter(hPrinter); 1918 break; 1919 } 1920 1921 case rad1: /* Paperorientation */ 1922 if (lppd->Flags & PD_PRINTSETUP) 1923 { 1924 lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; 1925 SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1926 (LPARAM)(PrintStructures->hPortraitIcon)); 1927 } 1928 break; 1929 1930 case rad2: /* Paperorientation */ 1931 if (lppd->Flags & PD_PRINTSETUP) 1932 { 1933 lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; 1934 SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1935 (LPARAM)(PrintStructures->hLandscapeIcon)); 1936 } 1937 break; 1938 1939 case cmb1: /* Printer Combobox in PRINT SETUP */ 1940 /* FALLTHROUGH */ 1941 case cmb4: /* Printer combobox */ 1942 if (HIWORD(wParam)==CBN_SELCHANGE) { 1943 WCHAR *PrinterName; 1944 INT index = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETCURSEL, 0, 0); 1945 INT length = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXTLEN, index, 0); 1946 1947 PrinterName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1)); 1948 SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName); 1949 PRINTDLG_ChangePrinterW(hDlg, PrinterName, PrintStructures); 1950 HeapFree(GetProcessHeap(),0,PrinterName); 1951 } 1952 break; 1953 1954 case cmb2: /* Papersize */ 1955 { 1956 DWORD Sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); 1957 if(Sel != CB_ERR) { 1958 lpdm->u1.s1.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2, 1959 CB_GETITEMDATA, 1960 Sel, 0); 1961 GetDlgItemTextW(hDlg, cmb2, lpdm->dmFormName, CCHFORMNAME); 1962 } 1963 } 1964 break; 1965 1966 case cmb3: /* Bin */ 1967 { 1968 DWORD Sel = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); 1969 if(Sel != CB_ERR) 1970 lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageW(hDlg, cmb3, 1971 CB_GETITEMDATA, Sel, 1972 0); 1973 } 1974 break; 1975 } 1976 if(lppd->Flags & PD_PRINTSETUP) { 1977 switch (LOWORD(wParam)) { 1978 case rad1: /* orientation */ 1979 case rad2: 1980 if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { 1981 if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) { 1982 lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT; 1983 SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, 1984 (LPARAM)PrintStructures->hPortraitIcon); 1985 SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1986 (LPARAM)PrintStructures->hPortraitIcon); 1987 } 1988 } else { 1989 if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) { 1990 lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE; 1991 SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON, 1992 (LPARAM)PrintStructures->hLandscapeIcon); 1993 SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON, 1994 (LPARAM)PrintStructures->hLandscapeIcon); 1995 } 1996 } 1997 break; 1998 } 1999 } 2000 return FALSE; 2001 } 2002 2003 /*********************************************************************** 2004 * PrintDlgProcA [internal] 2005 */ 2006 static INT_PTR CALLBACK PrintDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, 2007 LPARAM lParam) 2008 { 2009 PRINT_PTRA* PrintStructures; 2010 INT_PTR res = FALSE; 2011 2012 if (uMsg!=WM_INITDIALOG) { 2013 PrintStructures = GetPropW(hDlg, printdlg_prop); 2014 if (!PrintStructures) 2015 return FALSE; 2016 } else { 2017 PrintStructures = (PRINT_PTRA*) lParam; 2018 SetPropW(hDlg, printdlg_prop, PrintStructures); 2019 if(!check_printer_setup(hDlg)) 2020 { 2021 EndDialog(hDlg,FALSE); 2022 return FALSE; 2023 } 2024 res = PRINTDLG_WMInitDialog(hDlg, PrintStructures); 2025 2026 if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) 2027 res = PrintStructures->lpPrintDlg->lpfnPrintHook( 2028 hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg 2029 ); 2030 return res; 2031 } 2032 2033 if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { 2034 res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, 2035 lParam); 2036 if(res) return res; 2037 } 2038 2039 switch (uMsg) { 2040 case WM_COMMAND: 2041 return PRINTDLG_WMCommandA(hDlg, wParam, PrintStructures); 2042 2043 case WM_DESTROY: 2044 DestroyIcon(PrintStructures->hCollateIcon); 2045 DestroyIcon(PrintStructures->hNoCollateIcon); 2046 DestroyIcon(PrintStructures->hPortraitIcon); 2047 DestroyIcon(PrintStructures->hLandscapeIcon); 2048 if(PrintStructures->hwndUpDown) 2049 DestroyWindow(PrintStructures->hwndUpDown); 2050 return FALSE; 2051 } 2052 return res; 2053 } 2054 2055 static INT_PTR CALLBACK PrintDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, 2056 LPARAM lParam) 2057 { 2058 PRINT_PTRW* PrintStructures; 2059 INT_PTR res = FALSE; 2060 2061 if (uMsg!=WM_INITDIALOG) { 2062 PrintStructures = GetPropW(hDlg, printdlg_prop); 2063 if (!PrintStructures) 2064 return FALSE; 2065 } else { 2066 PrintStructures = (PRINT_PTRW*) lParam; 2067 SetPropW(hDlg, printdlg_prop, PrintStructures); 2068 if(!check_printer_setup(hDlg)) 2069 { 2070 EndDialog(hDlg,FALSE); 2071 return FALSE; 2072 } 2073 res = PRINTDLG_WMInitDialogW(hDlg, PrintStructures); 2074 2075 if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) 2076 res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg); 2077 return res; 2078 } 2079 2080 if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { 2081 res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, lParam); 2082 if(res) return res; 2083 } 2084 2085 switch (uMsg) { 2086 case WM_COMMAND: 2087 return PRINTDLG_WMCommandW(hDlg, wParam, PrintStructures); 2088 2089 case WM_DESTROY: 2090 DestroyIcon(PrintStructures->hCollateIcon); 2091 DestroyIcon(PrintStructures->hNoCollateIcon); 2092 DestroyIcon(PrintStructures->hPortraitIcon); 2093 DestroyIcon(PrintStructures->hLandscapeIcon); 2094 if(PrintStructures->hwndUpDown) 2095 DestroyWindow(PrintStructures->hwndUpDown); 2096 return FALSE; 2097 } 2098 return res; 2099 } 2100 2101 /************************************************************ 2102 * 2103 * PRINTDLG_GetDlgTemplate 2104 * 2105 */ 2106 static HGLOBAL PRINTDLG_GetDlgTemplateA(const PRINTDLGA *lppd) 2107 { 2108 HRSRC hResInfo; 2109 HGLOBAL hDlgTmpl; 2110 2111 if (lppd->Flags & PD_PRINTSETUP) { 2112 if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { 2113 hDlgTmpl = lppd->hSetupTemplate; 2114 } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { 2115 hResInfo = FindResourceA(lppd->hInstance, 2116 lppd->lpSetupTemplateName, (LPSTR)RT_DIALOG); 2117 hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); 2118 } else { 2119 hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP", 2120 (LPSTR)RT_DIALOG); 2121 hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); 2122 } 2123 } else { 2124 if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { 2125 hDlgTmpl = lppd->hPrintTemplate; 2126 } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { 2127 hResInfo = FindResourceA(lppd->hInstance, 2128 lppd->lpPrintTemplateName, 2129 (LPSTR)RT_DIALOG); 2130 hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); 2131 } else { 2132 hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32", 2133 (LPSTR)RT_DIALOG); 2134 hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); 2135 } 2136 } 2137 return hDlgTmpl; 2138 } 2139 2140 static HGLOBAL PRINTDLG_GetDlgTemplateW(const PRINTDLGW *lppd) 2141 { 2142 HRSRC hResInfo; 2143 HGLOBAL hDlgTmpl; 2144 static const WCHAR xpsetup[] = { 'P','R','I','N','T','3','2','_','S','E','T','U','P',0}; 2145 static const WCHAR xprint[] = { 'P','R','I','N','T','3','2',0}; 2146 2147 if (lppd->Flags & PD_PRINTSETUP) { 2148 if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { 2149 hDlgTmpl = lppd->hSetupTemplate; 2150 } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { 2151 hResInfo = FindResourceW(lppd->hInstance, 2152 lppd->lpSetupTemplateName, (LPWSTR)RT_DIALOG); 2153 hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); 2154 } else { 2155 hResInfo = FindResourceW(COMDLG32_hInstance, xpsetup, (LPWSTR)RT_DIALOG); 2156 hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); 2157 } 2158 } else { 2159 if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { 2160 hDlgTmpl = lppd->hPrintTemplate; 2161 } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { 2162 hResInfo = FindResourceW(lppd->hInstance, 2163 lppd->lpPrintTemplateName, 2164 (LPWSTR)RT_DIALOG); 2165 hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); 2166 } else { 2167 hResInfo = FindResourceW(COMDLG32_hInstance, xprint, (LPWSTR)RT_DIALOG); 2168 hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); 2169 } 2170 } 2171 return hDlgTmpl; 2172 } 2173 2174 /*********************************************************************** 2175 * 2176 * PRINTDLG_CreateDC 2177 * 2178 */ 2179 static BOOL PRINTDLG_CreateDCA(LPPRINTDLGA lppd) 2180 { 2181 DEVNAMES *pdn = GlobalLock(lppd->hDevNames); 2182 DEVMODEA *pdm = GlobalLock(lppd->hDevMode); 2183 2184 if(lppd->Flags & PD_RETURNDC) { 2185 lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset, 2186 (char*)pdn + pdn->wDeviceOffset, 2187 (char*)pdn + pdn->wOutputOffset, 2188 pdm ); 2189 } else if(lppd->Flags & PD_RETURNIC) { 2190 lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset, 2191 (char*)pdn + pdn->wDeviceOffset, 2192 (char*)pdn + pdn->wOutputOffset, 2193 pdm ); 2194 } 2195 GlobalUnlock(lppd->hDevNames); 2196 GlobalUnlock(lppd->hDevMode); 2197 return lppd->hDC != NULL; 2198 } 2199 2200 static BOOL PRINTDLG_CreateDCW(LPPRINTDLGW lppd) 2201 { 2202 DEVNAMES *pdn = GlobalLock(lppd->hDevNames); 2203 DEVMODEW *pdm = GlobalLock(lppd->hDevMode); 2204 2205 if(lppd->Flags & PD_RETURNDC) { 2206 lppd->hDC = CreateDCW((WCHAR*)pdn + pdn->wDriverOffset, 2207 (WCHAR*)pdn + pdn->wDeviceOffset, 2208 (WCHAR*)pdn + pdn->wOutputOffset, 2209 pdm ); 2210 } else if(lppd->Flags & PD_RETURNIC) { 2211 lppd->hDC = CreateICW((WCHAR*)pdn + pdn->wDriverOffset, 2212 (WCHAR*)pdn + pdn->wDeviceOffset, 2213 (WCHAR*)pdn + pdn->wOutputOffset, 2214 pdm ); 2215 } 2216 GlobalUnlock(lppd->hDevNames); 2217 GlobalUnlock(lppd->hDevMode); 2218 return lppd->hDC != NULL; 2219 } 2220 2221 /*********************************************************************** 2222 * PrintDlgA (COMDLG32.@) 2223 * 2224 * Displays the PRINT dialog box, which enables the user to specify 2225 * specific properties of the print job. 2226 * 2227 * PARAMS 2228 * lppd [IO] ptr to PRINTDLG32 struct 2229 * 2230 * RETURNS 2231 * nonzero if the user pressed the OK button 2232 * zero if the user cancelled the window or an error occurred 2233 * 2234 * BUGS 2235 * PrintDlg: 2236 * * The Collate Icons do not display, even though they are in the code. 2237 * * The Properties Button(s) should call DocumentPropertiesA(). 2238 */ 2239 2240 BOOL WINAPI PrintDlgA(LPPRINTDLGA lppd) 2241 { 2242 BOOL bRet = FALSE; 2243 LPVOID ptr; 2244 HINSTANCE hInst; 2245 2246 if (!lppd) 2247 { 2248 COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION); 2249 return FALSE; 2250 } 2251 2252 if(TRACE_ON(commdlg)) { 2253 char flagstr[1000] = ""; 2254 const struct pd_flags *pflag = pd_flags; 2255 for( ; pflag->name; pflag++) { 2256 if(lppd->Flags & pflag->flag) 2257 strcat(flagstr, pflag->name); 2258 } 2259 TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" 2260 "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" 2261 "flags %08x (%s)\n", 2262 lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, 2263 lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, 2264 lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); 2265 } 2266 2267 if(lppd->lStructSize != sizeof(PRINTDLGA)) { 2268 WARN("structure size failure!!!\n"); 2269 COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); 2270 return FALSE; 2271 } 2272 2273 if(lppd->Flags & PD_RETURNDEFAULT) { 2274 PRINTER_INFO_2A *pbuf; 2275 DRIVER_INFO_3A *dbuf; 2276 HANDLE hprn; 2277 DWORD needed; 2278 2279 if(lppd->hDevMode || lppd->hDevNames) { 2280 WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); 2281 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 2282 return FALSE; 2283 } 2284 if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { 2285 WARN("Can't find default printer\n"); 2286 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); 2287 return FALSE; 2288 } 2289 2290 GetPrinterA(hprn, 2, NULL, 0, &needed); 2291 pbuf = HeapAlloc(GetProcessHeap(), 0, needed); 2292 GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); 2293 2294 GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); 2295 dbuf = HeapAlloc(GetProcessHeap(),0,needed); 2296 if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { 2297 ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n", 2298 GetLastError(),pbuf->pPrinterName); 2299 HeapFree(GetProcessHeap(), 0, dbuf); 2300 HeapFree(GetProcessHeap(), 0, pbuf); 2301 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 2302 return FALSE; 2303 } 2304 ClosePrinter(hprn); 2305 2306 PRINTDLG_CreateDevNames(&(lppd->hDevNames), 2307 dbuf->pDriverPath, 2308 pbuf->pPrinterName, 2309 pbuf->pPortName); 2310 lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + 2311 pbuf->pDevMode->dmDriverExtra); 2312 ptr = GlobalLock(lppd->hDevMode); 2313 memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + 2314 pbuf->pDevMode->dmDriverExtra); 2315 GlobalUnlock(lppd->hDevMode); 2316 HeapFree(GetProcessHeap(), 0, pbuf); 2317 HeapFree(GetProcessHeap(), 0, dbuf); 2318 bRet = TRUE; 2319 } else { 2320 HGLOBAL hDlgTmpl; 2321 PRINT_PTRA *PrintStructures; 2322 2323 /* load Dialog resources, 2324 * depending on Flags indicates Print32 or Print32_setup dialog 2325 */ 2326 hDlgTmpl = PRINTDLG_GetDlgTemplateA(lppd); 2327 if (!hDlgTmpl) { 2328 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 2329 return FALSE; 2330 } 2331 ptr = LockResource( hDlgTmpl ); 2332 if (!ptr) { 2333 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 2334 return FALSE; 2335 } 2336 2337 PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2338 sizeof(PRINT_PTRA)); 2339 PrintStructures->lpPrintDlg = lppd; 2340 2341 /* and create & process the dialog . 2342 * -1 is failure, 0 is broken hwnd, everything else is ok. 2343 */ 2344 hInst = COMDLG32_hInstance; 2345 if (lppd->Flags & (PD_ENABLESETUPTEMPLATE | PD_ENABLEPRINTTEMPLATE)) hInst = lppd->hInstance; 2346 bRet = (0<DialogBoxIndirectParamA(hInst, ptr, lppd->hwndOwner, 2347 PrintDlgProcA, 2348 (LPARAM)PrintStructures)); 2349 2350 if(bRet) { 2351 DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn; 2352 PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo; 2353 DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo; 2354 2355 if (lppd->hDevMode == 0) { 2356 TRACE(" No hDevMode yet... Need to create my own\n"); 2357 lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, 2358 lpdm->dmSize + lpdm->dmDriverExtra); 2359 } else { 2360 lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, 2361 lpdm->dmSize + lpdm->dmDriverExtra, 2362 GMEM_MOVEABLE); 2363 } 2364 lpdmReturn = GlobalLock(lppd->hDevMode); 2365 memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); 2366 2367 PRINTDLG_CreateDevNames(&(lppd->hDevNames), 2368 di->pDriverPath, 2369 pi->pPrinterName, 2370 pi->pPortName 2371 ); 2372 GlobalUnlock(lppd->hDevMode); 2373 } 2374 HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); 2375 HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); 2376 HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); 2377 HeapFree(GetProcessHeap(), 0, PrintStructures); 2378 } 2379 if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) 2380 bRet = PRINTDLG_CreateDCA(lppd); 2381 2382 TRACE("exit! (%d)\n", bRet); 2383 return bRet; 2384 } 2385 2386 /*********************************************************************** 2387 * PrintDlgW (COMDLG32.@) 2388 * 2389 * See PrintDlgA. 2390 */ 2391 BOOL WINAPI PrintDlgW(LPPRINTDLGW lppd) 2392 { 2393 BOOL bRet = FALSE; 2394 LPVOID ptr; 2395 HINSTANCE hInst; 2396 2397 if (!lppd) 2398 { 2399 COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION); 2400 return FALSE; 2401 } 2402 2403 if(TRACE_ON(commdlg)) { 2404 char flagstr[1000] = ""; 2405 const struct pd_flags *pflag = pd_flags; 2406 for( ; pflag->name; pflag++) { 2407 if(lppd->Flags & pflag->flag) 2408 strcat(flagstr, pflag->name); 2409 } 2410 TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" 2411 "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" 2412 "flags %08x (%s)\n", 2413 lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, 2414 lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, 2415 lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); 2416 } 2417 2418 if(lppd->lStructSize != sizeof(PRINTDLGW)) { 2419 WARN("structure size failure!!!\n"); 2420 COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); 2421 return FALSE; 2422 } 2423 2424 if(lppd->Flags & PD_RETURNDEFAULT) { 2425 PRINTER_INFO_2W *pbuf; 2426 DRIVER_INFO_3W *dbuf; 2427 HANDLE hprn; 2428 DWORD needed; 2429 2430 if(lppd->hDevMode || lppd->hDevNames) { 2431 WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); 2432 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 2433 return FALSE; 2434 } 2435 if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { 2436 WARN("Can't find default printer\n"); 2437 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); 2438 return FALSE; 2439 } 2440 2441 GetPrinterW(hprn, 2, NULL, 0, &needed); 2442 pbuf = HeapAlloc(GetProcessHeap(), 0, needed); 2443 GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed); 2444 2445 GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); 2446 dbuf = HeapAlloc(GetProcessHeap(),0,needed); 2447 if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { 2448 ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n", 2449 GetLastError(),debugstr_w(pbuf->pPrinterName)); 2450 HeapFree(GetProcessHeap(), 0, dbuf); 2451 HeapFree(GetProcessHeap(), 0, pbuf); 2452 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 2453 return FALSE; 2454 } 2455 ClosePrinter(hprn); 2456 2457 PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), 2458 dbuf->pDriverPath, 2459 pbuf->pPrinterName, 2460 pbuf->pPortName); 2461 lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + 2462 pbuf->pDevMode->dmDriverExtra); 2463 ptr = GlobalLock(lppd->hDevMode); 2464 memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + 2465 pbuf->pDevMode->dmDriverExtra); 2466 GlobalUnlock(lppd->hDevMode); 2467 HeapFree(GetProcessHeap(), 0, pbuf); 2468 HeapFree(GetProcessHeap(), 0, dbuf); 2469 bRet = TRUE; 2470 } else { 2471 HGLOBAL hDlgTmpl; 2472 PRINT_PTRW *PrintStructures; 2473 2474 /* load Dialog resources, 2475 * depending on Flags indicates Print32 or Print32_setup dialog 2476 */ 2477 hDlgTmpl = PRINTDLG_GetDlgTemplateW(lppd); 2478 if (!hDlgTmpl) { 2479 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 2480 return FALSE; 2481 } 2482 ptr = LockResource( hDlgTmpl ); 2483 if (!ptr) { 2484 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); 2485 return FALSE; 2486 } 2487 2488 PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2489 sizeof(PRINT_PTRW)); 2490 PrintStructures->lpPrintDlg = lppd; 2491 2492 /* and create & process the dialog . 2493 * -1 is failure, 0 is broken hwnd, everything else is ok. 2494 */ 2495 hInst = COMDLG32_hInstance; 2496 if (lppd->Flags & (PD_ENABLESETUPTEMPLATE | PD_ENABLEPRINTTEMPLATE)) hInst = lppd->hInstance; 2497 bRet = (0<DialogBoxIndirectParamW(hInst, ptr, lppd->hwndOwner, 2498 PrintDlgProcW, 2499 (LPARAM)PrintStructures)); 2500 2501 if(bRet) { 2502 DEVMODEW *lpdm = PrintStructures->lpDevMode, *lpdmReturn; 2503 PRINTER_INFO_2W *pi = PrintStructures->lpPrinterInfo; 2504 DRIVER_INFO_3W *di = PrintStructures->lpDriverInfo; 2505 2506 if (lppd->hDevMode == 0) { 2507 TRACE(" No hDevMode yet... Need to create my own\n"); 2508 lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, 2509 lpdm->dmSize + lpdm->dmDriverExtra); 2510 } else { 2511 WORD locks; 2512 if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) { 2513 WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); 2514 while(locks--) { 2515 GlobalUnlock(lppd->hDevMode); 2516 TRACE("Now got %d locks\n", locks); 2517 } 2518 } 2519 lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, 2520 lpdm->dmSize + lpdm->dmDriverExtra, 2521 GMEM_MOVEABLE); 2522 } 2523 lpdmReturn = GlobalLock(lppd->hDevMode); 2524 memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); 2525 2526 if (lppd->hDevNames != 0) { 2527 WORD locks; 2528 if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) { 2529 WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); 2530 while(locks--) 2531 GlobalUnlock(lppd->hDevNames); 2532 } 2533 } 2534 PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), 2535 di->pDriverPath, 2536 pi->pPrinterName, 2537 pi->pPortName 2538 ); 2539 GlobalUnlock(lppd->hDevMode); 2540 } 2541 HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); 2542 HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); 2543 HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); 2544 HeapFree(GetProcessHeap(), 0, PrintStructures); 2545 } 2546 if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) 2547 bRet = PRINTDLG_CreateDCW(lppd); 2548 2549 TRACE("exit! (%d)\n", bRet); 2550 return bRet; 2551 } 2552 2553 /*********************************************************************** 2554 * 2555 * PageSetupDlg 2556 * rad1 - portrait 2557 * rad2 - landscape 2558 * cmb1 - printer select (not in standard dialog template) 2559 * cmb2 - paper size 2560 * cmb3 - source (tray?) 2561 * edt4 - border left 2562 * edt5 - border top 2563 * edt6 - border right 2564 * edt7 - border bottom 2565 * psh3 - "Printer..." 2566 */ 2567 2568 typedef struct 2569 { 2570 BOOL unicode; 2571 union 2572 { 2573 LPPAGESETUPDLGA dlga; 2574 LPPAGESETUPDLGW dlgw; 2575 } u; 2576 HWND hDlg; /* Page Setup dialog handle */ 2577 RECT rtDrawRect; /* Drawing rect for page */ 2578 } pagesetup_data; 2579 2580 static inline DWORD pagesetup_get_flags(const pagesetup_data *data) 2581 { 2582 return data->u.dlgw->Flags; 2583 } 2584 2585 static inline BOOL is_metric(const pagesetup_data *data) 2586 { 2587 return pagesetup_get_flags(data) & PSD_INHUNDREDTHSOFMILLIMETERS; 2588 } 2589 2590 static inline LONG tenths_mm_to_size(const pagesetup_data *data, LONG size) 2591 { 2592 if (is_metric(data)) 2593 return 10 * size; 2594 else 2595 return 10 * size * 100 / 254; 2596 } 2597 2598 static inline LONG thousandths_inch_to_size(const pagesetup_data *data, LONG size) 2599 { 2600 if (is_metric(data)) 2601 return size * 254 / 100; 2602 else 2603 return size; 2604 } 2605 2606 static WCHAR get_decimal_sep(void) 2607 { 2608 static WCHAR sep; 2609 2610 if(!sep) 2611 { 2612 WCHAR buf[] = {'.', 0}; 2613 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buf, sizeof(buf) / sizeof(buf[0])); 2614 sep = buf[0]; 2615 } 2616 return sep; 2617 } 2618 2619 static void size2str(const pagesetup_data *data, DWORD size, LPWSTR strout) 2620 { 2621 WCHAR integer_fmt[] = {'%','d',0}; 2622 WCHAR hundredths_fmt[] = {'%','d','%','c','%','0','2','d',0}; 2623 WCHAR thousandths_fmt[] = {'%','d','%','c','%','0','3','d',0}; 2624 2625 /* FIXME use LOCALE_SDECIMAL when the edit parsing code can cope */ 2626 2627 if (is_metric(data)) 2628 { 2629 if(size % 100) 2630 wsprintfW(strout, hundredths_fmt, size / 100, get_decimal_sep(), size % 100); 2631 else 2632 wsprintfW(strout, integer_fmt, size / 100); 2633 } 2634 else 2635 { 2636 if(size % 1000) 2637 wsprintfW(strout, thousandths_fmt, size / 1000, get_decimal_sep(), size % 1000); 2638 else 2639 wsprintfW(strout, integer_fmt, size / 1000); 2640 2641 } 2642 } 2643 2644 static inline BOOL is_default_metric(void) 2645 { 2646 DWORD system; 2647 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, 2648 (LPWSTR)&system, sizeof(system)); 2649 return system == 0; 2650 } 2651 2652 /********************************************** 2653 * rotate_rect 2654 * Cyclically permute the four members of rc 2655 * If sense is TRUE l -> t -> r -> b 2656 * otherwise l <- t <- r <- b 2657 */ 2658 static inline void rotate_rect(RECT *rc, BOOL sense) 2659 { 2660 INT tmp; 2661 if(sense) 2662 { 2663 tmp = rc->bottom; 2664 rc->bottom = rc->right; 2665 rc->right = rc->top; 2666 rc->top = rc->left; 2667 rc->left = tmp; 2668 } 2669 else 2670 { 2671 tmp = rc->left; 2672 rc->left = rc->top; 2673 rc->top = rc->right; 2674 rc->right = rc->bottom; 2675 rc->bottom = tmp; 2676 } 2677 } 2678 2679 static void pagesetup_set_orientation(pagesetup_data *data, WORD orient) 2680 { 2681 DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); 2682 2683 assert(orient == DMORIENT_PORTRAIT || orient == DMORIENT_LANDSCAPE); 2684 2685 if(data->unicode) 2686 dm->u1.s1.dmOrientation = orient; 2687 else 2688 { 2689 DEVMODEA *dmA = (DEVMODEA *)dm; 2690 dmA->u1.s1.dmOrientation = orient; 2691 } 2692 GlobalUnlock(data->u.dlgw->hDevMode); 2693 } 2694 2695 static WORD pagesetup_get_orientation(const pagesetup_data *data) 2696 { 2697 DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); 2698 WORD orient; 2699 2700 if(data->unicode) 2701 orient = dm->u1.s1.dmOrientation; 2702 else 2703 { 2704 DEVMODEA *dmA = (DEVMODEA *)dm; 2705 orient = dmA->u1.s1.dmOrientation; 2706 } 2707 GlobalUnlock(data->u.dlgw->hDevMode); 2708 return orient; 2709 } 2710 2711 static void pagesetup_set_papersize(pagesetup_data *data, WORD paper) 2712 { 2713 DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); 2714 2715 if(data->unicode) 2716 dm->u1.s1.dmPaperSize = paper; 2717 else 2718 { 2719 DEVMODEA *dmA = (DEVMODEA *)dm; 2720 dmA->u1.s1.dmPaperSize = paper; 2721 } 2722 GlobalUnlock(data->u.dlgw->hDevMode); 2723 } 2724 2725 static WORD pagesetup_get_papersize(const pagesetup_data *data) 2726 { 2727 DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); 2728 WORD paper; 2729 2730 if(data->unicode) 2731 paper = dm->u1.s1.dmPaperSize; 2732 else 2733 { 2734 DEVMODEA *dmA = (DEVMODEA *)dm; 2735 paper = dmA->u1.s1.dmPaperSize; 2736 } 2737 GlobalUnlock(data->u.dlgw->hDevMode); 2738 return paper; 2739 } 2740 2741 static void pagesetup_set_defaultsource(pagesetup_data *data, WORD source) 2742 { 2743 DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); 2744 2745 if(data->unicode) 2746 dm->u1.s1.dmDefaultSource = source; 2747 else 2748 { 2749 DEVMODEA *dmA = (DEVMODEA *)dm; 2750 dmA->u1.s1.dmDefaultSource = source; 2751 } 2752 GlobalUnlock(data->u.dlgw->hDevMode); 2753 } 2754 2755 typedef enum 2756 { 2757 devnames_driver_name, 2758 devnames_device_name, 2759 devnames_output_name 2760 } devnames_name; 2761 2762 2763 static inline WORD get_devname_offset(const DEVNAMES *dn, devnames_name which) 2764 { 2765 switch(which) 2766 { 2767 case devnames_driver_name: return dn->wDriverOffset; 2768 case devnames_device_name: return dn->wDeviceOffset; 2769 case devnames_output_name: return dn->wOutputOffset; 2770 } 2771 ERR("Shouldn't be here\n"); 2772 return 0; 2773 } 2774 2775 static WCHAR *pagesetup_get_a_devname(const pagesetup_data *data, devnames_name which) 2776 { 2777 DEVNAMES *dn; 2778 WCHAR *name; 2779 2780 dn = GlobalLock(data->u.dlgw->hDevNames); 2781 if(data->unicode) 2782 name = strdupW((WCHAR *)dn + get_devname_offset(dn, which)); 2783 else 2784 { 2785 int len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, NULL, 0); 2786 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 2787 MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, name, len); 2788 } 2789 GlobalUnlock(data->u.dlgw->hDevNames); 2790 return name; 2791 } 2792 2793 static WCHAR *pagesetup_get_drvname(const pagesetup_data *data) 2794 { 2795 return pagesetup_get_a_devname(data, devnames_driver_name); 2796 } 2797 2798 static WCHAR *pagesetup_get_devname(const pagesetup_data *data) 2799 { 2800 return pagesetup_get_a_devname(data, devnames_device_name); 2801 } 2802 2803 static WCHAR *pagesetup_get_portname(const pagesetup_data *data) 2804 { 2805 return pagesetup_get_a_devname(data, devnames_output_name); 2806 } 2807 2808 static void pagesetup_release_a_devname(const pagesetup_data *data, WCHAR *name) 2809 { 2810 HeapFree(GetProcessHeap(), 0, name); 2811 } 2812 2813 static void pagesetup_set_devnames(pagesetup_data *data, LPCWSTR drv, LPCWSTR devname, LPCWSTR port) 2814 { 2815 DEVNAMES *dn; 2816 WCHAR def[256]; 2817 DWORD len = sizeof(DEVNAMES), drv_len, dev_len, port_len; 2818 2819 if(data->unicode) 2820 { 2821 drv_len = (strlenW(drv) + 1) * sizeof(WCHAR); 2822 dev_len = (strlenW(devname) + 1) * sizeof(WCHAR); 2823 port_len = (strlenW(port) + 1) * sizeof(WCHAR); 2824 } 2825 else 2826 { 2827 drv_len = WideCharToMultiByte(CP_ACP, 0, drv, -1, NULL, 0, NULL, NULL); 2828 dev_len = WideCharToMultiByte(CP_ACP, 0, devname, -1, NULL, 0, NULL, NULL); 2829 port_len = WideCharToMultiByte(CP_ACP, 0, port, -1, NULL, 0, NULL, NULL); 2830 } 2831 len += drv_len + dev_len + port_len; 2832 2833 if(data->u.dlgw->hDevNames) 2834 data->u.dlgw->hDevNames = GlobalReAlloc(data->u.dlgw->hDevNames, len, GMEM_MOVEABLE); 2835 else 2836 data->u.dlgw->hDevNames = GlobalAlloc(GMEM_MOVEABLE, len); 2837 2838 dn = GlobalLock(data->u.dlgw->hDevNames); 2839 2840 if(data->unicode) 2841 { 2842 WCHAR *ptr = (WCHAR *)(dn + 1); 2843 len = sizeof(DEVNAMES) / sizeof(WCHAR); 2844 dn->wDriverOffset = len; 2845 strcpyW(ptr, drv); 2846 ptr += drv_len / sizeof(WCHAR); 2847 len += drv_len / sizeof(WCHAR); 2848 dn->wDeviceOffset = len; 2849 strcpyW(ptr, devname); 2850 ptr += dev_len / sizeof(WCHAR); 2851 len += dev_len / sizeof(WCHAR); 2852 dn->wOutputOffset = len; 2853 strcpyW(ptr, port); 2854 } 2855 else 2856 { 2857 char *ptr = (char *)(dn + 1); 2858 len = sizeof(DEVNAMES); 2859 dn->wDriverOffset = len; 2860 WideCharToMultiByte(CP_ACP, 0, drv, -1, ptr, drv_len, NULL, NULL); 2861 ptr += drv_len; 2862 len += drv_len; 2863 dn->wDeviceOffset = len; 2864 WideCharToMultiByte(CP_ACP, 0, devname, -1, ptr, dev_len, NULL, NULL); 2865 ptr += dev_len; 2866 len += dev_len; 2867 dn->wOutputOffset = len; 2868 WideCharToMultiByte(CP_ACP, 0, port, -1, ptr, port_len, NULL, NULL); 2869 } 2870 2871 dn->wDefault = 0; 2872 len = sizeof(def) / sizeof(def[0]); 2873 GetDefaultPrinterW(def, &len); 2874 if(!lstrcmpW(def, devname)) 2875 dn->wDefault = 1; 2876 2877 GlobalUnlock(data->u.dlgw->hDevNames); 2878 } 2879 2880 static DEVMODEW *pagesetup_get_devmode(const pagesetup_data *data) 2881 { 2882 DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode); 2883 DEVMODEW *ret; 2884 2885 if(data->unicode) 2886 { 2887 /* We make a copy even in the unicode case because the ptr 2888 may get passed back to us in pagesetup_set_devmode. */ 2889 ret = HeapAlloc(GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra); 2890 memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra); 2891 } 2892 else 2893 ret = GdiConvertToDevmodeW((DEVMODEA *)dm); 2894 2895 GlobalUnlock(data->u.dlgw->hDevMode); 2896 return ret; 2897 } 2898 2899 static void pagesetup_release_devmode(const pagesetup_data *data, DEVMODEW *dm) 2900 { 2901 HeapFree(GetProcessHeap(), 0, dm); 2902 } 2903 2904 static void pagesetup_set_devmode(pagesetup_data *data, DEVMODEW *dm) 2905 { 2906 DEVMODEA *dmA = NULL; 2907 void *src, *dst; 2908 DWORD size; 2909 2910 if(data->unicode) 2911 { 2912 size = dm->dmSize + dm->dmDriverExtra; 2913 src = dm; 2914 } 2915 else 2916 { 2917 dmA = convert_to_devmodeA(dm); 2918 size = dmA->dmSize + dmA->dmDriverExtra; 2919 src = dmA; 2920 } 2921 2922 if(data->u.dlgw->hDevMode) 2923 data->u.dlgw->hDevMode = GlobalReAlloc(data->u.dlgw->hDevMode, size, 2924 GMEM_MOVEABLE); 2925 else 2926 data->u.dlgw->hDevMode = GlobalAlloc(GMEM_MOVEABLE, size); 2927 2928 dst = GlobalLock(data->u.dlgw->hDevMode); 2929 memcpy(dst, src, size); 2930 GlobalUnlock(data->u.dlgw->hDevMode); 2931 HeapFree(GetProcessHeap(), 0, dmA); 2932 } 2933 2934 static inline POINT *pagesetup_get_papersize_pt(const pagesetup_data *data) 2935 { 2936 return &data->u.dlgw->ptPaperSize; 2937 } 2938 2939 static inline RECT *pagesetup_get_margin_rect(const pagesetup_data *data) 2940 { 2941 return &data->u.dlgw->rtMargin; 2942 } 2943 2944 typedef enum 2945 { 2946 page_setup_hook, 2947 page_paint_hook 2948 } hook_type; 2949 2950 static inline LPPAGESETUPHOOK pagesetup_get_hook(const pagesetup_data *data, hook_type which) 2951 { 2952 switch(which) 2953 { 2954 case page_setup_hook: return data->u.dlgw->lpfnPageSetupHook; 2955 case page_paint_hook: return data->u.dlgw->lpfnPagePaintHook; 2956 } 2957 return NULL; 2958 } 2959 2960 /* This should only be used in calls to hook procs so we return the ptr 2961 already cast to LPARAM */ 2962 static inline LPARAM pagesetup_get_dlg_struct(const pagesetup_data *data) 2963 { 2964 return (LPARAM)data->u.dlgw; 2965 } 2966 2967 static inline void swap_point(POINT *pt) 2968 { 2969 LONG tmp = pt->x; 2970 pt->x = pt->y; 2971 pt->y = tmp; 2972 } 2973 2974 static BOOL pagesetup_update_papersize(pagesetup_data *data) 2975 { 2976 DEVMODEW *dm; 2977 LPWSTR devname, portname; 2978 int i, num; 2979 WORD *words = NULL, paperword; 2980 POINT *points = NULL; 2981 BOOL retval = FALSE; 2982 2983 dm = pagesetup_get_devmode(data); 2984 devname = pagesetup_get_devname(data); 2985 portname = pagesetup_get_portname(data); 2986 2987 num = DeviceCapabilitiesW(devname, portname, DC_PAPERS, NULL, dm); 2988 if (num <= 0) 2989 { 2990 FIXME("No papernames found for %s/%s\n", debugstr_w(devname), debugstr_w(portname)); 2991 goto end; 2992 } 2993 2994 words = HeapAlloc(GetProcessHeap(), 0, num * sizeof(WORD)); 2995 points = HeapAlloc(GetProcessHeap(), 0, num * sizeof(POINT)); 2996 2997 if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERS, (LPWSTR)words, dm)) 2998 { 2999 FIXME("Number of returned words is not %d\n", num); 3000 goto end; 3001 } 3002 3003 if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERSIZE, (LPWSTR)points, dm)) 3004 { 3005 FIXME("Number of returned sizes is not %d\n", num); 3006 goto end; 3007 } 3008 3009 paperword = pagesetup_get_papersize(data); 3010 3011 for (i = 0; i < num; i++) 3012 if (words[i] == paperword) 3013 break; 3014 3015 if (i == num) 3016 { 3017 FIXME("Papersize %d not found in list?\n", paperword); 3018 goto end; 3019 } 3020 3021 /* this is _10ths_ of a millimeter */ 3022 pagesetup_get_papersize_pt(data)->x = tenths_mm_to_size(data, points[i].x); 3023 pagesetup_get_papersize_pt(data)->y = tenths_mm_to_size(data, points[i].y); 3024 3025 if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) 3026 swap_point(pagesetup_get_papersize_pt(data)); 3027 3028 retval = TRUE; 3029 3030 end: 3031 HeapFree(GetProcessHeap(), 0, words); 3032 HeapFree(GetProcessHeap(), 0, points); 3033 pagesetup_release_a_devname(data, portname); 3034 pagesetup_release_a_devname(data, devname); 3035 pagesetup_release_devmode(data, dm); 3036 3037 return retval; 3038 } 3039 3040 /********************************************************************************************** 3041 * pagesetup_change_printer 3042 * 3043 * Redefines hDevMode and hDevNames HANDLES and initialises it. 3044 * 3045 */ 3046 static BOOL pagesetup_change_printer(LPWSTR name, pagesetup_data *data) 3047 { 3048 HANDLE hprn; 3049 DWORD needed; 3050 PRINTER_INFO_2W *prn_info = NULL; 3051 DRIVER_INFO_3W *drv_info = NULL; 3052 DEVMODEW *dm = NULL; 3053 BOOL retval = FALSE; 3054 3055 if(!OpenPrinterW(name, &hprn, NULL)) 3056 { 3057 ERR("Can't open printer %s\n", debugstr_w(name)); 3058 goto end; 3059 } 3060 3061 GetPrinterW(hprn, 2, NULL, 0, &needed); 3062 prn_info = HeapAlloc(GetProcessHeap(), 0, needed); 3063 GetPrinterW(hprn, 2, (LPBYTE)prn_info, needed, &needed); 3064 GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); 3065 drv_info = HeapAlloc(GetProcessHeap(), 0, needed); 3066 if(!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)drv_info, needed, &needed)) 3067 { 3068 ERR("GetPrinterDriverA failed for %s, fix your config!\n", debugstr_w(prn_info->pPrinterName)); 3069 goto end; 3070 } 3071 ClosePrinter(hprn); 3072 3073 needed = DocumentPropertiesW(0, 0, name, NULL, NULL, 0); 3074 if(needed == -1) 3075 { 3076 ERR("DocumentProperties fails on %s\n", debugstr_w(name)); 3077 goto end; 3078 } 3079 3080 dm = HeapAlloc(GetProcessHeap(), 0, needed); 3081 DocumentPropertiesW(0, 0, name, dm, NULL, DM_OUT_BUFFER); 3082 3083 pagesetup_set_devmode(data, dm); 3084 pagesetup_set_devnames(data, drv_info->pDriverPath, prn_info->pPrinterName, 3085 prn_info->pPortName); 3086 3087 retval = TRUE; 3088 end: 3089 HeapFree(GetProcessHeap(), 0, dm); 3090 HeapFree(GetProcessHeap(), 0, prn_info); 3091 HeapFree(GetProcessHeap(), 0, drv_info); 3092 return retval; 3093 } 3094 3095 /**************************************************************************************** 3096 * pagesetup_init_combos 3097 * 3098 * Fills Printers, Paper and Source combos 3099 * 3100 */ 3101 static void pagesetup_init_combos(HWND hDlg, pagesetup_data *data) 3102 { 3103 DEVMODEW *dm; 3104 LPWSTR devname, portname; 3105 3106 dm = pagesetup_get_devmode(data); 3107 devname = pagesetup_get_devname(data); 3108 portname = pagesetup_get_portname(data); 3109 3110 PRINTDLG_SetUpPrinterListComboW(hDlg, cmb1, devname); 3111 PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, devname, portname, dm); 3112 PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, devname, portname, dm); 3113 3114 pagesetup_release_a_devname(data, portname); 3115 pagesetup_release_a_devname(data, devname); 3116 pagesetup_release_devmode(data, dm); 3117 } 3118 3119 3120 /**************************************************************************************** 3121 * pagesetup_change_printer_dialog 3122 * 3123 * Pops up another dialog that lets the user pick another printer. 3124 * 3125 * For now we display the PrintDlg, this should display a striped down version of it. 3126 */ 3127 static void pagesetup_change_printer_dialog(HWND hDlg, pagesetup_data *data) 3128 { 3129 PRINTDLGW prnt; 3130 LPWSTR drvname, devname, portname; 3131 DEVMODEW *tmp_dm, *dm; 3132 3133 memset(&prnt, 0, sizeof(prnt)); 3134 prnt.lStructSize = sizeof(prnt); 3135 prnt.Flags = 0; 3136 prnt.hwndOwner = hDlg; 3137 3138 drvname = pagesetup_get_drvname(data); 3139 devname = pagesetup_get_devname(data); 3140 portname = pagesetup_get_portname(data); 3141 prnt.hDevNames = 0; 3142 PRINTDLG_CreateDevNamesW(&prnt.hDevNames, drvname, devname, portname); 3143 pagesetup_release_a_devname(data, portname); 3144 pagesetup_release_a_devname(data, devname); 3145 pagesetup_release_a_devname(data, drvname); 3146 3147 tmp_dm = pagesetup_get_devmode(data); 3148 prnt.hDevMode = GlobalAlloc(GMEM_MOVEABLE, tmp_dm->dmSize + tmp_dm->dmDriverExtra); 3149 dm = GlobalLock(prnt.hDevMode); 3150 memcpy(dm, tmp_dm, tmp_dm->dmSize + tmp_dm->dmDriverExtra); 3151 GlobalUnlock(prnt.hDevMode); 3152 pagesetup_release_devmode(data, tmp_dm); 3153 3154 if (PrintDlgW(&prnt)) 3155 { 3156 DEVMODEW *dm = GlobalLock(prnt.hDevMode); 3157 DEVNAMES *dn = GlobalLock(prnt.hDevNames); 3158 3159 pagesetup_set_devnames(data, (WCHAR*)dn + dn->wDriverOffset, 3160 (WCHAR*)dn + dn->wDeviceOffset, (WCHAR *)dn + dn->wOutputOffset); 3161 pagesetup_set_devmode(data, dm); 3162 GlobalUnlock(prnt.hDevNames); 3163 GlobalUnlock(prnt.hDevMode); 3164 pagesetup_init_combos(hDlg, data); 3165 } 3166 3167 GlobalFree(prnt.hDevMode); 3168 GlobalFree(prnt.hDevNames); 3169 3170 } 3171 3172 /****************************************************************************************** 3173 * pagesetup_change_preview 3174 * 3175 * Changes paper preview size / position 3176 * 3177 */ 3178 static void pagesetup_change_preview(const pagesetup_data *data) 3179 { 3180 LONG width, height, x, y; 3181 RECT tmp; 3182 const int shadow = 4; 3183 3184 if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) 3185 { 3186 width = data->rtDrawRect.right - data->rtDrawRect.left; 3187 height = pagesetup_get_papersize_pt(data)->y * width / pagesetup_get_papersize_pt(data)->x; 3188 } 3189 else 3190 { 3191 height = data->rtDrawRect.bottom - data->rtDrawRect.top; 3192 width = pagesetup_get_papersize_pt(data)->x * height / pagesetup_get_papersize_pt(data)->y; 3193 } 3194 x = (data->rtDrawRect.right + data->rtDrawRect.left - width) / 2; 3195 y = (data->rtDrawRect.bottom + data->rtDrawRect.top - height) / 2; 3196 TRACE("draw rect %s x=%d, y=%d, w=%d, h=%d\n", 3197 wine_dbgstr_rect(&data->rtDrawRect), x, y, width, height); 3198 3199 MoveWindow(GetDlgItem(data->hDlg, rct2), x + width, y + shadow, shadow, height, FALSE); 3200 MoveWindow(GetDlgItem(data->hDlg, rct3), x + shadow, y + height, width, shadow, FALSE); 3201 MoveWindow(GetDlgItem(data->hDlg, rct1), x, y, width, height, FALSE); 3202 3203 tmp = data->rtDrawRect; 3204 tmp.right += shadow; 3205 tmp.bottom += shadow; 3206 InvalidateRect(data->hDlg, &tmp, TRUE); 3207 } 3208 3209 static inline LONG *element_from_margin_id(RECT *rc, WORD id) 3210 { 3211 switch(id) 3212 { 3213 case edt4: return &rc->left; 3214 case edt5: return &rc->top; 3215 case edt6: return &rc->right; 3216 case edt7: return &rc->bottom; 3217 } 3218 return NULL; 3219 } 3220 3221 static void update_margin_edits(HWND hDlg, const pagesetup_data *data, WORD id) 3222 { 3223 WCHAR str[100]; 3224 WORD idx; 3225 3226 for(idx = edt4; idx <= edt7; idx++) 3227 { 3228 if(id == 0 || id == idx) 3229 { 3230 size2str(data, *element_from_margin_id(pagesetup_get_margin_rect(data), idx), str); 3231 SetDlgItemTextW(hDlg, idx, str); 3232 } 3233 } 3234 } 3235 3236 static void margin_edit_notification(HWND hDlg, const pagesetup_data *data, WORD msg, WORD id) 3237 { 3238 switch (msg) 3239 { 3240 case EN_CHANGE: 3241 { 3242 WCHAR buf[10]; 3243 LONG val = 0; 3244 LONG *value = element_from_margin_id(pagesetup_get_margin_rect(data), id); 3245 3246 if (GetDlgItemTextW(hDlg, id, buf, sizeof(buf) / sizeof(buf[0])) != 0) 3247 { 3248 WCHAR *end; 3249 WCHAR decimal = get_decimal_sep(); 3250 3251 val = strtolW(buf, &end, 10); 3252 if(end != buf || *end == decimal) 3253 { 3254 int mult = is_metric(data) ? 100 : 1000; 3255 val *= mult; 3256 if(*end == decimal) 3257 { 3258 while(mult > 1) 3259 { 3260 end++; 3261 mult /= 10; 3262 if(isdigitW(*end)) 3263 val += (*end - '0') * mult; 3264 else 3265 break; 3266 } 3267 } 3268 } 3269 } 3270 *value = val; 3271 return; 3272 } 3273 3274 case EN_KILLFOCUS: 3275 update_margin_edits(hDlg, data, id); 3276 return; 3277 } 3278 } 3279 3280 static void set_margin_groupbox_title(HWND hDlg, const pagesetup_data *data) 3281 { 3282 WCHAR title[256]; 3283 3284 if(LoadStringW(COMDLG32_hInstance, is_metric(data) ? PD32_MARGINS_IN_MILLIMETERS : PD32_MARGINS_IN_INCHES, 3285 title, sizeof(title)/sizeof(title[0]))) 3286 SetDlgItemTextW(hDlg, grp4, title); 3287 } 3288 3289 static void pagesetup_update_orientation_buttons(HWND hDlg, const pagesetup_data *data) 3290 { 3291 if (pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) 3292 CheckRadioButton(hDlg, rad1, rad2, rad2); 3293 else 3294 CheckRadioButton(hDlg, rad1, rad2, rad1); 3295 } 3296 3297 /**************************************************************************************** 3298 * pagesetup_printer_properties 3299 * 3300 * Handle invocation of the 'Properties' button (not present in the default template). 3301 */ 3302 static void pagesetup_printer_properties(HWND hDlg, pagesetup_data *data) 3303 { 3304 HANDLE hprn; 3305 LPWSTR devname; 3306 DEVMODEW *dm; 3307 LRESULT count; 3308 int i; 3309 3310 devname = pagesetup_get_devname(data); 3311 3312 if (!OpenPrinterW(devname, &hprn, NULL)) 3313 { 3314 FIXME("Call to OpenPrinter did not succeed!\n"); 3315 pagesetup_release_a_devname(data, devname); 3316 return; 3317 } 3318 3319 dm = pagesetup_get_devmode(data); 3320 DocumentPropertiesW(hDlg, hprn, devname, dm, dm, DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); 3321 pagesetup_set_devmode(data, dm); 3322 pagesetup_release_devmode(data, dm); 3323 pagesetup_release_a_devname(data, devname); 3324 ClosePrinter(hprn); 3325 3326 /* Changing paper */ 3327 pagesetup_update_papersize(data); 3328 pagesetup_update_orientation_buttons(hDlg, data); 3329 3330 /* Changing paper preview */ 3331 pagesetup_change_preview(data); 3332 3333 /* Selecting paper in combo */ 3334 count = SendDlgItemMessageW(hDlg, cmb2, CB_GETCOUNT, 0, 0); 3335 if(count != CB_ERR) 3336 { 3337 WORD paperword = pagesetup_get_papersize(data); 3338 for(i = 0; i < count; i++) 3339 { 3340 if(SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0) == paperword) { 3341 SendDlgItemMessageW(hDlg, cmb2, CB_SETCURSEL, i, 0); 3342 break; 3343 } 3344 } 3345 } 3346 } 3347 3348 /******************************************************************************** 3349 * pagesetup_wm_command 3350 * process WM_COMMAND message for PageSetupDlg 3351 * 3352 * PARAMS 3353 * hDlg [in] Main dialog HANDLE 3354 * wParam [in] WM_COMMAND wParam 3355 * lParam [in] WM_COMMAND lParam 3356 * pda [in/out] ptr to PageSetupDataA 3357 */ 3358 3359 static BOOL pagesetup_wm_command(HWND hDlg, WPARAM wParam, LPARAM lParam, pagesetup_data *data) 3360 { 3361 WORD msg = HIWORD(wParam); 3362 WORD id = LOWORD(wParam); 3363 3364 TRACE("loword (lparam) %d, wparam 0x%lx, lparam %08lx\n", 3365 LOWORD(lParam),wParam,lParam); 3366 switch (id) { 3367 case IDOK: 3368 EndDialog(hDlg, TRUE); 3369 return TRUE ; 3370 3371 case IDCANCEL: 3372 EndDialog(hDlg, FALSE); 3373 return FALSE ; 3374 3375 case psh3: /* Printer... */ 3376 pagesetup_change_printer_dialog(hDlg, data); 3377 return TRUE; 3378 3379 case rad1: /* Portrait */ 3380 case rad2: /* Landscape */ 3381 if((id == rad1 && pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) || 3382 (id == rad2 && pagesetup_get_orientation(data) == DMORIENT_PORTRAIT)) 3383 { 3384 pagesetup_set_orientation(data, (id == rad1) ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE); 3385 pagesetup_update_papersize(data); 3386 rotate_rect(pagesetup_get_margin_rect(data), (id == rad2)); 3387 update_margin_edits(hDlg, data, 0); 3388 pagesetup_change_preview(data); 3389 } 3390 break; 3391 case cmb1: /* Printer combo */ 3392 if(msg == CBN_SELCHANGE) 3393 { 3394 WCHAR *name; 3395 INT index = SendDlgItemMessageW(hDlg, id, CB_GETCURSEL, 0, 0); 3396 INT length = SendDlgItemMessageW(hDlg, id, CB_GETLBTEXTLEN, index, 0); 3397 name = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1)); 3398 SendDlgItemMessageW(hDlg, id, CB_GETLBTEXT, index, (LPARAM)name); 3399 pagesetup_change_printer(name, data); 3400 pagesetup_init_combos(hDlg, data); 3401 HeapFree(GetProcessHeap(),0,name); 3402 } 3403 break; 3404 case cmb2: /* Paper combo */ 3405 if(msg == CBN_SELCHANGE) 3406 { 3407 DWORD paperword = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, 3408 SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0), 0); 3409 if (paperword != CB_ERR) 3410 { 3411 pagesetup_set_papersize(data, paperword); 3412 pagesetup_update_papersize(data); 3413 pagesetup_change_preview(data); 3414 } else 3415 FIXME("could not get dialog text for papersize cmbbox?\n"); 3416 } 3417 break; 3418 case cmb3: /* Paper Source */ 3419 if(msg == CBN_SELCHANGE) 3420 { 3421 WORD source = SendDlgItemMessageW(hDlg, cmb3, CB_GETITEMDATA, 3422 SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0), 0); 3423 pagesetup_set_defaultsource(data, source); 3424 } 3425 break; 3426 case psh2: /* Printer Properties button */ 3427 pagesetup_printer_properties(hDlg, data); 3428 break; 3429 case edt4: 3430 case edt5: 3431 case edt6: 3432 case edt7: 3433 margin_edit_notification(hDlg, data, msg, id); 3434 break; 3435 } 3436 InvalidateRect(GetDlgItem(hDlg, rct1), NULL, TRUE); 3437 return FALSE; 3438 } 3439 3440 /*********************************************************************** 3441 * default_page_paint_hook 3442 * Default hook paint procedure that receives WM_PSD_* messages from the dialog box 3443 * whenever the sample page is redrawn. 3444 */ 3445 static UINT_PTR default_page_paint_hook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, 3446 const pagesetup_data *data) 3447 { 3448 LPRECT lprc = (LPRECT) lParam; 3449 HDC hdc = (HDC) wParam; 3450 HPEN hpen, holdpen; 3451 LOGFONTW lf; 3452 HFONT hfont, holdfont; 3453 INT oldbkmode; 3454 TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER); 3455 /* Call user paint hook if enable */ 3456 if (pagesetup_get_flags(data) & PSD_ENABLEPAGEPAINTHOOK) 3457 if (pagesetup_get_hook(data, page_paint_hook)(hwndDlg, uMsg, wParam, lParam)) 3458 return TRUE; 3459 3460 switch (uMsg) { 3461 /* LPPAGESETUPDLG in lParam */ 3462 case WM_PSD_PAGESETUPDLG: 3463 /* Inform about the sample page rectangle */ 3464 case WM_PSD_FULLPAGERECT: 3465 /* Inform about the margin rectangle */ 3466 case WM_PSD_MINMARGINRECT: 3467 return FALSE; 3468 3469 /* Draw dashed rectangle showing margins */ 3470 case WM_PSD_MARGINRECT: 3471 hpen = CreatePen(PS_DASH, 1, GetSysColor(COLOR_3DSHADOW)); 3472 holdpen = SelectObject(hdc, hpen); 3473 Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); 3474 DeleteObject(SelectObject(hdc, holdpen)); 3475 return TRUE; 3476 /* Draw the fake document */ 3477 case WM_PSD_GREEKTEXTRECT: 3478 /* select a nice scalable font, because we want the text really small */ 3479 SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); 3480 lf.lfHeight = 6; /* value chosen based on visual effect */ 3481 hfont = CreateFontIndirectW(&lf); 3482 holdfont = SelectObject(hdc, hfont); 3483 3484 /* if text not loaded, then do so now */ 3485 if (wszFakeDocumentText[0] == '\0') 3486 LoadStringW(COMDLG32_hInstance, 3487 IDS_FAKEDOCTEXT, 3488 wszFakeDocumentText, 3489 sizeof(wszFakeDocumentText)/sizeof(wszFakeDocumentText[0])); 3490 3491 oldbkmode = SetBkMode(hdc, TRANSPARENT); 3492 DrawTextW(hdc, wszFakeDocumentText, -1, lprc, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); 3493 SetBkMode(hdc, oldbkmode); 3494 3495 DeleteObject(SelectObject(hdc, holdfont)); 3496 return TRUE; 3497 3498 /* Envelope stamp */ 3499 case WM_PSD_ENVSTAMPRECT: 3500 /* Return address */ 3501 case WM_PSD_YAFULLPAGERECT: 3502 FIXME("envelope/stamp is not implemented\n"); 3503 return FALSE; 3504 default: 3505 FIXME("Unknown message %x\n",uMsg); 3506 return FALSE; 3507 } 3508 return TRUE; 3509 } 3510 3511 /*********************************************************************** 3512 * PagePaintProc 3513 * The main paint procedure for the PageSetupDlg function. 3514 * The Page Setup dialog box includes an image of a sample page that shows how 3515 * the user's selections affect the appearance of the printed output. 3516 * The image consists of a rectangle that represents the selected paper 3517 * or envelope type, with a dotted-line rectangle representing 3518 * the current margins, and partial (Greek text) characters 3519 * to show how text looks on the printed page. 3520 * 3521 * The following messages in the order sends to user hook procedure: 3522 * WM_PSD_PAGESETUPDLG Draw the contents of the sample page 3523 * WM_PSD_FULLPAGERECT Inform about the bounding rectangle 3524 * WM_PSD_MINMARGINRECT Inform about the margin rectangle (min margin?) 3525 * WM_PSD_MARGINRECT Draw the margin rectangle 3526 * WM_PSD_GREEKTEXTRECT Draw the Greek text inside the margin rectangle 3527 * If any of first three messages returns TRUE, painting done. 3528 * 3529 * PARAMS: 3530 * hWnd [in] Handle to the Page Setup dialog box 3531 * uMsg [in] Received message 3532 * 3533 * TODO: 3534 * WM_PSD_ENVSTAMPRECT Draw in the envelope-stamp rectangle (for envelopes only) 3535 * WM_PSD_YAFULLPAGERECT Draw the return address portion (for envelopes and other paper sizes) 3536 * 3537 * RETURNS: 3538 * FALSE if all done correctly 3539 * 3540 */ 3541 3542 3543 static LRESULT CALLBACK 3544 PRINTDLG_PagePaintProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 3545 { 3546 PAINTSTRUCT ps; 3547 RECT rcClient, rcMargin; 3548 HPEN hpen, holdpen; 3549 HDC hdc; 3550 HBRUSH hbrush, holdbrush; 3551 pagesetup_data *data; 3552 int papersize=0, orientation=0; /* FIXME: set these values for the user paint hook */ 3553 double scalx, scaly; 3554 3555 if (uMsg != WM_PAINT) 3556 return CallWindowProcA(lpfnStaticWndProc, hWnd, uMsg, wParam, lParam); 3557 3558 /* Processing WM_PAINT message */ 3559 data = GetPropW(hWnd, pagesetupdlg_prop); 3560 if (!data) { 3561 WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); 3562 return FALSE; 3563 } 3564 if (default_page_paint_hook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation), 3565 pagesetup_get_dlg_struct(data), data)) 3566 return FALSE; 3567 3568 hdc = BeginPaint(hWnd, &ps); 3569 GetClientRect(hWnd, &rcClient); 3570 3571 scalx = rcClient.right / (double)pagesetup_get_papersize_pt(data)->x; 3572 scaly = rcClient.bottom / (double)pagesetup_get_papersize_pt(data)->y; 3573 rcMargin = rcClient; 3574 3575 rcMargin.left += pagesetup_get_margin_rect(data)->left * scalx; 3576 rcMargin.top += pagesetup_get_margin_rect(data)->top * scaly; 3577 rcMargin.right -= pagesetup_get_margin_rect(data)->right * scalx; 3578 rcMargin.bottom -= pagesetup_get_margin_rect(data)->bottom * scaly; 3579 3580 /* if the space is too small then we make sure to not draw anything */ 3581 rcMargin.left = min(rcMargin.left, rcMargin.right); 3582 rcMargin.top = min(rcMargin.top, rcMargin.bottom); 3583 3584 if (!default_page_paint_hook(hWnd, WM_PSD_FULLPAGERECT, (WPARAM)hdc, (LPARAM)&rcClient, data) && 3585 !default_page_paint_hook(hWnd, WM_PSD_MINMARGINRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data) ) 3586 { 3587 /* fill background */ 3588 hbrush = GetSysColorBrush(COLOR_3DHIGHLIGHT); 3589 FillRect(hdc, &rcClient, hbrush); 3590 holdbrush = SelectObject(hdc, hbrush); 3591 3592 hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); 3593 holdpen = SelectObject(hdc, hpen); 3594 3595 /* paint left edge */ 3596 MoveToEx(hdc, rcClient.left, rcClient.top, NULL); 3597 LineTo(hdc, rcClient.left, rcClient.bottom-1); 3598 3599 /* paint top edge */ 3600 MoveToEx(hdc, rcClient.left, rcClient.top, NULL); 3601 LineTo(hdc, rcClient.right, rcClient.top); 3602 3603 hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW)); 3604 DeleteObject(SelectObject(hdc, hpen)); 3605 3606 /* paint right edge */ 3607 MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL); 3608 LineTo(hdc, rcClient.right-1, rcClient.bottom); 3609 3610 /* paint bottom edge */ 3611 MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL); 3612 LineTo(hdc, rcClient.right, rcClient.bottom-1); 3613 3614 DeleteObject(SelectObject(hdc, holdpen)); 3615 DeleteObject(SelectObject(hdc, holdbrush)); 3616 3617 default_page_paint_hook(hWnd, WM_PSD_MARGINRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data); 3618 3619 /* give text a bit of a space from the frame */ 3620 InflateRect(&rcMargin, -2, -2); 3621 3622 /* if the space is too small then we make sure to not draw anything */ 3623 rcMargin.left = min(rcMargin.left, rcMargin.right); 3624 rcMargin.top = min(rcMargin.top, rcMargin.bottom); 3625 3626 default_page_paint_hook(hWnd, WM_PSD_GREEKTEXTRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data); 3627 } 3628 3629 EndPaint(hWnd, &ps); 3630 return FALSE; 3631 } 3632 3633 /******************************************************* 3634 * The margin edit controls are subclassed to filter 3635 * anything other than numbers and the decimal separator. 3636 */ 3637 static LRESULT CALLBACK pagesetup_margin_editproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 3638 { 3639 if (msg == WM_CHAR) 3640 { 3641 WCHAR decimal = get_decimal_sep(); 3642 WCHAR wc = (WCHAR)wparam; 3643 if(!isdigitW(wc) && wc != decimal && wc != VK_BACK) return 0; 3644 } 3645 return CallWindowProcW(edit_wndproc, hwnd, msg, wparam, lparam); 3646 } 3647 3648 static void subclass_margin_edits(HWND hDlg) 3649 { 3650 int id; 3651 WNDPROC old_proc; 3652 3653 for(id = edt4; id <= edt7; id++) 3654 { 3655 old_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hDlg, id), 3656 GWLP_WNDPROC, 3657 (ULONG_PTR)pagesetup_margin_editproc); 3658 InterlockedCompareExchangePointer((void**)&edit_wndproc, old_proc, NULL); 3659 } 3660 } 3661 3662 /*********************************************************************** 3663 * pagesetup_dlg_proc 3664 * 3665 * Message handler for PageSetupDlg 3666 */ 3667 static INT_PTR CALLBACK pagesetup_dlg_proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 3668 { 3669 pagesetup_data *data; 3670 INT_PTR res = FALSE; 3671 HWND hDrawWnd; 3672 3673 if (uMsg == WM_INITDIALOG) { /*Init dialog*/ 3674 data = (pagesetup_data *)lParam; 3675 data->hDlg = hDlg; 3676 3677 hDrawWnd = GetDlgItem(hDlg, rct1); 3678 TRACE("set property to %p\n", data); 3679 SetPropW(hDlg, pagesetupdlg_prop, data); 3680 SetPropW(hDrawWnd, pagesetupdlg_prop, data); 3681 GetWindowRect(hDrawWnd, &data->rtDrawRect); /* Calculating rect in client coordinates where paper draws */ 3682 MapWindowPoints( 0, hDlg, (LPPOINT)&data->rtDrawRect, 2 ); 3683 lpfnStaticWndProc = (WNDPROC)SetWindowLongPtrW( 3684 hDrawWnd, 3685 GWLP_WNDPROC, 3686 (ULONG_PTR)PRINTDLG_PagePaintProc); 3687 3688 /* FIXME: Paint hook. Must it be at begin of initialization or at end? */ 3689 res = TRUE; 3690 if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK) 3691 { 3692 if (!pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam, 3693 pagesetup_get_dlg_struct(data))) 3694 FIXME("Setup page hook failed?\n"); 3695 } 3696 3697 /* if printer button disabled */ 3698 if (pagesetup_get_flags(data) & PSD_DISABLEPRINTER) 3699 EnableWindow(GetDlgItem(hDlg, psh3), FALSE); 3700 /* if margin edit boxes disabled */ 3701 if (pagesetup_get_flags(data) & PSD_DISABLEMARGINS) 3702 { 3703 EnableWindow(GetDlgItem(hDlg, edt4), FALSE); 3704 EnableWindow(GetDlgItem(hDlg, edt5), FALSE); 3705 EnableWindow(GetDlgItem(hDlg, edt6), FALSE); 3706 EnableWindow(GetDlgItem(hDlg, edt7), FALSE); 3707 } 3708 3709 /* Set orientation radiobuttons properly */ 3710 pagesetup_update_orientation_buttons(hDlg, data); 3711 3712 /* if orientation disabled */ 3713 if (pagesetup_get_flags(data) & PSD_DISABLEORIENTATION) 3714 { 3715 EnableWindow(GetDlgItem(hDlg,rad1),FALSE); 3716 EnableWindow(GetDlgItem(hDlg,rad2),FALSE); 3717 } 3718 3719 /* We fill them out enabled or not */ 3720 if (!(pagesetup_get_flags(data) & PSD_MARGINS)) 3721 { 3722 /* default is 1 inch */ 3723 LONG size = thousandths_inch_to_size(data, 1000); 3724 SetRect(pagesetup_get_margin_rect(data), size, size, size, size); 3725 } 3726 update_margin_edits(hDlg, data, 0); 3727 subclass_margin_edits(hDlg); 3728 set_margin_groupbox_title(hDlg, data); 3729 3730 /* if paper disabled */ 3731 if (pagesetup_get_flags(data) & PSD_DISABLEPAPER) 3732 { 3733 EnableWindow(GetDlgItem(hDlg,cmb2),FALSE); 3734 EnableWindow(GetDlgItem(hDlg,cmb3),FALSE); 3735 } 3736 3737 /* filling combos: printer, paper, source. selecting current printer (from DEVMODEA) */ 3738 pagesetup_init_combos(hDlg, data); 3739 pagesetup_update_papersize(data); 3740 pagesetup_set_defaultsource(data, DMBIN_FORMSOURCE); /* FIXME: This is the auto select bin. Is this correct? */ 3741 3742 /* Drawing paper prev */ 3743 pagesetup_change_preview(data); 3744 return TRUE; 3745 } else { 3746 data = GetPropW(hDlg, pagesetupdlg_prop); 3747 if (!data) 3748 { 3749 WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); 3750 return FALSE; 3751 } 3752 if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK) 3753 { 3754 res = pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam, lParam); 3755 if (res) return res; 3756 } 3757 } 3758 switch (uMsg) { 3759 case WM_COMMAND: 3760 return pagesetup_wm_command(hDlg, wParam, lParam, data); 3761 } 3762 return FALSE; 3763 } 3764 3765 static WCHAR *get_default_printer(void) 3766 { 3767 WCHAR *name = NULL; 3768 DWORD len = 0; 3769 3770 GetDefaultPrinterW(NULL, &len); 3771 if(len) 3772 { 3773 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 3774 GetDefaultPrinterW(name, &len); 3775 } 3776 return name; 3777 } 3778 3779 static void pagesetup_dump_dlg_struct(const pagesetup_data *data) 3780 { 3781 if(TRACE_ON(commdlg)) 3782 { 3783 char flagstr[1000] = ""; 3784 const struct pd_flags *pflag = psd_flags; 3785 for( ; pflag->name; pflag++) 3786 { 3787 if(pagesetup_get_flags(data) & pflag->flag) 3788 { 3789 strcat(flagstr, pflag->name); 3790 strcat(flagstr, "|"); 3791 } 3792 } 3793 TRACE("%s: (%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" 3794 "hinst %p, flags %08x (%s)\n", 3795 data->unicode ? "unicode" : "ansi", 3796 data->u.dlgw, data->u.dlgw->hwndOwner, data->u.dlgw->hDevMode, 3797 data->u.dlgw->hDevNames, data->u.dlgw->hInstance, 3798 pagesetup_get_flags(data), flagstr); 3799 } 3800 } 3801 3802 static void *pagesetup_get_template(pagesetup_data *data) 3803 { 3804 HRSRC res; 3805 HGLOBAL tmpl_handle; 3806 3807 if(pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) 3808 { 3809 tmpl_handle = data->u.dlgw->hPageSetupTemplate; 3810 } 3811 else if(pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPTEMPLATE) 3812 { 3813 if(data->unicode) 3814 res = FindResourceW(data->u.dlgw->hInstance, 3815 data->u.dlgw->lpPageSetupTemplateName, (LPWSTR)RT_DIALOG); 3816 else 3817 res = FindResourceA(data->u.dlga->hInstance, 3818 data->u.dlga->lpPageSetupTemplateName, (LPSTR)RT_DIALOG); 3819 tmpl_handle = LoadResource(data->u.dlgw->hInstance, res); 3820 } 3821 else 3822 { 3823 res = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(PAGESETUPDLGORD), 3824 (LPWSTR)RT_DIALOG); 3825 tmpl_handle = LoadResource(COMDLG32_hInstance, res); 3826 } 3827 return LockResource(tmpl_handle); 3828 } 3829 3830 static BOOL pagesetup_common(pagesetup_data *data) 3831 { 3832 BOOL ret; 3833 void *tmpl; 3834 3835 if(!pagesetup_get_dlg_struct(data)) 3836 { 3837 COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION); 3838 return FALSE; 3839 } 3840 3841 pagesetup_dump_dlg_struct(data); 3842 3843 if(data->u.dlgw->lStructSize != sizeof(PAGESETUPDLGW)) 3844 { 3845 COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); 3846 return FALSE; 3847 } 3848 3849 if ((pagesetup_get_flags(data) & PSD_ENABLEPAGEPAINTHOOK) && 3850 (pagesetup_get_hook(data, page_paint_hook) == NULL)) 3851 { 3852 COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK); 3853 return FALSE; 3854 } 3855 3856 if(!(pagesetup_get_flags(data) & (PSD_INTHOUSANDTHSOFINCHES | PSD_INHUNDREDTHSOFMILLIMETERS))) 3857 data->u.dlgw->Flags |= is_default_metric() ? 3858 PSD_INHUNDREDTHSOFMILLIMETERS : PSD_INTHOUSANDTHSOFINCHES; 3859 3860 if (!data->u.dlgw->hDevMode || !data->u.dlgw->hDevNames) 3861 { 3862 WCHAR *def = get_default_printer(); 3863 if(!def) 3864 { 3865 if (!(pagesetup_get_flags(data) & PSD_NOWARNING)) 3866 { 3867 WCHAR errstr[256]; 3868 LoadStringW(COMDLG32_hInstance, PD32_NO_DEFAULT_PRINTER, errstr, 255); 3869 MessageBoxW(data->u.dlgw->hwndOwner, errstr, 0, MB_OK | MB_ICONERROR); 3870 } 3871 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); 3872 return FALSE; 3873 } 3874 pagesetup_change_printer(def, data); 3875 HeapFree(GetProcessHeap(), 0, def); 3876 } 3877 3878 if (pagesetup_get_flags(data) & PSD_RETURNDEFAULT) 3879 { 3880 pagesetup_update_papersize(data); 3881 return TRUE; 3882 } 3883 3884 tmpl = pagesetup_get_template(data); 3885 3886 ret = DialogBoxIndirectParamW(data->u.dlgw->hInstance, tmpl, 3887 data->u.dlgw->hwndOwner, 3888 pagesetup_dlg_proc, (LPARAM)data) > 0; 3889 return ret; 3890 } 3891 3892 /*********************************************************************** 3893 * PageSetupDlgA (COMDLG32.@) 3894 * 3895 * Displays the PAGE SETUP dialog box, which enables the user to specify 3896 * specific properties of a printed page such as 3897 * size, source, orientation and the width of the page margins. 3898 * 3899 * PARAMS 3900 * setupdlg [IO] PAGESETUPDLGA struct 3901 * 3902 * RETURNS 3903 * TRUE if the user pressed the OK button 3904 * FALSE if the user cancelled the window or an error occurred 3905 * 3906 * NOTES 3907 * The values of hDevMode and hDevNames are filled on output and can be 3908 * changed in PAGESETUPDLG when they are passed in PageSetupDlg. 3909 * 3910 */ 3911 BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg) 3912 { 3913 pagesetup_data data; 3914 3915 data.unicode = FALSE; 3916 data.u.dlga = setupdlg; 3917 3918 return pagesetup_common(&data); 3919 } 3920 3921 /*********************************************************************** 3922 * PageSetupDlgW (COMDLG32.@) 3923 * 3924 * See PageSetupDlgA. 3925 */ 3926 BOOL WINAPI PageSetupDlgW(LPPAGESETUPDLGW setupdlg) 3927 { 3928 pagesetup_data data; 3929 3930 data.unicode = TRUE; 3931 data.u.dlgw = setupdlg; 3932 3933 return pagesetup_common(&data); 3934 } 3935 3936 static void pdlgex_to_pdlg(const PRINTDLGEXW *pdlgex, PRINTDLGW *pdlg) 3937 { 3938 pdlg->lStructSize = sizeof(*pdlg); 3939 pdlg->hwndOwner = pdlgex->hwndOwner; 3940 pdlg->hDevMode = pdlgex->hDevMode; 3941 pdlg->hDevNames = pdlgex->hDevNames; 3942 pdlg->hDC = pdlgex->hDC; 3943 pdlg->Flags = pdlgex->Flags; 3944 if ((pdlgex->Flags & PD_NOPAGENUMS) || !pdlgex->nPageRanges || !pdlgex->lpPageRanges) 3945 { 3946 pdlg->nFromPage = 0; 3947 pdlg->nToPage = 65534; 3948 } 3949 else 3950 { 3951 pdlg->nFromPage = pdlgex->lpPageRanges[0].nFromPage; 3952 pdlg->nToPage = pdlgex->lpPageRanges[0].nToPage; 3953 } 3954 pdlg->nMinPage = pdlgex->nMinPage; 3955 pdlg->nMaxPage = pdlgex->nMaxPage; 3956 pdlg->nCopies = pdlgex->nCopies; 3957 pdlg->hInstance = pdlgex->hInstance; 3958 pdlg->lCustData = 0; 3959 pdlg->lpfnPrintHook = NULL; 3960 pdlg->lpfnSetupHook = NULL; 3961 pdlg->lpPrintTemplateName = pdlgex->lpPrintTemplateName; 3962 pdlg->lpSetupTemplateName = NULL; 3963 pdlg->hPrintTemplate = NULL; 3964 pdlg->hSetupTemplate = NULL; 3965 } 3966 3967 /* Only copy fields that are supposed to be changed. */ 3968 static void pdlg_to_pdlgex(const PRINTDLGW *pdlg, PRINTDLGEXW *pdlgex) 3969 { 3970 pdlgex->hDevMode = pdlg->hDevMode; 3971 pdlgex->hDevNames = pdlg->hDevNames; 3972 pdlgex->hDC = pdlg->hDC; 3973 if (!(pdlgex->Flags & PD_NOPAGENUMS) && pdlgex->nPageRanges && pdlgex->lpPageRanges) 3974 { 3975 pdlgex->lpPageRanges[0].nFromPage = pdlg->nFromPage; 3976 pdlgex->lpPageRanges[0].nToPage = pdlg->nToPage; 3977 } 3978 pdlgex->nMinPage = pdlg->nMinPage; 3979 pdlgex->nMaxPage = pdlg->nMaxPage; 3980 pdlgex->nCopies = pdlg->nCopies; 3981 } 3982 3983 struct callback_data 3984 { 3985 IPrintDialogCallback *callback; 3986 IObjectWithSite *object; 3987 }; 3988 3989 static UINT_PTR CALLBACK pdlgex_hook_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) 3990 { 3991 if (msg == WM_INITDIALOG) 3992 { 3993 PRINTDLGW *pd = (PRINTDLGW *)lp; 3994 struct callback_data *cb = (struct callback_data *)pd->lCustData; 3995 3996 if (cb->callback) 3997 { 3998 cb->callback->lpVtbl->SelectionChange(cb->callback); 3999 cb->callback->lpVtbl->InitDone(cb->callback); 4000 } 4001 } 4002 else 4003 { 4004 /* FIXME: store interface pointer somewhere in window properties and call it 4005 HRESULT hres; 4006 cb->callback->lpVtbl->HandleMessage(cb->callback, hwnd, msg, wp, lp, &hres); 4007 */ 4008 } 4009 4010 return 0; 4011 } 4012 4013 /*********************************************************************** 4014 * PrintDlgExA (COMDLG32.@) 4015 * 4016 * See PrintDlgExW. 4017 * 4018 * BUGS 4019 * Only a Stub 4020 * 4021 */ 4022 HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lppd) 4023 { 4024 PRINTER_INFO_2A *pbuf; 4025 DRIVER_INFO_3A *dbuf; 4026 DEVMODEA *dm; 4027 HRESULT hr = S_OK; 4028 HANDLE hprn; 4029 4030 if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXA))) 4031 return E_INVALIDARG; 4032 4033 if (!IsWindow(lppd->hwndOwner)) 4034 return E_HANDLE; 4035 4036 if (lppd->nStartPage != START_PAGE_GENERAL) 4037 { 4038 if (!lppd->nPropertyPages) 4039 return E_INVALIDARG; 4040 4041 FIXME("custom property sheets (%d at %p) not supported\n", lppd->nPropertyPages, lppd->lphPropertyPages); 4042 } 4043 4044 /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */ 4045 if (!(lppd->Flags & PD_NOPAGENUMS) && (!lppd->nMaxPageRanges || !lppd->lpPageRanges)) 4046 { 4047 return E_INVALIDARG; 4048 } 4049 4050 if (lppd->Flags & PD_RETURNDEFAULT) 4051 { 4052 if (lppd->hDevMode || lppd->hDevNames) 4053 { 4054 WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); 4055 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 4056 return E_INVALIDARG; 4057 } 4058 if (!PRINTDLG_OpenDefaultPrinter(&hprn)) 4059 { 4060 WARN("Can't find default printer\n"); 4061 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); 4062 return E_FAIL; 4063 } 4064 4065 pbuf = get_printer_infoA(hprn); 4066 if (!pbuf) 4067 { 4068 ClosePrinter(hprn); 4069 return E_FAIL; 4070 } 4071 4072 dbuf = get_driver_infoA(hprn); 4073 if (!dbuf) 4074 { 4075 HeapFree(GetProcessHeap(), 0, pbuf); 4076 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 4077 ClosePrinter(hprn); 4078 return E_FAIL; 4079 } 4080 dm = pbuf->pDevMode; 4081 } 4082 else 4083 { 4084 PRINTDLGA pdlg; 4085 struct callback_data cb_data = { 0 }; 4086 4087 FIXME("(%p) semi-stub\n", lppd); 4088 4089 if (lppd->lpCallback) 4090 { 4091 IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IPrintDialogCallback, (void **)&cb_data.callback); 4092 IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IObjectWithSite, (void **)&cb_data.object); 4093 } 4094 4095 /* 4096 * PRINTDLGEXA/W and PRINTDLGA/W layout is the same for A and W variants. 4097 */ 4098 pdlgex_to_pdlg((const PRINTDLGEXW *)lppd, (PRINTDLGW *)&pdlg); 4099 pdlg.Flags |= PD_ENABLEPRINTHOOK; 4100 pdlg.lpfnPrintHook = pdlgex_hook_proc; 4101 pdlg.lCustData = (LPARAM)&cb_data; 4102 4103 if (PrintDlgA(&pdlg)) 4104 { 4105 pdlg_to_pdlgex((const PRINTDLGW *)&pdlg, (PRINTDLGEXW *)lppd); 4106 lppd->dwResultAction = PD_RESULT_PRINT; 4107 } 4108 else 4109 lppd->dwResultAction = PD_RESULT_CANCEL; 4110 4111 if (cb_data.callback) 4112 cb_data.callback->lpVtbl->Release(cb_data.callback); 4113 if (cb_data.object) 4114 cb_data.object->lpVtbl->Release(cb_data.object); 4115 4116 return S_OK; 4117 } 4118 4119 ClosePrinter(hprn); 4120 4121 PRINTDLG_CreateDevNames(&(lppd->hDevNames), dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName); 4122 if (!lppd->hDevNames) 4123 hr = E_FAIL; 4124 4125 lppd->hDevMode = update_devmode_handleA(lppd->hDevMode, dm); 4126 if (hr == S_OK && lppd->hDevMode) { 4127 if (lppd->Flags & PD_RETURNDC) { 4128 lppd->hDC = CreateDCA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm); 4129 if (!lppd->hDC) 4130 hr = E_FAIL; 4131 } 4132 else if (lppd->Flags & PD_RETURNIC) { 4133 lppd->hDC = CreateICA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm); 4134 if (!lppd->hDC) 4135 hr = E_FAIL; 4136 } 4137 } 4138 else 4139 hr = E_FAIL; 4140 4141 HeapFree(GetProcessHeap(), 0, pbuf); 4142 HeapFree(GetProcessHeap(), 0, dbuf); 4143 4144 return hr; 4145 } 4146 4147 /*********************************************************************** 4148 * PrintDlgExW (COMDLG32.@) 4149 * 4150 * Display the property sheet style PRINT dialog box 4151 * 4152 * PARAMS 4153 * lppd [IO] ptr to PRINTDLGEX struct 4154 * 4155 * RETURNS 4156 * Success: S_OK 4157 * Failure: One of the following COM error codes: 4158 * E_OUTOFMEMORY Insufficient memory. 4159 * E_INVALIDARG One or more arguments are invalid. 4160 * E_POINTER Invalid pointer. 4161 * E_HANDLE Invalid handle. 4162 * E_FAIL Unspecified error. 4163 * 4164 * NOTES 4165 * This Dialog enables the user to specify specific properties of the print job. 4166 * The property sheet can also have additional application-specific and 4167 * driver-specific property pages. 4168 * 4169 * BUGS 4170 * Not fully implemented 4171 * 4172 */ 4173 HRESULT WINAPI PrintDlgExW(LPPRINTDLGEXW lppd) 4174 { 4175 PRINTER_INFO_2W *pbuf; 4176 DRIVER_INFO_3W *dbuf; 4177 DEVMODEW *dm; 4178 HRESULT hr = S_OK; 4179 HANDLE hprn; 4180 4181 if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXW))) { 4182 return E_INVALIDARG; 4183 } 4184 4185 if (!IsWindow(lppd->hwndOwner)) { 4186 return E_HANDLE; 4187 } 4188 4189 if (lppd->nStartPage != START_PAGE_GENERAL) 4190 { 4191 if (!lppd->nPropertyPages) 4192 return E_INVALIDARG; 4193 4194 FIXME("custom property sheets (%d at %p) not supported\n", lppd->nPropertyPages, lppd->lphPropertyPages); 4195 } 4196 4197 /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */ 4198 if (!(lppd->Flags & PD_NOPAGENUMS) && (!lppd->nMaxPageRanges || !lppd->lpPageRanges)) 4199 { 4200 return E_INVALIDARG; 4201 } 4202 4203 if (lppd->Flags & PD_RETURNDEFAULT) { 4204 4205 if (lppd->hDevMode || lppd->hDevNames) { 4206 WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); 4207 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 4208 return E_INVALIDARG; 4209 } 4210 if (!PRINTDLG_OpenDefaultPrinter(&hprn)) { 4211 WARN("Can't find default printer\n"); 4212 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); 4213 return E_FAIL; 4214 } 4215 4216 pbuf = get_printer_infoW(hprn); 4217 if (!pbuf) 4218 { 4219 ClosePrinter(hprn); 4220 return E_FAIL; 4221 } 4222 4223 dbuf = get_driver_infoW(hprn); 4224 if (!dbuf) 4225 { 4226 HeapFree(GetProcessHeap(), 0, pbuf); 4227 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 4228 ClosePrinter(hprn); 4229 return E_FAIL; 4230 } 4231 dm = pbuf->pDevMode; 4232 } 4233 else 4234 { 4235 PRINTDLGW pdlg; 4236 struct callback_data cb_data = { 0 }; 4237 4238 FIXME("(%p) semi-stub\n", lppd); 4239 4240 if (lppd->lpCallback) 4241 { 4242 IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IPrintDialogCallback, (void **)&cb_data.callback); 4243 IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IObjectWithSite, (void **)&cb_data.object); 4244 } 4245 4246 pdlgex_to_pdlg(lppd, &pdlg); 4247 pdlg.Flags |= PD_ENABLEPRINTHOOK; 4248 pdlg.lpfnPrintHook = pdlgex_hook_proc; 4249 pdlg.lCustData = (LPARAM)&cb_data; 4250 4251 if (PrintDlgW(&pdlg)) 4252 { 4253 pdlg_to_pdlgex(&pdlg, lppd); 4254 lppd->dwResultAction = PD_RESULT_PRINT; 4255 } 4256 else 4257 lppd->dwResultAction = PD_RESULT_CANCEL; 4258 4259 if (cb_data.callback) 4260 cb_data.callback->lpVtbl->Release(cb_data.callback); 4261 if (cb_data.object) 4262 cb_data.object->lpVtbl->Release(cb_data.object); 4263 4264 return S_OK; 4265 } 4266 4267 ClosePrinter(hprn); 4268 4269 PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName); 4270 if (!lppd->hDevNames) 4271 hr = E_FAIL; 4272 4273 lppd->hDevMode = update_devmode_handleW(lppd->hDevMode, dm); 4274 if (hr == S_OK && lppd->hDevMode) { 4275 if (lppd->Flags & PD_RETURNDC) { 4276 lppd->hDC = CreateDCW(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm); 4277 if (!lppd->hDC) 4278 hr = E_FAIL; 4279 } 4280 else if (lppd->Flags & PD_RETURNIC) { 4281 lppd->hDC = CreateICW(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm); 4282 if (!lppd->hDC) 4283 hr = E_FAIL; 4284 } 4285 } 4286 else 4287 hr = E_FAIL; 4288 4289 HeapFree(GetProcessHeap(), 0, pbuf); 4290 HeapFree(GetProcessHeap(), 0, dbuf); 4291 4292 return hr; 4293 } 4294