| /* |
| * Unit test suite for comdlg32 API functions: printer dialogs |
| * |
| * Copyright 2006-2007 Detlef Riekenberg |
| * Copyright 2013 Dmitry Timoshkov |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| * |
| */ |
| |
| #define COBJMACROS |
| #define CONST_VTABLE |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winerror.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "objbase.h" |
| |
| #include "cderr.h" |
| #include "commdlg.h" |
| #include "dlgs.h" |
| #include "winspool.h" |
| |
| #include "wine/test.h" |
| |
| /* ########################### */ |
| |
| extern const IID IID_IObjectWithSite; |
| |
| static HMODULE hcomdlg32; |
| static HRESULT (WINAPI * pPrintDlgExW)(LPPRINTDLGEXW); |
| |
| /* ########################### */ |
| |
| static const CHAR emptyA[] = ""; |
| static const CHAR PrinterPortsA[] = "PrinterPorts"; |
| |
| /* ########################### */ |
| |
| static void test_PageSetupDlgA(void) |
| { |
| LPPAGESETUPDLGA pDlg; |
| DWORD res; |
| |
| pDlg = HeapAlloc(GetProcessHeap(), 0, (sizeof(PAGESETUPDLGA)) * 2); |
| if (!pDlg) return; |
| |
| SetLastError(0xdeadbeef); |
| res = PageSetupDlgA(NULL); |
| ok( !res && (CommDlgExtendedError() == CDERR_INITIALIZATION), |
| "returned %u with %u and 0x%x (expected '0' and " |
| "CDERR_INITIALIZATION)\n", res, GetLastError(), CommDlgExtendedError()); |
| |
| ZeroMemory(pDlg, sizeof(PAGESETUPDLGA)); |
| pDlg->lStructSize = sizeof(PAGESETUPDLGA) -1; |
| SetLastError(0xdeadbeef); |
| res = PageSetupDlgA(pDlg); |
| ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE), |
| "returned %u with %u and 0x%x (expected '0' and " |
| "CDERR_STRUCTSIZE)\n", res, GetLastError(), CommDlgExtendedError()); |
| |
| ZeroMemory(pDlg, sizeof(PAGESETUPDLGA)); |
| pDlg->lStructSize = sizeof(PAGESETUPDLGA) +1; |
| pDlg->Flags = PSD_RETURNDEFAULT; |
| SetLastError(0xdeadbeef); |
| res = PageSetupDlgA(pDlg); |
| ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE), |
| "returned %u with %u and 0x%x (expected '0' and CDERR_STRUCTSIZE)\n", |
| res, GetLastError(), CommDlgExtendedError()); |
| |
| |
| ZeroMemory(pDlg, sizeof(PAGESETUPDLGA)); |
| pDlg->lStructSize = sizeof(PAGESETUPDLGA); |
| pDlg->Flags = PSD_RETURNDEFAULT | PSD_NOWARNING; |
| SetLastError(0xdeadbeef); |
| res = PageSetupDlgA(pDlg); |
| ok( res || (CommDlgExtendedError() == PDERR_NODEFAULTPRN), |
| "returned %u with %u and 0x%x (expected '!= 0' or '0' and " |
| "PDERR_NODEFAULTPRN)\n", res, GetLastError(), CommDlgExtendedError()); |
| |
| if (!res && (CommDlgExtendedError() == PDERR_NODEFAULTPRN)) { |
| skip("No printer configured.\n"); |
| HeapFree(GetProcessHeap(), 0, pDlg); |
| return; |
| } |
| |
| ok( pDlg->hDevMode && pDlg->hDevNames, |
| "got %p and %p (expected '!= NULL' for both)\n", |
| pDlg->hDevMode, pDlg->hDevNames); |
| |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| |
| HeapFree(GetProcessHeap(), 0, pDlg); |
| |
| } |
| |
| /* ########################### */ |
| |
| static UINT_PTR CALLBACK print_hook_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp) |
| { |
| if (msg == WM_INITDIALOG) |
| { |
| /* some driver popup a dialog and hung the test or silently limit the number of copies, |
| when trying to set more than 999 copies */ |
| SetDlgItemInt(hdlg, edt3, 123, FALSE); |
| PostMessageA(hdlg, WM_COMMAND, IDOK, FALSE); |
| } |
| return 0; |
| } |
| |
| static void test_PrintDlgA(void) |
| { |
| DWORD res, n_copies = 0; |
| LPPRINTDLGA pDlg; |
| DEVNAMES *pDevNames; |
| LPCSTR driver; |
| LPCSTR device; |
| LPCSTR port; |
| CHAR buffer[MAX_PATH]; |
| LPSTR ptr; |
| DEVMODEA *dm; |
| |
| pDlg = HeapAlloc(GetProcessHeap(), 0, (sizeof(PRINTDLGA)) * 2); |
| if (!pDlg) return; |
| |
| |
| /* will crash with unpatched wine */ |
| SetLastError(0xdeadbeef); |
| res = PrintDlgA(NULL); |
| ok( !res && (CommDlgExtendedError() == CDERR_INITIALIZATION), |
| "returned %d with 0x%x and 0x%x (expected '0' and " |
| "CDERR_INITIALIZATION)\n", res, GetLastError(), CommDlgExtendedError()); |
| |
| ZeroMemory(pDlg, sizeof(PRINTDLGA)); |
| pDlg->lStructSize = sizeof(PRINTDLGA) - 1; |
| SetLastError(0xdeadbeef); |
| res = PrintDlgA(pDlg); |
| ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE), |
| "returned %d with 0x%x and 0x%x (expected '0' and " |
| "CDERR_STRUCTSIZE)\n", res, GetLastError(), CommDlgExtendedError()); |
| |
| ZeroMemory(pDlg, sizeof(PRINTDLGA)); |
| pDlg->lStructSize = sizeof(PRINTDLGA) + 1; |
| pDlg->Flags = PD_RETURNDEFAULT; |
| SetLastError(0xdeadbeef); |
| res = PrintDlgA(pDlg); |
| ok( !res && (CommDlgExtendedError() == CDERR_STRUCTSIZE), |
| "returned %u with %u and 0x%x (expected '0' and " |
| "CDERR_STRUCTSIZE)\n", res, GetLastError(), CommDlgExtendedError()); |
| |
| |
| ZeroMemory(pDlg, sizeof(PRINTDLGA)); |
| pDlg->lStructSize = sizeof(PRINTDLGA); |
| pDlg->Flags = PD_RETURNDEFAULT; |
| SetLastError(0xdeadbeef); |
| res = PrintDlgA(pDlg); |
| ok( res || (CommDlgExtendedError() == PDERR_NODEFAULTPRN), |
| "returned %d with 0x%x and 0x%x (expected '!= 0' or '0' and " |
| "PDERR_NODEFAULTPRN)\n", res, GetLastError(), CommDlgExtendedError()); |
| |
| if (!res && (CommDlgExtendedError() == PDERR_NODEFAULTPRN)) { |
| skip("No printer configured.\n"); |
| HeapFree(GetProcessHeap(), 0, pDlg); |
| return; |
| } |
| |
| ok(pDlg->hDevNames != NULL, "(expected '!= NULL')\n"); |
| pDevNames = GlobalLock(pDlg->hDevNames); |
| ok(pDevNames != NULL, "(expected '!= NULL')\n"); |
| |
| if (pDevNames) { |
| ok(pDevNames->wDriverOffset, "(expected '!= 0' for wDriverOffset)\n"); |
| ok(pDevNames->wDeviceOffset, "(expected '!= 0' for wDeviceOffset)\n"); |
| ok(pDevNames->wOutputOffset, "(expected '!= 0' for wOutputOffset)\n"); |
| ok(pDevNames->wDefault == DN_DEFAULTPRN, "got 0x%x (expected DN_DEFAULTPRN)\n", pDevNames->wDefault); |
| |
| driver = (LPCSTR)pDevNames + pDevNames->wDriverOffset; |
| device = (LPCSTR)pDevNames + pDevNames->wDeviceOffset; |
| port = (LPCSTR)pDevNames + pDevNames->wOutputOffset; |
| trace("driver '%s' device '%s' port '%s'\n", driver, device, port); |
| |
| /* The Driver Entry does not include a Path */ |
| ptr = strrchr(driver, '\\'); |
| ok( ptr == NULL, "got %p for '%s' (expected NULL for a simple name)\n", ptr, driver); |
| |
| /* The Driver Entry does not have an extension (fixed to ".drv") */ |
| ptr = strrchr(driver, '.'); |
| todo_wine { |
| ok( ptr == NULL, "got %p for '%s' (expected NULL for no extension)\n", ptr, driver); |
| } |
| |
| |
| buffer[0] = '\0'; |
| SetLastError(0xdeadbeef); |
| res = GetProfileStringA(PrinterPortsA, device, emptyA, buffer, sizeof(buffer)); |
| ptr = strchr(buffer, ','); |
| ok( (res > 1) && (ptr != NULL), |
| "got %u with %u and %p for '%s' (expected '>1' and '!= NULL')\n", |
| res, GetLastError(), ptr, buffer); |
| |
| if (ptr) ptr[0] = '\0'; |
| ok( lstrcmpiA(driver, buffer) == 0, |
| "got driver '%s' (expected '%s')\n", driver, buffer); |
| |
| n_copies = DeviceCapabilitiesA(device, port, DC_COPIES, NULL, NULL); |
| ok(n_copies > 0, "DeviceCapabilities(DC_COPIES) failed\n"); |
| } |
| |
| GlobalUnlock(pDlg->hDevNames); |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| |
| /* if device doesn't support printing of multiple copies then |
| * an attempt to set number of copies > 1 in print dialog would |
| * cause the PrintDlg under Windows display the MessageBox and |
| * the test will hang waiting for user response. |
| */ |
| if (n_copies > 1) |
| { |
| ZeroMemory(pDlg, sizeof(*pDlg)); |
| pDlg->lStructSize = sizeof(*pDlg); |
| pDlg->Flags = PD_ENABLEPRINTHOOK; |
| pDlg->lpfnPrintHook = print_hook_proc; |
| res = PrintDlgA(pDlg); |
| ok(res, "PrintDlg error %#x\n", CommDlgExtendedError()); |
| /* Version of Microsoft XPS Document Writer driver shipped before Win7 |
| * reports that it can print multiple copies, but returns 1. |
| */ |
| ok(pDlg->nCopies == 123 || broken(pDlg->nCopies == 1), "expected nCopies 123, got %d\n", pDlg->nCopies); |
| ok(pDlg->hDevMode != 0, "hDevMode should not be 0\n"); |
| dm = GlobalLock(pDlg->hDevMode); |
| /* some broken drivers use always PD_USEDEVMODECOPIES */ |
| ok((S1(U1(*dm)).dmCopies == 1) || broken(S1(U1(*dm)).dmCopies == 123), |
| "expected dm->dmCopies 1, got %d\n", S1(U1(*dm)).dmCopies); |
| GlobalUnlock(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| |
| ZeroMemory(pDlg, sizeof(*pDlg)); |
| pDlg->lStructSize = sizeof(*pDlg); |
| pDlg->Flags = PD_ENABLEPRINTHOOK | PD_USEDEVMODECOPIES; |
| pDlg->lpfnPrintHook = print_hook_proc; |
| res = PrintDlgA(pDlg); |
| ok(res, "PrintDlg error %#x\n", CommDlgExtendedError()); |
| ok(pDlg->nCopies == 1, "expected nCopies 1, got %d\n", pDlg->nCopies); |
| ok(pDlg->hDevMode != 0, "hDevMode should not be 0\n"); |
| dm = GlobalLock(pDlg->hDevMode); |
| ok(S1(U1(*dm)).dmCopies == 123, "expected dm->dmCopies 123, got %d\n", S1(U1(*dm)).dmCopies); |
| GlobalUnlock(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| } |
| |
| HeapFree(GetProcessHeap(), 0, pDlg); |
| } |
| |
| /* ########################### */ |
| |
| static HRESULT WINAPI callback_QueryInterface(IPrintDialogCallback *iface, |
| REFIID riid, void **ppv) |
| { |
| ok(0, "callback_QueryInterface(%s): unexpected call\n", wine_dbgstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI callback_AddRef(IPrintDialogCallback *iface) |
| { |
| trace("callback_AddRef\n"); |
| return 2; |
| } |
| |
| static ULONG WINAPI callback_Release(IPrintDialogCallback *iface) |
| { |
| trace("callback_Release\n"); |
| return 1; |
| } |
| |
| static HRESULT WINAPI callback_InitDone(IPrintDialogCallback *iface) |
| { |
| trace("callback_InitDone\n"); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI callback_SelectionChange(IPrintDialogCallback *iface) |
| { |
| trace("callback_SelectionChange\n"); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI callback_HandleMessage(IPrintDialogCallback *iface, |
| HWND hdlg, UINT msg, WPARAM wp, LPARAM lp, LRESULT *res) |
| { |
| trace("callback_HandleMessage %p,%04x,%lx,%lx,%p\n", hdlg, msg, wp, lp, res); |
| /* *res = PD_RESULT_PRINT; */ |
| return S_OK; |
| } |
| |
| static const IPrintDialogCallbackVtbl callback_Vtbl = |
| { |
| callback_QueryInterface, |
| callback_AddRef, |
| callback_Release, |
| callback_InitDone, |
| callback_SelectionChange, |
| callback_HandleMessage |
| }; |
| |
| static IPrintDialogCallback callback = { &callback_Vtbl }; |
| |
| static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) |
| { |
| trace("unknown_QueryInterface %s\n", wine_dbgstr_guid(riid)); |
| |
| if (IsEqualGUID(riid, &IID_IPrintDialogCallback)) |
| { |
| *ppv = &callback; |
| return S_OK; |
| } |
| else if (IsEqualGUID(riid, &IID_IObjectWithSite)) |
| { |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| ok(0, "unexpected IID %s\n", wine_dbgstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI unknown_AddRef(IUnknown *iface) |
| { |
| trace("unknown_AddRef\n"); |
| return 2; |
| } |
| |
| static ULONG WINAPI unknown_Release(IUnknown *iface) |
| { |
| trace("unknown_Release\n"); |
| return 1; |
| } |
| |
| static const IUnknownVtbl unknown_Vtbl = |
| { |
| unknown_QueryInterface, |
| unknown_AddRef, |
| unknown_Release |
| }; |
| |
| static IUnknown unknown = { &unknown_Vtbl }; |
| |
| static void test_PrintDlgExW(void) |
| { |
| PRINTPAGERANGE pagerange[2]; |
| LPPRINTDLGEXW pDlg; |
| DEVNAMES *dn; |
| HRESULT res; |
| |
| /* PrintDlgEx not present before w2k */ |
| if (!pPrintDlgExW) { |
| skip("PrintDlgExW not available\n"); |
| return; |
| } |
| |
| if (0) /* Crashes on Win10 */ |
| { |
| /* Set CommDlgExtendedError != 0 */ |
| PrintDlgA(NULL); |
| SetLastError(0xdeadbeef); |
| res = pPrintDlgExW(NULL); |
| ok( (res == E_INVALIDARG), |
| "got 0x%x with %u and %u (expected 'E_INVALIDARG')\n", |
| res, GetLastError(), CommDlgExtendedError() ); |
| } |
| |
| pDlg = HeapAlloc(GetProcessHeap(), 0, (sizeof(PRINTDLGEXW)) + 8); |
| if (!pDlg) return; |
| |
| /* lStructSize must be exact */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW) - 1; |
| PrintDlgA(NULL); |
| SetLastError(0xdeadbeef); |
| res = pPrintDlgExW(pDlg); |
| ok( (res == E_INVALIDARG), |
| "got 0x%x with %u and %u (expected 'E_INVALIDARG')\n", |
| res, GetLastError(), CommDlgExtendedError()); |
| |
| |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW) + 1; |
| PrintDlgA(NULL); |
| SetLastError(0xdeadbeef); |
| res = pPrintDlgExW(pDlg); |
| ok( (res == E_INVALIDARG), |
| "got 0x%x with %u and %u (expected 'E_INVALIDARG')\n", |
| res, GetLastError(), CommDlgExtendedError()); |
| |
| |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| SetLastError(0xdeadbeef); |
| res = pPrintDlgExW(pDlg); |
| ok( (res == E_HANDLE), |
| "got 0x%x with %u and %u (expected 'E_HANDLE')\n", |
| res, GetLastError(), CommDlgExtendedError()); |
| |
| /* nStartPage must be START_PAGE_GENERAL for the general page or a valid property sheet index */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS; |
| res = pPrintDlgExW(pDlg); |
| ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res); |
| |
| /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| res = pPrintDlgExW(pDlg); |
| ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res); |
| |
| /* this is invalid: a valid lpPageRanges with 0 for nMaxPageRanges */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING; |
| pDlg->lpPageRanges = pagerange; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| res = pPrintDlgExW(pDlg); |
| ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res); |
| |
| /* this is invalid: NULL for lpPageRanges with a valid nMaxPageRanges */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING; |
| pDlg->nMaxPageRanges = 1; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| res = pPrintDlgExW(pDlg); |
| ok((res == E_INVALIDARG), "got 0x%x (expected 'E_INVALIDARG')\n", res); |
| |
| /* this works: lpPageRanges with a valid nMaxPageRanges */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING; |
| pDlg->nMaxPageRanges = 1; |
| pDlg->lpPageRanges = pagerange; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| res = pPrintDlgExW(pDlg); |
| if (res == E_FAIL) |
| { |
| skip("No printer configured.\n"); |
| HeapFree(GetProcessHeap(), 0, pDlg); |
| return; |
| } |
| |
| ok(res == S_OK, "got 0x%x (expected S_OK)\n", res); |
| |
| dn = GlobalLock(pDlg->hDevNames); |
| ok(dn != NULL, "expected '!= NULL' for GlobalLock(%p)\n",pDlg->hDevNames); |
| if (dn) |
| { |
| ok(dn->wDriverOffset, "(expected '!= 0' for wDriverOffset)\n"); |
| ok(dn->wDeviceOffset, "(expected '!= 0' for wDeviceOffset)\n"); |
| ok(dn->wOutputOffset, "(expected '!= 0' for wOutputOffset)\n"); |
| ok(dn->wDefault == DN_DEFAULTPRN, "got 0x%x (expected DN_DEFAULTPRN)\n", dn->wDefault); |
| |
| GlobalUnlock(pDlg->hDevNames); |
| } |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| |
| /* this works also: PD_NOPAGENUMS */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| res = pPrintDlgExW(pDlg); |
| ok(res == S_OK, "got 0x%x (expected S_OK)\n", res); |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| |
| /* this works: PD_RETURNDC with PD_RETURNDEFAULT */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS | PD_RETURNDC; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| res = pPrintDlgExW(pDlg); |
| ok(res == S_OK, "got 0x%x (expected S_OK)\n", res); |
| ok(pDlg->hDC != NULL, "HDC missing for PD_RETURNDC\n"); |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| DeleteDC(pDlg->hDC); |
| |
| /* this works: PD_RETURNIC with PD_RETURNDEFAULT */ |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_RETURNDEFAULT | PD_NOWARNING | PD_NOPAGENUMS | PD_RETURNIC; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| res = pPrintDlgExW(pDlg); |
| ok(res == S_OK, "got 0x%x (expected S_OK)\n", res); |
| ok(pDlg->hDC != NULL, "HDC missing for PD_RETURNIC\n"); |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| DeleteDC(pDlg->hDC); |
| |
| /* interactive PrintDlgEx tests */ |
| |
| if (!winetest_interactive) |
| { |
| skip("interactive PrintDlgEx tests (set WINETEST_INTERACTIVE=1)\n"); |
| HeapFree(GetProcessHeap(), 0, pDlg); |
| return; |
| } |
| |
| ZeroMemory(pDlg, sizeof(PRINTDLGEXW)); |
| pDlg->lStructSize = sizeof(PRINTDLGEXW); |
| pDlg->hwndOwner = GetDesktopWindow(); |
| pDlg->Flags = PD_NOPAGENUMS | PD_RETURNIC; |
| pDlg->nStartPage = START_PAGE_GENERAL; |
| pDlg->lpCallback = &unknown; |
| pDlg->dwResultAction = S_OK; |
| res = pPrintDlgExW(pDlg); |
| ok(res == S_OK, "got 0x%x (expected S_OK)\n", res); |
| ok(pDlg->dwResultAction == PD_RESULT_PRINT, "expected PD_RESULT_PRINT, got %#x\n", pDlg->dwResultAction); |
| ok(pDlg->hDC != NULL, "HDC missing for PD_RETURNIC\n"); |
| GlobalFree(pDlg->hDevMode); |
| GlobalFree(pDlg->hDevNames); |
| DeleteDC(pDlg->hDC); |
| |
| HeapFree(GetProcessHeap(), 0, pDlg); |
| } |
| |
| static BOOL abort_proc_called = FALSE; |
| static BOOL CALLBACK abort_proc(HDC hdc, int error) { return abort_proc_called = TRUE; } |
| static void test_abort_proc(void) |
| { |
| HDC print_dc; |
| RECT rect = {0, 0, 100, 100}; |
| DOCINFOA doc_info = {0}; |
| PRINTDLGA pd = {0}; |
| char filename[MAX_PATH]; |
| int job_id; |
| |
| if (!GetTempFileNameA(".", "prn", 0, filename)) |
| { |
| skip("Failed to create a temporary file name\n"); |
| return; |
| } |
| |
| pd.lStructSize = sizeof(pd); |
| pd.Flags = PD_RETURNDEFAULT | PD_ALLPAGES | PD_RETURNDC | PD_PRINTTOFILE; |
| pd.nFromPage = 1; |
| pd.nToPage = 1; |
| pd.nCopies = 1; |
| |
| if (!PrintDlgA(&pd)) |
| { |
| skip("No default printer available.\n"); |
| goto end; |
| } |
| GlobalFree(pd.hDevMode); |
| GlobalFree(pd.hDevNames); |
| |
| ok(pd.hDC != NULL, "PrintDlg didn't return a DC.\n"); |
| if (!(print_dc = pd.hDC)) |
| goto end; |
| |
| ok(SetAbortProc(print_dc, abort_proc) > 0, "SetAbortProc failed\n"); |
| ok(!abort_proc_called, "AbortProc got called unexpectedly by SetAbortProc.\n"); |
| abort_proc_called = FALSE; |
| |
| doc_info.cbSize = sizeof(doc_info); |
| doc_info.lpszDocName = "Some document"; |
| doc_info.lpszOutput = filename; |
| |
| job_id = StartDocA(print_dc, &doc_info); |
| |
| ok(job_id > 0 || |
| GetLastError() == ERROR_SPL_NO_STARTDOC, /* Vista can fail with this error when using the XPS driver */ |
| "StartDocA failed ret %d gle %d\n", job_id, GetLastError()); |
| |
| if(job_id <= 0) |
| { |
| skip("StartDoc failed\n"); |
| goto end; |
| } |
| |
| /* StartDoc may or may not call abort proc */ |
| |
| abort_proc_called = FALSE; |
| ok(StartPage(print_dc) > 0, "StartPage failed\n"); |
| ok(!abort_proc_called, "AbortProc got called unexpectedly by StartPage.\n"); |
| abort_proc_called = FALSE; |
| |
| /* following functions sometimes call abort proc too */ |
| ok(FillRect(print_dc, &rect, (HBRUSH)(COLOR_BACKGROUND + 1)), "FillRect failed\n"); |
| ok(EndPage(print_dc) > 0, "EndPage failed\n"); |
| ok(EndDoc(print_dc) > 0, "EndDoc failed\n"); |
| |
| abort_proc_called = FALSE; |
| ok(DeleteDC(print_dc), "DeleteDC failed\n"); |
| ok(!abort_proc_called, "AbortProc got called unexpectedly by DeleteDC.\n"); |
| abort_proc_called = FALSE; |
| |
| end: |
| SetLastError(0xdeadbeef); |
| if(!DeleteFileA(filename)) |
| trace("Failed to delete temporary file (err = %x)\n", GetLastError()); |
| } |
| |
| /* ########################### */ |
| |
| START_TEST(printdlg) |
| { |
| hcomdlg32 = GetModuleHandleA("comdlg32.dll"); |
| pPrintDlgExW = (void *) GetProcAddress(hcomdlg32, "PrintDlgExW"); |
| |
| test_PageSetupDlgA(); |
| test_PrintDlgA(); |
| test_PrintDlgExW(); |
| test_abort_proc(); |
| } |