1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:     ReactOS Print Spooler DLL API Tests
3c2c66affSColin Finck  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4c2c66affSColin Finck  * PURPOSE:     Tests for GetPrinterData(Ex)A/GetPrinterData(Ex)W/SetPrinterData(Ex)A/SetPrinterData(Ex)W
5c2c66affSColin Finck  * COPYRIGHT:   Copyright 2017 Colin Finck (colin@reactos.org)
6c2c66affSColin Finck  */
7c2c66affSColin Finck 
8c2c66affSColin Finck #include <apitest.h>
9c2c66affSColin Finck 
10c2c66affSColin Finck #define WIN32_NO_STATUS
11c2c66affSColin Finck #include <windef.h>
12c2c66affSColin Finck #include <winbase.h>
13c2c66affSColin Finck #include <wingdi.h>
14c2c66affSColin Finck #include <winspool.h>
15c2c66affSColin Finck #include <winreg.h>
16c2c66affSColin Finck 
17c2c66affSColin Finck /* From printing/include/spoolss.h */
18c2c66affSColin Finck #define MAX_PRINTER_NAME        220
19c2c66affSColin Finck 
20c2c66affSColin Finck typedef struct _SPLREG_VALUE
21c2c66affSColin Finck {
22c2c66affSColin Finck     PSTR pszName;
23c2c66affSColin Finck     PWSTR pwszName;
24c2c66affSColin Finck     DWORD dwType;
25c2c66affSColin Finck     DWORD cbNeededA;
26c2c66affSColin Finck     BOOL bSettable;
27c2c66affSColin Finck }
28c2c66affSColin Finck SPLREG_VALUE, *PSPLREG_VALUE;
29c2c66affSColin Finck 
30c2c66affSColin Finck SPLREG_VALUE SplRegValues[] = {
31c2c66affSColin Finck     { "DefaultSpoolDirectory", L"DefaultSpoolDirectory", REG_SZ, 0xFFFFFFFF, TRUE },
32c2c66affSColin Finck     { "PortThreadPriorityDefault", L"PortThreadPriorityDefault", REG_NONE, 4, FALSE },
33c2c66affSColin Finck     { "PortThreadPriority", L"PortThreadPriority", REG_DWORD, 4, TRUE },
34c2c66affSColin Finck     { "SchedulerThreadPriorityDefault", L"SchedulerThreadPriorityDefault", REG_NONE, 4, FALSE },
35c2c66affSColin Finck     { "SchedulerThreadPriority", L"SchedulerThreadPriority", REG_DWORD, 4, TRUE },
36c2c66affSColin Finck     { "BeepEnabled", L"BeepEnabled", REG_DWORD, 4, TRUE },
37c2c66affSColin Finck 
38c2c66affSColin Finck     /* These fail in Win8, probably removed since NT6:
39c2c66affSColin Finck 
40c2c66affSColin Finck     { "NetPopup", L"NetPopup", REG_DWORD, 4, TRUE },
41c2c66affSColin Finck     { "RetryPopup", L"RetryPopup", REG_DWORD, 4, TRUE },
42c2c66affSColin Finck     { "NetPopupToComputer", L"NetPopupToComputer", REG_DWORD, 4, TRUE },
43c2c66affSColin Finck 
44c2c66affSColin Finck     */
45c2c66affSColin Finck 
46c2c66affSColin Finck     { "EventLog", L"EventLog", REG_DWORD, 4, TRUE },
47c2c66affSColin Finck     { "MajorVersion", L"MajorVersion", REG_NONE, 4, FALSE },
48c2c66affSColin Finck     { "MinorVersion", L"MinorVersion", REG_NONE, 4, FALSE },
49c2c66affSColin Finck     { "Architecture", L"Architecture", REG_NONE, 0xFFFFFFFF, FALSE },
50c2c66affSColin Finck     { "OSVersion", L"OSVersion", REG_NONE, sizeof(OSVERSIONINFOA), FALSE },
51c2c66affSColin Finck     { "OSVersionEx", L"OSVersionEx", REG_NONE, sizeof(OSVERSIONINFOEXA), FALSE },
52c2c66affSColin Finck #if 0
53c2c66affSColin Finck     { "DsPresent", L"DsPresent", REG_DWORD, 4, FALSE },
54c2c66affSColin Finck     { "DsPresentForUser", L"DsPresentForUser", REG_DWORD, 4, FALSE },
55c2c66affSColin Finck #endif
56c2c66affSColin Finck     { "RemoteFax", L"RemoteFax", REG_NONE, 4, FALSE },
57c2c66affSColin Finck     { "RestartJobOnPoolError", L"RestartJobOnPoolError", REG_DWORD, 4, TRUE },
58c2c66affSColin Finck     { "RestartJobOnPoolEnabled", L"RestartJobOnPoolEnabled", REG_DWORD, 4, TRUE },
59*465745b6STimo Kreuzer #if 0 // FIXME: fails on WHS testbot with ERROR_INVALID_PARAMETER
60c2c66affSColin Finck     { "DNSMachineName", L"DNSMachineName", REG_SZ, 0xFFFFFFFF, FALSE },
61*465745b6STimo Kreuzer #endif
62c2c66affSColin Finck     { "AllowUserManageForms", L"AllowUserManageForms", REG_DWORD, 4, TRUE },
63c2c66affSColin Finck     { NULL, NULL, 0, 0, FALSE }
64c2c66affSColin Finck };
65c2c66affSColin Finck 
START_TEST(GetPrinterData)66c2c66affSColin Finck START_TEST(GetPrinterData)
67c2c66affSColin Finck {
68c2c66affSColin Finck     DWORD cbNeeded;
69c2c66affSColin Finck     DWORD cchDefaultPrinter;
70c2c66affSColin Finck     DWORD dwReturnCode;
71c2c66affSColin Finck     DWORD dwType;
72c2c66affSColin Finck     HANDLE hPrinter;
73c2c66affSColin Finck     PBYTE pDataA;
74c2c66affSColin Finck     PBYTE pDataW;
75c2c66affSColin Finck     PSPLREG_VALUE p;
76c2c66affSColin Finck     WCHAR wszDefaultPrinter[MAX_PRINTER_NAME + 1];
77c2c66affSColin Finck 
78c2c66affSColin Finck     // Don't supply any parameters, this has to fail with ERROR_INVALID_HANDLE!
79c2c66affSColin Finck     dwReturnCode = GetPrinterDataExW(NULL, NULL, NULL, NULL, NULL, 0, NULL);
80c2c66affSColin Finck     ok(dwReturnCode == ERROR_INVALID_HANDLE, "GetPrinterDataExW returns error %lu!\n", dwReturnCode);
81c2c66affSColin Finck 
82c2c66affSColin Finck     // Open a handle to the local print server.
83c2c66affSColin Finck     if (!OpenPrinterW(NULL, &hPrinter, NULL))
84c2c66affSColin Finck     {
85c2c66affSColin Finck         skip("Could not retrieve a handle to the local print server!\n");
86c2c66affSColin Finck         return;
87c2c66affSColin Finck     }
88c2c66affSColin Finck 
89c2c66affSColin Finck     // Now try with valid handle, but leave remaining parameters NULL.
90c2c66affSColin Finck     dwReturnCode = GetPrinterDataExW(hPrinter, NULL, NULL, NULL, NULL, 0, NULL);
91c2c66affSColin Finck     ok(dwReturnCode == RPC_X_NULL_REF_POINTER, "GetPrinterDataExW returns error %lu!\n", dwReturnCode);
92c2c66affSColin Finck 
93c2c66affSColin Finck     // Try all valid Print Server data values.
94c2c66affSColin Finck     for (p = SplRegValues; p->pszName; p++)
95c2c66affSColin Finck     {
96c2c66affSColin Finck         // Try the ANSI version of the function.
97c2c66affSColin Finck         dwType = 0xDEADBEEF;
98c2c66affSColin Finck         dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, &dwType, NULL, 0, &cbNeeded);
99c2c66affSColin Finck         ok(dwReturnCode == ERROR_MORE_DATA || dwReturnCode == ERROR_FILE_NOT_FOUND, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
100c2c66affSColin Finck         if (dwReturnCode != ERROR_MORE_DATA)
101c2c66affSColin Finck             continue;
102c2c66affSColin Finck 
103c2c66affSColin Finck         ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName);
104c2c66affSColin Finck 
105c2c66affSColin Finck         if (p->cbNeededA < 0xFFFFFFFF)
106c2c66affSColin Finck             ok(cbNeeded == p->cbNeededA, "cbNeeded is %lu for \"%s\", but expected %lu!\n", cbNeeded, p->pszName, p->cbNeededA);
107c2c66affSColin Finck         else
108c2c66affSColin Finck             ok(cbNeeded > 0, "cbNeeded is 0 for \"%s\"!\n", p->pszName);
109c2c66affSColin Finck 
110c2c66affSColin Finck         pDataA = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
111c2c66affSColin Finck         dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, NULL, pDataA, cbNeeded, &cbNeeded);
112c2c66affSColin Finck         ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
113c2c66affSColin Finck 
114c2c66affSColin Finck         // Try the Unicode version of the function too.
115c2c66affSColin Finck         dwType = 0xDEADBEEF;
116c2c66affSColin Finck         dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, &dwType, NULL, 0, &cbNeeded);
117c2c66affSColin Finck         ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
118c2c66affSColin Finck         ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName);
119c2c66affSColin Finck 
120c2c66affSColin Finck         pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
121c2c66affSColin Finck         dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, NULL, pDataW, cbNeeded, &cbNeeded);
122c2c66affSColin Finck         ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
123c2c66affSColin Finck 
124c2c66affSColin Finck         // Verify that OSVERSIONINFO structures are correctly returned.
125c2c66affSColin Finck         if (strcmp(p->pszName, "OSVersion") == 0)
126c2c66affSColin Finck         {
127c2c66affSColin Finck             POSVERSIONINFOA pOSVersionInfoA = (POSVERSIONINFOA)pDataA;
128c2c66affSColin Finck             POSVERSIONINFOW pOSVersionInfoW = (POSVERSIONINFOW)pDataW;
129c2c66affSColin Finck             ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize);
130c2c66affSColin Finck             ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize);
131c2c66affSColin Finck         }
132c2c66affSColin Finck         else if (strcmp(p->pszName, "OSVersionEx") == 0)
133c2c66affSColin Finck         {
134c2c66affSColin Finck             POSVERSIONINFOEXA pOSVersionInfoA = (POSVERSIONINFOEXA)pDataA;
135c2c66affSColin Finck             POSVERSIONINFOEXW pOSVersionInfoW = (POSVERSIONINFOEXW)pDataW;
136c2c66affSColin Finck             ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize);
137c2c66affSColin Finck             ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize);
138c2c66affSColin Finck         }
139c2c66affSColin Finck 
140c2c66affSColin Finck         // Shortly test SetPrinterDataExW by setting the same data we just retrieved.
141c2c66affSColin Finck         if (p->bSettable)
142c2c66affSColin Finck         {
143c2c66affSColin Finck             dwReturnCode = SetPrinterDataExW(hPrinter, NULL, p->pwszName, dwType, pDataW, cbNeeded);
144c2c66affSColin Finck             ok(dwReturnCode == ERROR_SUCCESS, "SetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
145c2c66affSColin Finck         }
146c2c66affSColin Finck 
147c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, pDataA);
148c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, pDataW);
149c2c66affSColin Finck     }
150c2c66affSColin Finck 
151c2c66affSColin Finck     // Try an invalid one.
152c2c66affSColin Finck     dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Invalid", NULL, NULL, 0, &cbNeeded);
153c2c66affSColin Finck     ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
154c2c66affSColin Finck 
155c2c66affSColin Finck     ClosePrinter(hPrinter);
156c2c66affSColin Finck 
157c2c66affSColin Finck     // Open a handle to the default printer.
158c2c66affSColin Finck     cchDefaultPrinter = _countof(wszDefaultPrinter);
159c2c66affSColin Finck     ok(GetDefaultPrinterW(wszDefaultPrinter, &cchDefaultPrinter), "GetDefaultPrinterW returns FALSE and requires %lu characters!\n", cchDefaultPrinter);
160c2c66affSColin Finck     if (!OpenPrinterW(wszDefaultPrinter, &hPrinter, NULL))
161c2c66affSColin Finck     {
162c2c66affSColin Finck         skip("Could not retrieve a handle to the default printer!\n");
163c2c66affSColin Finck         return;
164c2c66affSColin Finck     }
165c2c66affSColin Finck 
166c2c66affSColin Finck     // Using NULL or L"" for pKeyName on a Printer handle yields ERROR_INVALID_PARAMETER.
167c2c66affSColin Finck     dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Name", NULL, NULL, 0, &cbNeeded);
168c2c66affSColin Finck     ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
169c2c66affSColin Finck     dwReturnCode = GetPrinterDataExW(hPrinter, L"", L"Name", NULL, NULL, 0, &cbNeeded);
170c2c66affSColin Finck     ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
171c2c66affSColin Finck 
172c2c66affSColin Finck     // Using L"\\" allows us to examine the contents of the main printer key anyway.
173c2c66affSColin Finck     dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", &dwType, NULL, 0, &cbNeeded);
174c2c66affSColin Finck     ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
175c2c66affSColin Finck     ok(dwType == REG_SZ, "dwType is %lu!\n", dwType);
176c2c66affSColin Finck     ok(cbNeeded > 0, "cbNeeded is 0!\n");
177c2c66affSColin Finck 
178c2c66affSColin Finck     pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
179c2c66affSColin Finck     dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", NULL, pDataW, cbNeeded, &cbNeeded);
180c2c66affSColin Finck     ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
181c2c66affSColin Finck 
182c2c66affSColin Finck     // The following test fails if the default printer is a remote printer.
183c2c66affSColin Finck     ok(wcscmp((PWSTR)pDataW, wszDefaultPrinter) == 0, "pDataW is \"%S\", default printer is \"%S\"!\n", (PWSTR)pDataW, wszDefaultPrinter);
184c2c66affSColin Finck 
185c2c66affSColin Finck     // SetPrinterDataExW should return ERROR_ACCESS_DENIED when attempting to set the Name.
186c2c66affSColin Finck     dwReturnCode = SetPrinterDataExW(hPrinter, L"\\", L"Name", REG_SZ, pDataW, cbNeeded);
187c2c66affSColin Finck     ok(dwReturnCode == ERROR_ACCESS_DENIED, "SetPrinterDataExW returns %lu!\n", dwReturnCode);
188c2c66affSColin Finck 
189c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, pDataW);
190c2c66affSColin Finck }
191