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