ReactOS 0.4.15-dev-5672-gf73ac17
EnumPrinters.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 EnumPrintersA/EnumPrintersW
5 * COPYRIGHT: Copyright 2015-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
17{
18 BYTE TempBuffer[50];
19 BYTE ZeroBuffer[50] = { 0 };
20 DWORD cbNeeded;
21 DWORD cbTemp;
22 DWORD cchComputerName;
23 DWORD dwReturned;
24 PPRINTER_INFO_1W pPrinterInfo1;
25 PVOID pMem;
27 WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 2 + 1];
28
29 wszComputerName[0] = L'\\';
30 wszComputerName[1] = L'\\';
31 cchComputerName = MAX_COMPUTERNAME_LENGTH + 1;
32 if (!GetComputerNameW(&wszComputerName[2], &cchComputerName))
33 {
34 skip("GetComputerNameW failed with error %lu!\n", GetLastError());
35 return;
36 }
37
38 cchComputerName += 2;
39
40 // Verify that EnumPrintersW returns success and zeroes all input variables even though no flag has been specified.
41 memset(TempBuffer, 0xDE, sizeof(TempBuffer));
42 cbNeeded = 0xDEADBEEF;
43 dwReturned = 0xDEADBEEF;
44 SetLastError(0xDEADBEEF);
45 ok(EnumPrintersW(0, NULL, 1, TempBuffer, sizeof(TempBuffer), &cbNeeded, &dwReturned), "EnumPrintersW returns FALSE\n");
46 ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu!\n", GetLastError());
47 ok(memcmp(TempBuffer, ZeroBuffer, sizeof(TempBuffer)) == 0, "TempBuffer has not been zeroed!\n");
48 ok(cbNeeded == 0, "cbNeeded is %lu!\n", cbNeeded);
49 ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
50
51 // Level 5 is the highest supported under Windows Server 2003. Higher levels need to fail and leave the variables untouched!
52 cbNeeded = 0xDEADBEEF;
53 dwReturned = 0xDEADBEEF;
54 SetLastError(0xDEADBEEF);
55 ok(!EnumPrintersW(0, NULL, 6, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE!\n");
56 ok(GetLastError() == ERROR_INVALID_LEVEL, "EnumPrintersW returns error %lu!\n", GetLastError());
57 ok(cbNeeded == 0xDEADBEEF, "cbNeeded is %lu!\n", cbNeeded);
58 ok(dwReturned == 0xDEADBEEF, "dwReturned is %lu!\n", dwReturned);
59
60 // Same goes for level 3.
61 cbNeeded = 0xDEADBEEF;
62 dwReturned = 0xDEADBEEF;
63 SetLastError(0xDEADBEEF);
64 ok(!EnumPrintersW(0, NULL, 3, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE!\n");
65 ok(GetLastError() == ERROR_INVALID_LEVEL, "EnumPrintersW returns error %lu!\n", GetLastError());
66 ok(cbNeeded == 0xDEADBEEF, "cbNeeded is %lu!\n", cbNeeded);
67 ok(dwReturned == 0xDEADBEEF, "dwReturned is %lu!\n", dwReturned);
68
69 // Try for all levels. Level 0 is valid here and returns the PRINTER_INFO_STRESS structure (documented in MS-RPRN).
70 for (Level = 0; Level <= 5; Level++)
71 {
72 if (Level == 3)
73 continue;
74
75 // Try with no valid arguments at all.
76 SetLastError(0xDEADBEEF);
77 ok(!EnumPrintersW(0, NULL, Level, NULL, 0, NULL, NULL), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
78 ok(GetLastError() == RPC_X_NULL_REF_POINTER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
79
80 // It has to succeed if we supply the required pointers and query no information.
81 SetLastError(0xDEADBEEF);
82 ok(EnumPrintersW(0, NULL, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n", Level);
83 ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
84 ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, Level);
85 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
86
87 // This constant is from Windows 9x/ME times and mustn't work anymore.
88 SetLastError(0xDEADBEEF);
89 ok(EnumPrintersW(PRINTER_ENUM_DEFAULT, NULL, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n", Level);
90 ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
91 ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, Level);
92 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
93
94 // Now things get interesting. Let's query the buffer size for information about the local printers.
95 SetLastError(0xDEADBEEF);
96 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
97 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
98 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
99
100 // There need to be installed local printers for the next steps.
101 if (cbNeeded > 0)
102 {
103 // Same error has to occur with no buffer, but a size < 4 (AlignRpcPtr comes into play here).
104 SetLastError(0xDEADBEEF);
105 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, NULL, 1, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
106 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
107 ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", Level);
108 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
109
110 // Now provide the demanded size, but no buffer.
111 SetLastError(0xDEADBEEF);
112 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
113 ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
114 ok(cbTemp == 0, "cbTemp is %lu for Level %lu!\n", cbTemp, Level);
115 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
116
117 // Finally use the function as intended and aim for success!
118 // After that, cbTemp contains the needed buffer size without the computer name prepended.
119 pMem = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
120 SetLastError(0xDEADBEEF);
121 ok(EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, pMem, cbNeeded, &cbTemp, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n", Level);
122 ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
123 HeapFree(GetProcessHeap(), 0, pMem);
124
125 if (Level != 4)
126 {
127 // Show that the Name parameter is checked when PRINTER_ENUM_NAME is also specified.
128 SetLastError(0xDEADBEEF);
129 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, L"LOREM IPSUM", Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
130 ok(GetLastError() != ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
131 ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, Level);
132 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
133 }
134
135 // Show that the structure is returned with its known size again when PRINTER_ENUM_NAME is specified and Name
136 // is the (case-insensitively compared) name of the Local Print Provider.
137 SetLastError(0xDEADBEEF);
138 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, L"wInDoWs NT Local Print Providor", Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
139 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
140 ok(cbNeeded == cbTemp, "cbNeeded is %lu, reference size is %lu for Level %lu!\n", cbNeeded, cbTemp, Level);
141 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
142
143 // Now we specify the correct "\\COMPUTERNAME" for Name.
144 // The returned structure should have some strings prepended with the Computer Name and thus require a larger buffer.
145 SetLastError(0xDEADBEEF);
146 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, wszComputerName, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
147 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
148 ok(cbNeeded > cbTemp, "cbNeeded is %lu, reference size is %lu for Level %lu!\n", cbNeeded, cbTemp, Level);
149 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
150
151 if (Level != 4)
152 {
153 // This won't work when there is a trailing backslash (i.e. "\\COMPUTERNAME\").
154 wszComputerName[cchComputerName++] = L'\\';
155 wszComputerName[cchComputerName] = 0;
156 SetLastError(0xDEADBEEF);
157 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, wszComputerName, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
158 ok(GetLastError() == ERROR_INVALID_NAME, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
159 ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, Level);
160 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
161 wszComputerName[--cchComputerName] = 0;
162 }
163
164 // Now it gets funky. There are also cases where EnumPrintersW takes the Name parameter into account,
165 // although PRINTER_ENUM_NAME is not given.
166 // A bogus Name without two backslashes is ignored.
167 SetLastError(0xDEADBEEF);
168 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, L"LOREM IPSUM", Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
169 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
170 ok(cbNeeded == cbTemp, "cbNeeded is %lu, reference size is %lu for Level %lu!\n", cbNeeded, cbTemp, Level);
171 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
172
173 // Specifying "\\COMPUTERNAME" again prepends it to some strings.
174 SetLastError(0xDEADBEEF);
175 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, wszComputerName, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
176 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
177 ok(cbNeeded > cbTemp, "cbNeeded is %lu, reference size is %lu for Level %lu!\n", cbNeeded, cbTemp, Level);
178 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
179
180 // Specifying "\\COMPUTERNAME\" also verifies the Computer Name, but doesn't prepend it.
181 // This logic is crazy, and different to PRINTER_ENUM_NAME...
182 wszComputerName[cchComputerName++] = L'\\';
183 wszComputerName[cchComputerName] = 0;
184 SetLastError(0xDEADBEEF);
185 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, wszComputerName, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
186 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
187 ok(cbNeeded == cbTemp, "cbNeeded is %lu for Level %lu!\n", cbNeeded, Level);
188 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
189
190 // I can even put an additional bogus character after the trailing backslash, doesn't change anything.
191 wszComputerName[cchComputerName++] = L'a';
192 wszComputerName[cchComputerName] = 0;
193 SetLastError(0xDEADBEEF);
194 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, wszComputerName, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
195 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), Level);
196 ok(cbNeeded == cbTemp, "cbNeeded is %lu for Level %lu!\n", cbNeeded, Level);
197 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, Level);
198 cchComputerName -= 2;
199 wszComputerName[cchComputerName] = 0;
200 }
201 else
202 {
203 skip("cbNeeded is 0 on Level %lu, skipping additional tests!\n", Level);
204 }
205 }
206
207 // Using EnumPrintersW with PRINTER_ENUM_NAME, Level 1 and no Name must return information about the Print Providers.
208 // First record must always be the Local Print Provider.
209 SetLastError(0xDEADBEEF);
210 ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE!\n");
211 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu!\n", GetLastError());
212 ok(cbNeeded > 0, "cbNeeded is 0!\n");
213 ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
214
215 SetLastError(0xDEADBEEF);
216 pPrinterInfo1 = (PPRINTER_INFO_1W)HeapAlloc(GetProcessHeap(), 0, cbNeeded);
217 ok(EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, (PBYTE)pPrinterInfo1, cbNeeded, &cbTemp, &dwReturned), "EnumPrintersW returns FALSE!\n");
218 ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu!\n", GetLastError());
219 ok(cbTemp == cbNeeded, "cbTemp is %lu, cbNeeded is %lu!\n", cbTemp, cbNeeded);
220 ok(dwReturned > 0, "dwReturned is %lu!\n", dwReturned);
221 ok(!wcscmp(pPrinterInfo1->pName, L"Windows NT Local Print Providor"), "pPrinterInfo1->pName is %S!\n", pPrinterInfo1->pName);
222 ok(!wcscmp(pPrinterInfo1->pComment, L"Locally connected Printers"), "pPrinterInfo1->pComment is %S!\n", pPrinterInfo1->pComment);
223 ok(!wcscmp(pPrinterInfo1->pDescription, L"Windows NT Local Printers"), "pPrinterInfo1->pDescription is %S!\n", pPrinterInfo1->pDescription);
224 HeapFree(GetProcessHeap(), 0, pPrinterInfo1);
225}
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
BOOL WINAPI GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
Definition: compname.c:446
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define GetProcessHeap()
Definition: compat.h:736
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define ERROR_INVALID_NAME
Definition: compat.h:103
unsigned long DWORD
Definition: ntddk_ex.h:95
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define memset(x, y, z)
Definition: compat.h:39
LPWSTR pName
Definition: winspool.h:29
LPWSTR pComment
Definition: winspool.h:30
LPWSTR pDescription
Definition: winspool.h:28
DWORD WINAPI GetLastError(void)
Definition: except.c:1040
#define MAX_COMPUTERNAME_LENGTH
Definition: winbase.h:243
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
#define ERROR_INVALID_USER_BUFFER
Definition: winerror.h:1091
#define RPC_X_NULL_REF_POINTER
Definition: winerror.h:1087
#define PRINTER_ENUM_LOCAL
Definition: winspool.h:896
WINBOOL WINAPI EnumPrintersW(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
struct _PRINTER_INFO_1W * PPRINTER_INFO_1W
#define PRINTER_ENUM_DEFAULT
Definition: winspool.h:895
#define PRINTER_ENUM_NAME
Definition: winspool.h:899
#define EnumPrinters
Definition: winspool.h:890
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193