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