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