ReactOS  0.4.15-dev-309-g7c8d563
GetPrinterData.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Print Spooler DLL API Tests
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Tests for GetPrinterData(Ex)A/GetPrinterData(Ex)W/SetPrinterData(Ex)A/SetPrinterData(Ex)W
5  * COPYRIGHT: Copyright 2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include <apitest.h>
9 
10 #define WIN32_NO_STATUS
11 #include <windef.h>
12 #include <winbase.h>
13 #include <wingdi.h>
14 #include <winspool.h>
15 #include <winreg.h>
16 
17 /* From printing/include/spoolss.h */
18 #define MAX_PRINTER_NAME 220
19 
20 typedef struct _SPLREG_VALUE
21 {
27 }
29 
31  { "DefaultSpoolDirectory", L"DefaultSpoolDirectory", REG_SZ, 0xFFFFFFFF, TRUE },
32  { "PortThreadPriorityDefault", L"PortThreadPriorityDefault", REG_NONE, 4, FALSE },
33  { "PortThreadPriority", L"PortThreadPriority", REG_DWORD, 4, TRUE },
34  { "SchedulerThreadPriorityDefault", L"SchedulerThreadPriorityDefault", REG_NONE, 4, FALSE },
35  { "SchedulerThreadPriority", L"SchedulerThreadPriority", REG_DWORD, 4, TRUE },
36  { "BeepEnabled", L"BeepEnabled", REG_DWORD, 4, TRUE },
37 
38  /* These fail in Win8, probably removed since NT6:
39 
40  { "NetPopup", L"NetPopup", REG_DWORD, 4, TRUE },
41  { "RetryPopup", L"RetryPopup", REG_DWORD, 4, TRUE },
42  { "NetPopupToComputer", L"NetPopupToComputer", REG_DWORD, 4, TRUE },
43 
44  */
45 
46  { "EventLog", L"EventLog", REG_DWORD, 4, TRUE },
47  { "MajorVersion", L"MajorVersion", REG_NONE, 4, FALSE },
48  { "MinorVersion", L"MinorVersion", REG_NONE, 4, FALSE },
49  { "Architecture", L"Architecture", REG_NONE, 0xFFFFFFFF, FALSE },
50  { "OSVersion", L"OSVersion", REG_NONE, sizeof(OSVERSIONINFOA), FALSE },
51  { "OSVersionEx", L"OSVersionEx", REG_NONE, sizeof(OSVERSIONINFOEXA), FALSE },
52 #if 0
53  { "DsPresent", L"DsPresent", REG_DWORD, 4, FALSE },
54  { "DsPresentForUser", L"DsPresentForUser", REG_DWORD, 4, FALSE },
55 #endif
56  { "RemoteFax", L"RemoteFax", REG_NONE, 4, FALSE },
57  { "RestartJobOnPoolError", L"RestartJobOnPoolError", REG_DWORD, 4, TRUE },
58  { "RestartJobOnPoolEnabled", L"RestartJobOnPoolEnabled", REG_DWORD, 4, TRUE },
59 #if 0 // FIXME: fails on WHS testbot with ERROR_INVALID_PARAMETER
60  { "DNSMachineName", L"DNSMachineName", REG_SZ, 0xFFFFFFFF, FALSE },
61 #endif
62  { "AllowUserManageForms", L"AllowUserManageForms", REG_DWORD, 4, TRUE },
63  { NULL, NULL, 0, 0, FALSE }
64 };
65 
67 {
68  DWORD cbNeeded;
69  DWORD cchDefaultPrinter;
70  DWORD dwReturnCode;
71  DWORD dwType;
72  HANDLE hPrinter;
73  PBYTE pDataA;
74  PBYTE pDataW;
76  WCHAR wszDefaultPrinter[MAX_PRINTER_NAME + 1];
77 
78  // Don't supply any parameters, this has to fail with ERROR_INVALID_HANDLE!
79  dwReturnCode = GetPrinterDataExW(NULL, NULL, NULL, NULL, NULL, 0, NULL);
80  ok(dwReturnCode == ERROR_INVALID_HANDLE, "GetPrinterDataExW returns error %lu!\n", dwReturnCode);
81 
82  // Open a handle to the local print server.
83  if (!OpenPrinterW(NULL, &hPrinter, NULL))
84  {
85  skip("Could not retrieve a handle to the local print server!\n");
86  return;
87  }
88 
89  // Now try with valid handle, but leave remaining parameters NULL.
90  dwReturnCode = GetPrinterDataExW(hPrinter, NULL, NULL, NULL, NULL, 0, NULL);
91  ok(dwReturnCode == RPC_X_NULL_REF_POINTER, "GetPrinterDataExW returns error %lu!\n", dwReturnCode);
92 
93  // Try all valid Print Server data values.
94  for (p = SplRegValues; p->pszName; p++)
95  {
96  // Try the ANSI version of the function.
97  dwType = 0xDEADBEEF;
98  dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, &dwType, NULL, 0, &cbNeeded);
99  ok(dwReturnCode == ERROR_MORE_DATA || dwReturnCode == ERROR_FILE_NOT_FOUND, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
100  if (dwReturnCode != ERROR_MORE_DATA)
101  continue;
102 
103  ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName);
104 
105  if (p->cbNeededA < 0xFFFFFFFF)
106  ok(cbNeeded == p->cbNeededA, "cbNeeded is %lu for \"%s\", but expected %lu!\n", cbNeeded, p->pszName, p->cbNeededA);
107  else
108  ok(cbNeeded > 0, "cbNeeded is 0 for \"%s\"!\n", p->pszName);
109 
110  pDataA = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
111  dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, NULL, pDataA, cbNeeded, &cbNeeded);
112  ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
113 
114  // Try the Unicode version of the function too.
115  dwType = 0xDEADBEEF;
116  dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, &dwType, NULL, 0, &cbNeeded);
117  ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
118  ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName);
119 
120  pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
121  dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, NULL, pDataW, cbNeeded, &cbNeeded);
122  ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
123 
124  // Verify that OSVERSIONINFO structures are correctly returned.
125  if (strcmp(p->pszName, "OSVersion") == 0)
126  {
127  POSVERSIONINFOA pOSVersionInfoA = (POSVERSIONINFOA)pDataA;
128  POSVERSIONINFOW pOSVersionInfoW = (POSVERSIONINFOW)pDataW;
129  ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize);
130  ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize);
131  }
132  else if (strcmp(p->pszName, "OSVersionEx") == 0)
133  {
134  POSVERSIONINFOEXA pOSVersionInfoA = (POSVERSIONINFOEXA)pDataA;
135  POSVERSIONINFOEXW pOSVersionInfoW = (POSVERSIONINFOEXW)pDataW;
136  ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize);
137  ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize);
138  }
139 
140  // Shortly test SetPrinterDataExW by setting the same data we just retrieved.
141  if (p->bSettable)
142  {
143  dwReturnCode = SetPrinterDataExW(hPrinter, NULL, p->pwszName, dwType, pDataW, cbNeeded);
144  ok(dwReturnCode == ERROR_SUCCESS, "SetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
145  }
146 
147  HeapFree(GetProcessHeap(), 0, pDataA);
148  HeapFree(GetProcessHeap(), 0, pDataW);
149  }
150 
151  // Try an invalid one.
152  dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Invalid", NULL, NULL, 0, &cbNeeded);
153  ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
154 
155  ClosePrinter(hPrinter);
156 
157  // Open a handle to the default printer.
158  cchDefaultPrinter = _countof(wszDefaultPrinter);
159  ok(GetDefaultPrinterW(wszDefaultPrinter, &cchDefaultPrinter), "GetDefaultPrinterW returns FALSE and requires %lu characters!\n", cchDefaultPrinter);
160  if (!OpenPrinterW(wszDefaultPrinter, &hPrinter, NULL))
161  {
162  skip("Could not retrieve a handle to the default printer!\n");
163  return;
164  }
165 
166  // Using NULL or L"" for pKeyName on a Printer handle yields ERROR_INVALID_PARAMETER.
167  dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Name", NULL, NULL, 0, &cbNeeded);
168  ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
169  dwReturnCode = GetPrinterDataExW(hPrinter, L"", L"Name", NULL, NULL, 0, &cbNeeded);
170  ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
171 
172  // Using L"\\" allows us to examine the contents of the main printer key anyway.
173  dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", &dwType, NULL, 0, &cbNeeded);
174  ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
175  ok(dwType == REG_SZ, "dwType is %lu!\n", dwType);
176  ok(cbNeeded > 0, "cbNeeded is 0!\n");
177 
178  pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
179  dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", NULL, pDataW, cbNeeded, &cbNeeded);
180  ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
181 
182  // The following test fails if the default printer is a remote printer.
183  ok(wcscmp((PWSTR)pDataW, wszDefaultPrinter) == 0, "pDataW is \"%S\", default printer is \"%S\"!\n", (PWSTR)pDataW, wszDefaultPrinter);
184 
185  // SetPrinterDataExW should return ERROR_ACCESS_DENIED when attempting to set the Name.
186  dwReturnCode = SetPrinterDataExW(hPrinter, L"\\", L"Name", REG_SZ, pDataW, cbNeeded);
187  ok(dwReturnCode == ERROR_ACCESS_DENIED, "SetPrinterDataExW returns %lu!\n", dwReturnCode);
188 
189  HeapFree(GetProcessHeap(), 0, pDataW);
190 }
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
ULONG dwOSVersionInfoSize
Definition: rtltypes.h:265
#define TRUE
Definition: types.h:120
struct _SPLREG_VALUE * PSPLREG_VALUE
#define ERROR_SUCCESS
Definition: deptool.c:10
#define RPC_X_NULL_REF_POINTER
Definition: winerror.h:1087
struct _SPLREG_VALUE SPLREG_VALUE
WINBOOL WINAPI GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
Definition: printers.c:1027
#define GetPrinterData
Definition: winspool.h:852
DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
Definition: printerdata.c:130
struct _OSVERSIONINFOEXW * POSVERSIONINFOEXW
uint16_t * PWSTR
Definition: typedefs.h:55
struct _OSVERSIONINFOW * POSVERSIONINFOW
#define ERROR_INVALID_HANDLE
Definition: compat.h:88
START_TEST(GetPrinterData)
#define MAX_PRINTER_NAME
DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
Definition: printerdata.c:11
#define ERROR_ACCESS_DENIED
Definition: compat.h:87
unsigned int BOOL
Definition: ntddk_ex.h:94
WINBOOL WINAPI ClosePrinter(HANDLE hPrinter)
Definition: printers.c:12
smooth NULL
Definition: ftsmooth.c:416
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
ULONG dwOSVersionInfoSize
Definition: rtltypes.h:233
struct _OSVERSIONINFOEXA OSVERSIONINFOEXA
ULONG dwOSVersionInfoSize
Definition: rtltypes.h:251
#define GetProcessHeap()
Definition: compat.h:404
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define _countof(array)
Definition: sndvol32.h:68
ULONG dwOSVersionInfoSize
Definition: rtltypes.h:242
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
Definition: printerdata.c:38
static const WCHAR L[]
Definition: oid.c:1250
#define ERROR_MORE_DATA
Definition: dderror.h:13
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
WINBOOL WINAPI OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
Definition: printers.c:1973
struct _OSVERSIONINFOA OSVERSIONINFOA
struct _OSVERSIONINFOA * POSVERSIONINFOA
#define ok(value,...)
Definition: atltest.h:57
signed char * PSTR
Definition: retypes.h:7
struct _OSVERSIONINFOEXA * POSVERSIONINFOEXA
#define skip(...)
Definition: atltest.h:64
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define REG_NONE
Definition: nt_native.h:1492
GLfloat GLfloat p
Definition: glext.h:8902
#define REG_DWORD
Definition: sdbapi.c:596
BYTE * PBYTE
Definition: pedump.c:66
#define HeapFree(x, y, z)
Definition: compat.h:403
SPLREG_VALUE SplRegValues[]
#define REG_SZ
Definition: layer.c:22