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 GetPrinterData(Ex)A/GetPrinterData(Ex)W/SetPrinterData(Ex)A/SetPrinterData(Ex)W 5 * COPYRIGHT: Copyright 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 #include <winreg.h> 16 17 /* From printing/include/spoolss.h */ 18 #define MAX_PRINTER_NAME 220 19 20 typedef struct _SPLREG_VALUE 21 { 22 PSTR pszName; 23 PWSTR pwszName; 24 DWORD dwType; 25 DWORD cbNeededA; 26 BOOL bSettable; 27 } 28 SPLREG_VALUE, *PSPLREG_VALUE; 29 30 SPLREG_VALUE SplRegValues[] = { 31 { "DefaultSpoolDirectory", L"DefaultSpoolDirectory", REG_SZ, 0xFFFFFFFF, TRUE }, 32 { "PortThreadPriorityDefault", L"PortThreadPriorityDefault", REG_NONE, 4, FALSE }, 33 { "PortThreadPriority", L"PortThreadPriority", REG_DWORD, 4, TRUE }, 34 { "SchedulerThreadPriorityDefault", L"SchedulerThreadPriorityDefault", REG_NONE, 4, FALSE }, 35 { "SchedulerThreadPriority", L"SchedulerThreadPriority", REG_DWORD, 4, TRUE }, 36 { "BeepEnabled", L"BeepEnabled", REG_DWORD, 4, TRUE }, 37 38 /* These fail in Win8, probably removed since NT6: 39 40 { "NetPopup", L"NetPopup", REG_DWORD, 4, TRUE }, 41 { "RetryPopup", L"RetryPopup", REG_DWORD, 4, TRUE }, 42 { "NetPopupToComputer", L"NetPopupToComputer", REG_DWORD, 4, TRUE }, 43 44 */ 45 46 { "EventLog", L"EventLog", REG_DWORD, 4, TRUE }, 47 { "MajorVersion", L"MajorVersion", REG_NONE, 4, FALSE }, 48 { "MinorVersion", L"MinorVersion", REG_NONE, 4, FALSE }, 49 { "Architecture", L"Architecture", REG_NONE, 0xFFFFFFFF, FALSE }, 50 { "OSVersion", L"OSVersion", REG_NONE, sizeof(OSVERSIONINFOA), FALSE }, 51 { "OSVersionEx", L"OSVersionEx", REG_NONE, sizeof(OSVERSIONINFOEXA), FALSE }, 52 #if 0 53 { "DsPresent", L"DsPresent", REG_DWORD, 4, FALSE }, 54 { "DsPresentForUser", L"DsPresentForUser", REG_DWORD, 4, FALSE }, 55 #endif 56 { "RemoteFax", L"RemoteFax", REG_NONE, 4, FALSE }, 57 { "RestartJobOnPoolError", L"RestartJobOnPoolError", REG_DWORD, 4, TRUE }, 58 { "RestartJobOnPoolEnabled", L"RestartJobOnPoolEnabled", REG_DWORD, 4, TRUE }, 59 #if 0 // FIXME: fails on WHS testbot with ERROR_INVALID_PARAMETER 60 { "DNSMachineName", L"DNSMachineName", REG_SZ, 0xFFFFFFFF, FALSE }, 61 #endif 62 { "AllowUserManageForms", L"AllowUserManageForms", REG_DWORD, 4, TRUE }, 63 { NULL, NULL, 0, 0, FALSE } 64 }; 65 66 START_TEST(GetPrinterData) 67 { 68 DWORD cbNeeded; 69 DWORD cchDefaultPrinter; 70 DWORD dwReturnCode; 71 DWORD dwType; 72 HANDLE hPrinter; 73 PBYTE pDataA; 74 PBYTE pDataW; 75 PSPLREG_VALUE p; 76 WCHAR wszDefaultPrinter[MAX_PRINTER_NAME + 1]; 77 78 // Don't supply any parameters, this has to fail with ERROR_INVALID_HANDLE! 79 dwReturnCode = GetPrinterDataExW(NULL, NULL, NULL, NULL, NULL, 0, NULL); 80 ok(dwReturnCode == ERROR_INVALID_HANDLE, "GetPrinterDataExW returns error %lu!\n", dwReturnCode); 81 82 // Open a handle to the local print server. 83 if (!OpenPrinterW(NULL, &hPrinter, NULL)) 84 { 85 skip("Could not retrieve a handle to the local print server!\n"); 86 return; 87 } 88 89 // Now try with valid handle, but leave remaining parameters NULL. 90 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, NULL, NULL, NULL, 0, NULL); 91 ok(dwReturnCode == RPC_X_NULL_REF_POINTER, "GetPrinterDataExW returns error %lu!\n", dwReturnCode); 92 93 // Try all valid Print Server data values. 94 for (p = SplRegValues; p->pszName; p++) 95 { 96 // Try the ANSI version of the function. 97 dwType = 0xDEADBEEF; 98 dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, &dwType, NULL, 0, &cbNeeded); 99 ok(dwReturnCode == ERROR_MORE_DATA || dwReturnCode == ERROR_FILE_NOT_FOUND, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 100 if (dwReturnCode != ERROR_MORE_DATA) 101 continue; 102 103 ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName); 104 105 if (p->cbNeededA < 0xFFFFFFFF) 106 ok(cbNeeded == p->cbNeededA, "cbNeeded is %lu for \"%s\", but expected %lu!\n", cbNeeded, p->pszName, p->cbNeededA); 107 else 108 ok(cbNeeded > 0, "cbNeeded is 0 for \"%s\"!\n", p->pszName); 109 110 pDataA = HeapAlloc(GetProcessHeap(), 0, cbNeeded); 111 dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, NULL, pDataA, cbNeeded, &cbNeeded); 112 ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 113 114 // Try the Unicode version of the function too. 115 dwType = 0xDEADBEEF; 116 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, &dwType, NULL, 0, &cbNeeded); 117 ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 118 ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName); 119 120 pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded); 121 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, NULL, pDataW, cbNeeded, &cbNeeded); 122 ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 123 124 // Verify that OSVERSIONINFO structures are correctly returned. 125 if (strcmp(p->pszName, "OSVersion") == 0) 126 { 127 POSVERSIONINFOA pOSVersionInfoA = (POSVERSIONINFOA)pDataA; 128 POSVERSIONINFOW pOSVersionInfoW = (POSVERSIONINFOW)pDataW; 129 ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize); 130 ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize); 131 } 132 else if (strcmp(p->pszName, "OSVersionEx") == 0) 133 { 134 POSVERSIONINFOEXA pOSVersionInfoA = (POSVERSIONINFOEXA)pDataA; 135 POSVERSIONINFOEXW pOSVersionInfoW = (POSVERSIONINFOEXW)pDataW; 136 ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize); 137 ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize); 138 } 139 140 // Shortly test SetPrinterDataExW by setting the same data we just retrieved. 141 if (p->bSettable) 142 { 143 dwReturnCode = SetPrinterDataExW(hPrinter, NULL, p->pwszName, dwType, pDataW, cbNeeded); 144 ok(dwReturnCode == ERROR_SUCCESS, "SetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 145 } 146 147 HeapFree(GetProcessHeap(), 0, pDataA); 148 HeapFree(GetProcessHeap(), 0, pDataW); 149 } 150 151 // Try an invalid one. 152 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Invalid", NULL, NULL, 0, &cbNeeded); 153 ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 154 155 ClosePrinter(hPrinter); 156 157 // Open a handle to the default printer. 158 cchDefaultPrinter = _countof(wszDefaultPrinter); 159 ok(GetDefaultPrinterW(wszDefaultPrinter, &cchDefaultPrinter), "GetDefaultPrinterW returns FALSE and requires %lu characters!\n", cchDefaultPrinter); 160 if (!OpenPrinterW(wszDefaultPrinter, &hPrinter, NULL)) 161 { 162 skip("Could not retrieve a handle to the default printer!\n"); 163 return; 164 } 165 166 // Using NULL or L"" for pKeyName on a Printer handle yields ERROR_INVALID_PARAMETER. 167 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Name", NULL, NULL, 0, &cbNeeded); 168 ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 169 dwReturnCode = GetPrinterDataExW(hPrinter, L"", L"Name", NULL, NULL, 0, &cbNeeded); 170 ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 171 172 // Using L"\\" allows us to examine the contents of the main printer key anyway. 173 dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", &dwType, NULL, 0, &cbNeeded); 174 ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 175 ok(dwType == REG_SZ, "dwType is %lu!\n", dwType); 176 ok(cbNeeded > 0, "cbNeeded is 0!\n"); 177 178 pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded); 179 dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", NULL, pDataW, cbNeeded, &cbNeeded); 180 ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 181 182 // The following test fails if the default printer is a remote printer. 183 ok(wcscmp((PWSTR)pDataW, wszDefaultPrinter) == 0, "pDataW is \"%S\", default printer is \"%S\"!\n", (PWSTR)pDataW, wszDefaultPrinter); 184 185 // SetPrinterDataExW should return ERROR_ACCESS_DENIED when attempting to set the Name. 186 dwReturnCode = SetPrinterDataExW(hPrinter, L"\\", L"Name", REG_SZ, pDataW, cbNeeded); 187 ok(dwReturnCode == ERROR_ACCESS_DENIED, "SetPrinterDataExW returns %lu!\n", dwReturnCode); 188 189 HeapFree(GetProcessHeap(), 0, pDataW); 190 } 191