2 * PROJECT: ReactOS Print Spooler DLL API Tests
3 * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
4 * PURPOSE: Tests for EnumPrintersA/EnumPrintersW
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
10 #define WIN32_NO_STATUS
16 START_TEST(EnumPrinters
)
19 BYTE ZeroBuffer
[50] = { 0 };
22 DWORD cchComputerName
;
24 PPRINTER_INFO_1W pPrinterInfo1
;
27 WCHAR wszComputerName
[2 + MAX_COMPUTERNAME_LENGTH
+ 2 + 1];
29 wszComputerName
[0] = L
'\\';
30 wszComputerName
[1] = L
'\\';
31 cchComputerName
= MAX_COMPUTERNAME_LENGTH
+ 1;
32 if (!GetComputerNameW(&wszComputerName
[2], &cchComputerName
))
34 skip("GetComputerNameW failed with error %lu!\n", GetLastError());
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
);
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
);
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
);
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
++)
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
);
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
);
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
);
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
);
100 // There need to be installed local printers for the next steps.
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
);
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
);
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
);
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
);
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
);
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
);
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;
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
);
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
);
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
);
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;
203 skip("cbNeeded is 0 on Level %lu, skipping additional tests!\n", Level
);
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
);
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
);