ReactOS  0.4.15-dev-1206-g731eddf
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;
26  DWORD Level;
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 ERROR_SUCCESS
Definition: deptool.c:10
#define RPC_X_NULL_REF_POINTER
Definition: winerror.h:1087
START_TEST(EnumPrinters)
Definition: EnumPrinters.c:16
#define EnumPrinters
Definition: winspool.h:890
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
BOOL WINAPI GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
Definition: compname.c:446
#define ERROR_INVALID_USER_BUFFER
Definition: winerror.h:1091
#define PRINTER_ENUM_DEFAULT
Definition: winspool.h:895
smooth NULL
Definition: ftsmooth.c:416
struct _PRINTER_INFO_1W * PPRINTER_INFO_1W
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define PRINTER_ENUM_NAME
Definition: winspool.h:899
#define PRINTER_ENUM_LOCAL
Definition: winspool.h:896
unsigned long DWORD
Definition: ntddk_ex.h:95
#define SetLastError(x)
Definition: compat.h:611
WINBOOL WINAPI EnumPrintersW(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
static const WCHAR L[]
Definition: oid.c:1250
unsigned char BYTE
Definition: xxhash.c:193
#define MAX_COMPUTERNAME_LENGTH
Definition: winbase.h:240
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define ERROR_INVALID_NAME
Definition: compat.h:103
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
#define memset(x, y, z)
Definition: compat.h:39
BYTE * PBYTE
Definition: pedump.c:66
#define HeapFree(x, y, z)
Definition: compat.h:594
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10