1 /*
2  * Unit test suite for comdlg32 API functions: printer dialogs
3  *
4  * Copyright 2006-2007 Detlef Riekenberg
5  * Copyright 2013 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  */
22 
23 #define COBJMACROS
24 #define CONST_VTABLE
25 #define WIN32_NO_STATUS
26 
27 #include <wine/test.h>
28 
29 //#include <stdarg.h>
30 #include <stdio.h>
31 
32 //#include "windef.h"
33 //#include "winbase.h"
34 //#include "winerror.h"
35 #include <wingdi.h>
36 #include <winuser.h>
37 #include <objbase.h>
38 
39 #include <cderr.h>
40 #include <commdlg.h>
41 #include <dlgs.h>
42 
43 /* ########################### */
44 
45 extern const IID IID_IObjectWithSite;
46 
47 static HMODULE  hcomdlg32;
48 static HRESULT (WINAPI * pPrintDlgExW)(LPPRINTDLGEXW);
49 
50 /* ########################### */
51 
52 static const CHAR emptyA[] = "";
53 static const CHAR PrinterPortsA[] = "PrinterPorts";
54 
55 /* ########################### */
56 
57 static void test_PageSetupDlgA(void)
58 {
59     LPPAGESETUPDLGA pDlg;
60     DWORD res;
61 
62     pDlg = HeapAlloc(GetProcessHeap(), 0, (sizeof(PAGESETUPDLGA)) * 2);
63     if (!pDlg) return;
64 
65     SetLastError(0xdeadbeef);
66     res = PageSetupDlgA(NULL);
67     ok( !res && (CommDlgExtendedError() == CDERR_INITIALIZATION),
68         "returned %u with %u and 0x%x (expected '0' and "
69         "CDERR_INITIALIZATION)\n", res, GetLastError(), CommDlgExtendedError());
70 
71     ZeroMemory(pDlg, sizeof(PAGESETUPDLGA));
72     pDlg->lStructSize = sizeof(PAGESETUPDLGA) -1;
73     SetLastError(0xdeadbeef);
74     res = PageSetupDlgA(pDlg);
75     ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE),
76         "returned %u with %u and 0x%x (expected '0' and "
77         "CDERR_STRUCTSIZE)\n", res, GetLastError(), CommDlgExtendedError());
78 
79     ZeroMemory(pDlg, sizeof(PAGESETUPDLGA));
80     pDlg->lStructSize = sizeof(PAGESETUPDLGA) +1;
81     pDlg->Flags = PSD_RETURNDEFAULT;
82     SetLastError(0xdeadbeef);
83     res = PageSetupDlgA(pDlg);
84     ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE),
85         "returned %u with %u and 0x%x (expected '0' and CDERR_STRUCTSIZE)\n",
86         res, GetLastError(), CommDlgExtendedError());
87 
88 
89     ZeroMemory(pDlg, sizeof(PAGESETUPDLGA));
90     pDlg->lStructSize = sizeof(PAGESETUPDLGA);
91     pDlg->Flags = PSD_RETURNDEFAULT | PSD_NOWARNING;
92     SetLastError(0xdeadbeef);
93     res = PageSetupDlgA(pDlg);
94     ok( res || (CommDlgExtendedError() == PDERR_NODEFAULTPRN),
95         "returned %u with %u and 0x%x (expected '!= 0' or '0' and "
96         "PDERR_NODEFAULTPRN)\n", res, GetLastError(), CommDlgExtendedError());
97 
98     if (!res && (CommDlgExtendedError() == PDERR_NODEFAULTPRN)) {
99         skip("No printer configured.\n");
100         HeapFree(GetProcessHeap(), 0, pDlg);
101         return;
102     }
103 
104     ok( pDlg->hDevMode && pDlg->hDevNames,
105         "got %p and %p (expected '!= NULL' for both)\n",
106         pDlg->hDevMode, pDlg->hDevNames);
107 
108     GlobalFree(pDlg->hDevMode);
109     GlobalFree(pDlg->hDevNames);
110 
111     HeapFree(GetProcessHeap(), 0, pDlg);
112 
113 }
114 
115 /* ########################### */
116 
117 static UINT_PTR CALLBACK print_hook_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
118 {
119     if (msg == WM_INITDIALOG)
120     {
121         /* some driver popup a dialog and hung the test or silently limit the number of copies,
122            when trying to set more than 999 copies */
123         SetDlgItemInt(hdlg, edt3, 123, FALSE);
124         PostMessageA(hdlg, WM_COMMAND, IDOK, FALSE);
125     }
126     return 0;
127 }
128 
129 static void test_PrintDlgA(void)
130 {
131     DWORD res, n_copies = 0;
132     LPPRINTDLGA pDlg;
133     DEVNAMES    *pDevNames;
134     LPCSTR driver;
135     LPCSTR device;
136     LPCSTR port;
137     CHAR   buffer[MAX_PATH];
138     LPSTR  ptr;
139     DEVMODEA *dm;
140 
141     pDlg = HeapAlloc(GetProcessHeap(), 0, (sizeof(PRINTDLGA)) * 2);
142     if (!pDlg) return;
143 
144 
145     /* will crash with unpatched wine */
146     SetLastError(0xdeadbeef);
147     res = PrintDlgA(NULL);
148     ok( !res && (CommDlgExtendedError() == CDERR_INITIALIZATION),
149         "returned %d with 0x%x and 0x%x (expected '0' and "
150         "CDERR_INITIALIZATION)\n", res, GetLastError(), CommDlgExtendedError());
151 
152     ZeroMemory(pDlg, sizeof(PRINTDLGA));
153     pDlg->lStructSize = sizeof(PRINTDLGA) - 1;
154     SetLastError(0xdeadbeef);
155     res = PrintDlgA(pDlg);
156     ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE),
157         "returned %d with 0x%x and 0x%x (expected '0' and "
158         "CDERR_STRUCTSIZE)\n", res, GetLastError(), CommDlgExtendedError());
159 
160     ZeroMemory(pDlg, sizeof(PRINTDLGA));
161     pDlg->lStructSize = sizeof(PRINTDLGA) + 1;
162     pDlg->Flags = PD_RETURNDEFAULT;
163     SetLastError(0xdeadbeef);
164     res = PrintDlgA(pDlg);
165     ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE),
166         "returned %u with %u and 0x%x (expected '0' and "
167         "CDERR_STRUCTSIZE)\n", res, GetLastError(), CommDlgExtendedError());
168 
169 
170     ZeroMemory(pDlg, sizeof(PRINTDLGA));
171     pDlg->lStructSize = sizeof(PRINTDLGA);
172     pDlg->Flags = PD_RETURNDEFAULT;
173     SetLastError(0xdeadbeef);
174     res = PrintDlgA(pDlg);
175     ok( res || (CommDlgExtendedError() == PDERR_NODEFAULTPRN),
176         "returned %d with 0x%x and 0x%x (expected '!= 0' or '0' and "
177         "PDERR_NODEFAULTPRN)\n", res, GetLastError(), CommDlgExtendedError());
178 
179     if (!res && (CommDlgExtendedError() == PDERR_NODEFAULTPRN)) {
180         skip("No printer configured.\n");
181         HeapFree(GetProcessHeap(), 0, pDlg);
182         return;
183     }
184 
185     ok(pDlg->hDevNames != NULL, "(expected '!= NULL')\n");
186     pDevNames = GlobalLock(pDlg->hDevNames);
187     ok(pDevNames != NULL, "(expected '!= NULL')\n");
188 
189     if (pDevNames) {
190         ok(pDevNames->wDriverOffset, "(expected '!= 0' for wDriverOffset)\n");
191         ok(pDevNames->wDeviceOffset, "(expected '!= 0' for wDeviceOffset)\n");
192         ok(pDevNames->wOutputOffset, "(expected '!= 0' for wOutputOffset)\n");
193         ok(pDevNames->wDefault == DN_DEFAULTPRN, "got 0x%x (expected DN_DEFAULTPRN)\n", pDevNames->wDefault);
194 
195         driver = (LPCSTR)pDevNames + pDevNames->wDriverOffset;
196         device = (LPCSTR)pDevNames + pDevNames->wDeviceOffset;
197         port = (LPCSTR)pDevNames + pDevNames->wOutputOffset;
198         trace("driver '%s' device '%s' port '%s'\n", driver, device, port);
199 
200         /* The Driver Entry does not include a Path */
201         ptr = strrchr(driver, '\\');
202         ok( ptr == NULL, "got %p for '%s' (expected NULL for a simple name)\n", ptr, driver);
203 
204         /* The Driver Entry does not have an extension (fixed to ".drv") */
205         ptr = strrchr(driver, '.');
206         todo_wine {
207         ok( ptr == NULL, "got %p for '%s' (expected NULL for no extension)\n", ptr, driver);
208         }
209 
210 
211         buffer[0] = '\0';
212         SetLastError(0xdeadbeef);
213         res = GetProfileStringA(PrinterPortsA, device, emptyA, buffer, sizeof(buffer));
214         ptr = strchr(buffer, ',');
215         ok( (res > 1) && (ptr != NULL),
216             "got %u with %u and %p for '%s' (expected '>1' and '!= NULL')\n",
217             res, GetLastError(), ptr, buffer);
218 
219         if (ptr) ptr[0] = '\0';
220         ok( lstrcmpiA(driver, buffer) == 0,
221             "got driver '%s' (expected '%s')\n", driver, buffer);
222 
223         n_copies = DeviceCapabilitiesA(device, port, DC_COPIES, NULL, NULL);
224         ok(n_copies > 0, "DeviceCapabilities(DC_COPIES) failed\n");
225     }
226 
227     GlobalUnlock(pDlg->hDevNames);
228     GlobalFree(pDlg->hDevMode);
229     GlobalFree(pDlg->hDevNames);
230 
231     /* if device doesn't support printing of multiple copies then
232      * an attempt to set number of copies > 1 in print dialog would
233      * cause the PrintDlg under Windows display the MessageBox and
234      * the test will hang waiting for user response.
235      */
236     if (n_copies > 1)
237     {
238         ZeroMemory(pDlg, sizeof(*pDlg));
239         pDlg->lStructSize = sizeof(*pDlg);
240         pDlg->Flags = PD_ENABLEPRINTHOOK;
241         pDlg->lpfnPrintHook = print_hook_proc;
242         res = PrintDlgA(pDlg);
243         ok(res, "PrintDlg error %#x\n", CommDlgExtendedError());
244         /* Version of Microsoft XPS Document Writer driver shipped before Win7
245          * reports that it can print multiple copies, but returns 1.
246          */
247         ok(pDlg->nCopies == 123 || broken(pDlg->nCopies == 1), "expected nCopies 123, got %d\n", pDlg->nCopies);
248         ok(pDlg->hDevMode != 0, "hDevMode should not be 0\n");
249         dm = GlobalLock(pDlg->hDevMode);
250         /* some broken drivers use always PD_USEDEVMODECOPIES */
251         ok((S1(U1(*dm)).dmCopies == 1) || broken(S1(U1(*dm)).dmCopies == 123),
252             "expected dm->dmCopies 1, got %d\n", S1(U1(*dm)).dmCopies);
253         GlobalUnlock(pDlg->hDevMode);
254         GlobalFree(pDlg->hDevMode);
255         GlobalFree(pDlg->hDevNames);
256 
257         ZeroMemory(pDlg, sizeof(*pDlg));
258         pDlg->lStructSize = sizeof(*pDlg);
259         pDlg->Flags = PD_ENABLEPRINTHOOK | PD_USEDEVMODECOPIES;
260         pDlg->lpfnPrintHook = print_hook_proc;
261         res = PrintDlgA(pDlg);
262         ok(res, "PrintDlg error %#x\n", CommDlgExtendedError());
263         ok(pDlg->nCopies == 1, "expected nCopies 1, got %d\n", pDlg->nCopies);
264         ok(pDlg->hDevMode != 0, "hDevMode should not be 0\n");
265         dm = GlobalLock(pDlg->hDevMode);
266         ok(S1(U1(*dm)).dmCopies == 123, "expected dm->dmCopies 123, got %d\n", S1(U1(*dm)).dmCopies);
267         GlobalUnlock(pDlg->hDevMode);
268         GlobalFree(pDlg->hDevMode);
269         GlobalFree(pDlg->hDevNames);
270     }
271 
272     HeapFree(GetProcessHeap(), 0, pDlg);
273 }
274 
275 /* ########################### */
276 
277 static HRESULT WINAPI callback_QueryInterface(IPrintDialogCallback *iface,
278                                               REFIID riid, void **ppv)
279 {
280     ok(0, "callback_QueryInterface(%s): unexpected call\n", wine_dbgstr_guid(riid));
281     return E_NOINTERFACE;
282 }
283 
284 static ULONG WINAPI callback_AddRef(IPrintDialogCallback *iface)
285 {
286     trace("callback_AddRef\n");
287     return 2;
288 }
289 
290 static ULONG WINAPI callback_Release(IPrintDialogCallback *iface)
291 {
292     trace("callback_Release\n");
293     return 1;
294 }
295 
296 static HRESULT WINAPI callback_InitDone(IPrintDialogCallback *iface)
297 {
298     trace("callback_InitDone\n");
299     return S_OK;
300 }
301 
302 static HRESULT WINAPI callback_SelectionChange(IPrintDialogCallback *iface)
303 {
304     trace("callback_SelectionChange\n");
305     return S_OK;
306 }
307 
308 static HRESULT WINAPI callback_HandleMessage(IPrintDialogCallback *iface,
309     HWND hdlg, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res)
310 {
311     trace("callback_HandleMessage %p,%04x,%lx,%lx,%p\n", hdlg, msg, wp, lp, res);
312     /* *res = PD_RESULT_PRINT; */
313     return S_OK;
314 }
315 
316 static const IPrintDialogCallbackVtbl callback_Vtbl =
317 {
318     callback_QueryInterface,
319     callback_AddRef,
320     callback_Release,
321     callback_InitDone,
322     callback_SelectionChange,
323     callback_HandleMessage
324 };
325 
326 static IPrintDialogCallback callback = { &callback_Vtbl };
327 
328 static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
329 {
330     trace("unknown_QueryInterface %s\n", wine_dbgstr_guid(riid));
331 
332     if (IsEqualGUID(riid, &IID_IPrintDialogCallback))
333     {
334         *ppv = &callback;
335         return S_OK;
336     }
337     else if (IsEqualGUID(riid, &IID_IObjectWithSite))
338     {
339         *ppv = NULL;
340         return E_NOINTERFACE;
341     }
342 
343     ok(0, "unexpected IID %s\n", wine_dbgstr_guid(riid));
344     *ppv = NULL;
345     return E_NOINTERFACE;
346 }
347 
348 static ULONG WINAPI unknown_AddRef(IUnknown *iface)
349 {
350     trace("unknown_AddRef\n");
351     return 2;
352 }
353 
354 static ULONG WINAPI unknown_Release(IUnknown *iface)
355 {
356     trace("unknown_Release\n");
357     return 1;
358 }
359 
360 static const IUnknownVtbl unknown_Vtbl =
361 {
362     unknown_QueryInterface,
363     unknown_AddRef,
364     unknown_Release
365 };
366 
367 static IUnknown unknown = { &unknown_Vtbl };
368 
369 static void test_PrintDlgExW(void)
370 {
371     PRINTPAGERANGE pagerange[2];
372     LPPRINTDLGEXW pDlg;
373     DEVNAMES *dn;
374     HRESULT res;
375 
376     /* PrintDlgEx not present before w2k */
377     if (!pPrintDlgExW) {
378         skip("PrintDlgExW not available\n");
379         return;
380     }
381 
382     if (0) /* Crashes on Win10 */
383     {
384         /* Set CommDlgExtendedError != 0 */
385         PrintDlgA(NULL);
386         SetLastError(0xdeadbeef);
387         res = pPrintDlgExW(NULL);
388         ok( (res == E_INVALIDARG),
389             "got 0x%x with %u and %u (expected 'E_INVALIDARG')\n",
390             res, GetLastError(), CommDlgExtendedError() );
391     }
392 
393     pDlg = HeapAlloc(GetProcessHeap(), 0, (sizeof(PRINTDLGEXW)) + 8);
394     if (!pDlg) return;
395 
396     /* lStructSize must be exact */
397     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
398     pDlg->lStructSize = sizeof(PRINTDLGEXW) - 1;
399     PrintDlgA(NULL);
400     SetLastError(0xdeadbeef);
401     res = pPrintDlgExW(pDlg);
402     ok( (res == E_INVALIDARG),
403         "got 0x%x with %u and %u (expected 'E_INVALIDARG')\n",
404         res, GetLastError(), CommDlgExtendedError());
405 
406 
407     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
408     pDlg->lStructSize = sizeof(PRINTDLGEXW) + 1;
409     PrintDlgA(NULL);
410     SetLastError(0xdeadbeef);
411     res = pPrintDlgExW(pDlg);
412     ok( (res == E_INVALIDARG),
413         "got 0x%x with %u and %u (expected 'E_INVALIDARG')\n",
414         res, GetLastError(), CommDlgExtendedError());
415 
416 
417     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
418     pDlg->lStructSize = sizeof(PRINTDLGEXW);
419     SetLastError(0xdeadbeef);
420     res = pPrintDlgExW(pDlg);
421     ok( (res == E_HANDLE),
422         "got 0x%x with %u and %u (expected 'E_HANDLE')\n",
423         res, GetLastError(), CommDlgExtendedError());
424 
425     /* nStartPage must be START_PAGE_GENERAL for the general page or a valid property sheet index */
426     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
427     pDlg->lStructSize = sizeof(PRINTDLGEXW);
428     pDlg->hwndOwner = GetDesktopWindow();
429     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS;
430     res = pPrintDlgExW(pDlg);
431     ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res);
432 
433     /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */
434     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
435     pDlg->lStructSize = sizeof(PRINTDLGEXW);
436     pDlg->hwndOwner = GetDesktopWindow();
437     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING;
438     pDlg->nStartPage = START_PAGE_GENERAL;
439     res = pPrintDlgExW(pDlg);
440     ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res);
441 
442     /* this is invalid: a valid lpPageRanges with 0 for nMaxPageRanges */
443     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
444     pDlg->lStructSize = sizeof(PRINTDLGEXW);
445     pDlg->hwndOwner = GetDesktopWindow();
446     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING;
447     pDlg->lpPageRanges = pagerange;
448     pDlg->nStartPage = START_PAGE_GENERAL;
449     res = pPrintDlgExW(pDlg);
450     ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res);
451 
452     /* this is invalid: NULL for lpPageRanges with a valid nMaxPageRanges */
453     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
454     pDlg->lStructSize = sizeof(PRINTDLGEXW);
455     pDlg->hwndOwner = GetDesktopWindow();
456     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING;
457     pDlg->nMaxPageRanges = 1;
458     pDlg->nStartPage = START_PAGE_GENERAL;
459     res = pPrintDlgExW(pDlg);
460     ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res);
461 
462     /* this works: lpPageRanges with a valid nMaxPageRanges */
463     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
464     pDlg->lStructSize = sizeof(PRINTDLGEXW);
465     pDlg->hwndOwner = GetDesktopWindow();
466     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING;
467     pDlg->nMaxPageRanges = 1;
468     pDlg->lpPageRanges = pagerange;
469     pDlg->nStartPage = START_PAGE_GENERAL;
470     res = pPrintDlgExW(pDlg);
471     if (res == E_FAIL)
472     {
473         skip("No printer configured.\n");
474         HeapFree(GetProcessHeap(), 0, pDlg);
475         return;
476     }
477 
478     ok(res == S_OK, "got 0x%x (expected S_OK)\n", res);
479 
480     dn = GlobalLock(pDlg->hDevNames);
481     ok(dn != NULL, "expected '!= NULL' for GlobalLock(%p)\n",pDlg->hDevNames);
482     if (dn)
483     {
484         ok(dn->wDriverOffset, "(expected '!= 0' for wDriverOffset)\n");
485         ok(dn->wDeviceOffset, "(expected '!= 0' for wDeviceOffset)\n");
486         ok(dn->wOutputOffset, "(expected '!= 0' for wOutputOffset)\n");
487         ok(dn->wDefault == DN_DEFAULTPRN, "got 0x%x (expected DN_DEFAULTPRN)\n", dn->wDefault);
488 
489         GlobalUnlock(pDlg->hDevNames);
490     }
491     GlobalFree(pDlg->hDevMode);
492     GlobalFree(pDlg->hDevNames);
493 
494     /* this works also: PD_NOPAGENUMS */
495     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
496     pDlg->lStructSize = sizeof(PRINTDLGEXW);
497     pDlg->hwndOwner = GetDesktopWindow();
498     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS;
499     pDlg->nStartPage = START_PAGE_GENERAL;
500     res = pPrintDlgExW(pDlg);
501     ok(res == S_OK, "got 0x%x (expected S_OK)\n", res);
502     GlobalFree(pDlg->hDevMode);
503     GlobalFree(pDlg->hDevNames);
504 
505     /* this works: PD_RETURNDC with PD_RETURNDEFAULT */
506     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
507     pDlg->lStructSize = sizeof(PRINTDLGEXW);
508     pDlg->hwndOwner = GetDesktopWindow();
509     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS | PD_RETURNDC;
510     pDlg->nStartPage = START_PAGE_GENERAL;
511     res = pPrintDlgExW(pDlg);
512     ok(res == S_OK, "got 0x%x (expected S_OK)\n", res);
513     ok(pDlg->hDC != NULL, "HDC missing for PD_RETURNDC\n");
514     GlobalFree(pDlg->hDevMode);
515     GlobalFree(pDlg->hDevNames);
516     DeleteDC(pDlg->hDC);
517 
518     /* this works: PD_RETURNIC with PD_RETURNDEFAULT */
519     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
520     pDlg->lStructSize = sizeof(PRINTDLGEXW);
521     pDlg->hwndOwner = GetDesktopWindow();
522     pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS | PD_RETURNIC;
523     pDlg->nStartPage = START_PAGE_GENERAL;
524     res = pPrintDlgExW(pDlg);
525     ok(res == S_OK, "got 0x%x (expected S_OK)\n", res);
526     ok(pDlg->hDC != NULL, "HDC missing for PD_RETURNIC\n");
527     GlobalFree(pDlg->hDevMode);
528     GlobalFree(pDlg->hDevNames);
529     DeleteDC(pDlg->hDC);
530 
531     /* interactive PrintDlgEx tests */
532 
533     if (!winetest_interactive)
534     {
535         skip("interactive PrintDlgEx tests (set WINETEST_INTERACTIVE=1)\n");
536         HeapFree(GetProcessHeap(), 0, pDlg);
537         return;
538     }
539 
540     ZeroMemory(pDlg, sizeof(PRINTDLGEXW));
541     pDlg->lStructSize = sizeof(PRINTDLGEXW);
542     pDlg->hwndOwner = GetDesktopWindow();
543     pDlg->Flags = PD_NOPAGENUMS | PD_RETURNIC;
544     pDlg->nStartPage = START_PAGE_GENERAL;
545     pDlg->lpCallback = &unknown;
546     pDlg->dwResultAction = S_OK;
547     res = pPrintDlgExW(pDlg);
548     ok(res == S_OK, "got 0x%x (expected S_OK)\n", res);
549     ok(pDlg->dwResultAction == PD_RESULT_PRINT, "expected PD_RESULT_PRINT, got %#x\n", pDlg->dwResultAction);
550     ok(pDlg->hDC != NULL, "HDC missing for PD_RETURNIC\n");
551     GlobalFree(pDlg->hDevMode);
552     GlobalFree(pDlg->hDevNames);
553     DeleteDC(pDlg->hDC);
554 
555     HeapFree(GetProcessHeap(), 0, pDlg);
556 }
557 
558 static BOOL abort_proc_called = FALSE;
559 static BOOL CALLBACK abort_proc(HDC hdc, int error) { return abort_proc_called = TRUE; }
560 static void test_abort_proc(void)
561 {
562     HDC print_dc;
563     RECT rect = {0, 0, 100, 100};
564     DOCINFOA doc_info = {0};
565     PRINTDLGA pd = {0};
566     char filename[MAX_PATH];
567     int job_id;
568 
569     if (!GetTempFileNameA(".", "prn", 0, filename))
570     {
571         skip("Failed to create a temporary file name\n");
572         return;
573     }
574 
575     pd.lStructSize = sizeof(pd);
576     pd.Flags = PD_RETURNDEFAULT | PD_ALLPAGES | PD_RETURNDC | PD_PRINTTOFILE;
577     pd.nFromPage = 1;
578     pd.nToPage = 1;
579     pd.nCopies = 1;
580 
581     if (!PrintDlgA(&pd))
582     {
583         skip("No default printer available.\n");
584         goto end;
585     }
586     GlobalFree(pd.hDevMode);
587     GlobalFree(pd.hDevNames);
588 
589     ok(pd.hDC != NULL, "PrintDlg didn't return a DC.\n");
590     if (!(print_dc = pd.hDC))
591         goto end;
592 
593     ok(SetAbortProc(print_dc, abort_proc) > 0, "SetAbortProc failed\n");
594     ok(!abort_proc_called, "AbortProc got called unexpectedly by SetAbortProc.\n");
595     abort_proc_called = FALSE;
596 
597     doc_info.cbSize = sizeof(doc_info);
598     doc_info.lpszDocName = "Some document";
599     doc_info.lpszOutput = filename;
600 
601     job_id = StartDocA(print_dc, &doc_info);
602 
603     ok(job_id > 0 ||
604        GetLastError() == ERROR_SPL_NO_STARTDOC, /* Vista can fail with this error when using the XPS driver */
605        "StartDocA failed ret %d gle %d\n", job_id, GetLastError());
606 
607     if(job_id <= 0)
608     {
609         skip("StartDoc failed\n");
610         goto end;
611     }
612 
613     /* StartDoc may or may not call abort proc */
614 
615     abort_proc_called = FALSE;
616     ok(StartPage(print_dc) > 0, "StartPage failed\n");
617     ok(!abort_proc_called, "AbortProc got called unexpectedly by StartPage.\n");
618     abort_proc_called = FALSE;
619 
620     /* following functions sometimes call abort proc too */
621     ok(FillRect(print_dc, &rect, (HBRUSH)(COLOR_BACKGROUND + 1)), "FillRect failed\n");
622     ok(EndPage(print_dc) > 0, "EndPage failed\n");
623     ok(EndDoc(print_dc) > 0, "EndDoc failed\n");
624 
625     abort_proc_called = FALSE;
626     ok(DeleteDC(print_dc), "DeleteDC failed\n");
627     ok(!abort_proc_called, "AbortProc got called unexpectedly by DeleteDC.\n");
628     abort_proc_called = FALSE;
629 
630 end:
631     SetLastError(0xdeadbeef);
632     if(!DeleteFileA(filename))
633         trace("Failed to delete temporary file (err = %x)\n", GetLastError());
634 }
635 
636 /* ########################### */
637 
638 START_TEST(printdlg)
639 {
640     hcomdlg32 = GetModuleHandleA("comdlg32.dll");
641     pPrintDlgExW = (void *) GetProcAddress(hcomdlg32, "PrintDlgExW");
642 
643     test_PageSetupDlgA();
644     test_PrintDlgA();
645     test_PrintDlgExW();
646     test_abort_proc();
647 }
648