[LOCALSPL]
[reactos.git] / rostests / apitests / localspl / dll / fpEnumPrinters.c
1 /*
2 * PROJECT: ReactOS Local Spooler API Tests Injected DLL
3 * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
4 * PURPOSE: Tests for fpEnumPrinters
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 <winreg.h>
15 #include <winspool.h>
16 #include <winsplp.h>
17
18 #include "../localspl_apitest.h"
19 #include <spoolss.h>
20
21 extern BOOL GetLocalsplFuncs(LPPRINTPROVIDOR pp);
22
23 START_TEST(fpEnumPrinters)
24 {
25 BYTE TempBuffer[50];
26 BYTE ZeroBuffer[50];
27 DWORD cbNeeded;
28 DWORD cbTemp;
29 DWORD dwReturned;
30 DWORD i;
31 PRINTPROVIDOR pp;
32 PPRINTER_INFO_1W pPrinterInfo1;
33 PVOID pMem;
34
35 if (!GetLocalsplFuncs(&pp))
36 return;
37
38 // Verify that fpEnumPrinters returns success and zeros cbNeeded and dwReturned (but not TempBuffer!) if no flag has been specified.
39 memset(TempBuffer, 0xDE, sizeof(TempBuffer));
40 memset(ZeroBuffer, 0, sizeof(ZeroBuffer));
41 cbNeeded = 0xDEADBEEF;
42 dwReturned = 0xDEADBEEF;
43 SetLastError(0xDEADBEEF);
44 ok(pp.fpEnumPrinters(0, NULL, 1, TempBuffer, sizeof(TempBuffer), &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE\n");
45 ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
46 ok(memcmp(TempBuffer, ZeroBuffer, sizeof(TempBuffer)) != 0, "TempBuffer has been zeroed!\n");
47 ok(cbNeeded == 0, "cbNeeded is %lu!\n", cbNeeded);
48 ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
49
50 // Verify that localspl only returns information about a single print provider (namely itself).
51 cbNeeded = 0xDEADBEEF;
52 dwReturned = 0xDEADBEEF;
53 SetLastError(0xDEADBEEF);
54 ok(!pp.fpEnumPrinters(PRINTER_ENUM_NAME, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE\n");
55 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu!\n", GetLastError());
56 ok(cbNeeded > 0, "cbNeeded is 0!\n");
57 ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
58
59 SetLastError(0xDEADBEEF);
60 pPrinterInfo1 = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
61 ok(pp.fpEnumPrinters(PRINTER_ENUM_NAME, NULL, 1, (PBYTE)pPrinterInfo1, cbNeeded, &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE\n");
62 ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
63 ok(cbNeeded > 0, "cbNeeded is 0!\n");
64 ok(dwReturned == 1, "dwReturned is %lu!\n", dwReturned);
65
66 // Verify the actual strings returned.
67 ok(wcscmp(pPrinterInfo1->pName, L"Windows NT Local Print Providor") == 0, "pPrinterInfo1->pName is \"%S\"!\n", pPrinterInfo1->pName);
68 ok(wcscmp(pPrinterInfo1->pDescription, L"Windows NT Local Printers") == 0, "pPrinterInfo1->pDescription is \"%S\"!\n", pPrinterInfo1->pDescription);
69 ok(wcscmp(pPrinterInfo1->pComment, L"Locally connected Printers") == 0, "pPrinterInfo1->pComment is \"%S\"!\n", pPrinterInfo1->pComment);
70
71 // Level 7 is the highest supported for localspl under Windows Server 2003.
72 // Higher levels need to fail, but they don't set an error code, just cbNeeded to 0.
73 cbNeeded = 0xDEADBEEF;
74 dwReturned = 0xDEADBEEF;
75 SetLastError(0xDEADBEEF);
76 ok(!pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, 8, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE!\n");
77 ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
78 ok(cbNeeded == 0, "cbNeeded is %lu!\n", cbNeeded);
79 ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
80
81 // Verify that all valid levels work.
82 // In contrast to EnumPrintersW, which only accepts levels 0, 1, 2, 4 and 5, localspl returns information for level 0 to 7.
83 for (i = 0; i <= 7; i++)
84 {
85 // Try with no valid arguments at all.
86 // This scenario is usually caugt by RPC, so it just raises an exception here.
87 _SEH2_TRY
88 {
89 dwReturned = 0;
90 pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, NULL, 0, NULL, NULL);
91 }
92 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
93 {
94 dwReturned = _SEH2_GetExceptionCode();
95 }
96 _SEH2_END;
97
98 ok(dwReturned == EXCEPTION_ACCESS_VIOLATION, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
99
100 // Now get the required buffer size.
101 cbNeeded = 0xDEADBEEF;
102 dwReturned = 0xDEADBEEF;
103 SetLastError(0xDEADBEEF);
104 ok(!pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE for Level %lu!\n", i);
105 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
106 ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", i);
107 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
108
109 // This test corrupts something inside spoolsv so that it's only runnable once without restarting spoolsv. Therefore it's disabled.
110 #if 0
111 // Now provide the demanded size, but no buffer. This also mustn't touch cbNeeded.
112 // This scenario is also caught by RPC and we just have an exception here.
113 _SEH2_TRY
114 {
115 dwReturned = 0;
116 pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, NULL, cbNeeded, &cbTemp, &dwReturned);
117 }
118 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
119 {
120 dwReturned = _SEH2_GetExceptionCode();
121 }
122 _SEH2_END;
123
124 ok(dwReturned == EXCEPTION_ACCESS_VIOLATION, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
125 ok(cbNeeded == cbTemp, "cbNeeded is %lu, cbTemp is %lu for Level %lu!\n", cbNeeded, cbTemp, i);
126 #endif
127
128 // Finally use the function as intended and aim for success!
129 pMem = DllAllocSplMem(cbNeeded);
130 SetLastError(0xDEADBEEF);
131 ok(pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, pMem, cbNeeded, &cbTemp, &dwReturned), "fpEnumPrinters returns FALSE for Level %lu!\n", i);
132
133 // This is crazy. For level 3, fpEnumPrinters always returns ERROR_INSUFFICIENT_BUFFER even if we supply a buffer large enough.
134 if (i == 3)
135 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
136 else
137 ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
138
139 DllFreeSplMem(pMem);
140 }
141
142 // fpEnumPrinters has to succeed independent of the level (valid or not) if we query no information.
143 for (i = 0; i < 10; i++)
144 {
145 SetLastError(0xDEADBEEF);
146 ok(pp.fpEnumPrinters(0, NULL, i, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE for Level %lu!\n", i);
147 ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
148 ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, i);
149 ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
150 }
151 }