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 { "DNSMachineName", L"DNSMachineName", REG_SZ, 0xFFFFFFFF, FALSE }, 60 { "AllowUserManageForms", L"AllowUserManageForms", REG_DWORD, 4, TRUE }, 61 { NULL, NULL, 0, 0, FALSE } 62 }; 63 64 START_TEST(GetPrinterData) 65 { 66 DWORD cbNeeded; 67 DWORD cchDefaultPrinter; 68 DWORD dwReturnCode; 69 DWORD dwType; 70 HANDLE hPrinter; 71 PBYTE pDataA; 72 PBYTE pDataW; 73 PSPLREG_VALUE p; 74 WCHAR wszDefaultPrinter[MAX_PRINTER_NAME + 1]; 75 76 // Don't supply any parameters, this has to fail with ERROR_INVALID_HANDLE! 77 dwReturnCode = GetPrinterDataExW(NULL, NULL, NULL, NULL, NULL, 0, NULL); 78 ok(dwReturnCode == ERROR_INVALID_HANDLE, "GetPrinterDataExW returns error %lu!\n", dwReturnCode); 79 80 // Open a handle to the local print server. 81 if (!OpenPrinterW(NULL, &hPrinter, NULL)) 82 { 83 skip("Could not retrieve a handle to the local print server!\n"); 84 return; 85 } 86 87 // Now try with valid handle, but leave remaining parameters NULL. 88 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, NULL, NULL, NULL, 0, NULL); 89 ok(dwReturnCode == RPC_X_NULL_REF_POINTER, "GetPrinterDataExW returns error %lu!\n", dwReturnCode); 90 91 // Try all valid Print Server data values. 92 for (p = SplRegValues; p->pszName; p++) 93 { 94 // Try the ANSI version of the function. 95 dwType = 0xDEADBEEF; 96 dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, &dwType, NULL, 0, &cbNeeded); 97 ok(dwReturnCode == ERROR_MORE_DATA || dwReturnCode == ERROR_FILE_NOT_FOUND, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 98 if (dwReturnCode != ERROR_MORE_DATA) 99 continue; 100 101 ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName); 102 103 if (p->cbNeededA < 0xFFFFFFFF) 104 ok(cbNeeded == p->cbNeededA, "cbNeeded is %lu for \"%s\", but expected %lu!\n", cbNeeded, p->pszName, p->cbNeededA); 105 else 106 ok(cbNeeded > 0, "cbNeeded is 0 for \"%s\"!\n", p->pszName); 107 108 pDataA = HeapAlloc(GetProcessHeap(), 0, cbNeeded); 109 dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, NULL, pDataA, cbNeeded, &cbNeeded); 110 ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 111 112 // Try the Unicode version of the function too. 113 dwType = 0xDEADBEEF; 114 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, &dwType, NULL, 0, &cbNeeded); 115 ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 116 ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName); 117 118 pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded); 119 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, NULL, pDataW, cbNeeded, &cbNeeded); 120 ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 121 122 // Verify that OSVERSIONINFO structures are correctly returned. 123 if (strcmp(p->pszName, "OSVersion") == 0) 124 { 125 POSVERSIONINFOA pOSVersionInfoA = (POSVERSIONINFOA)pDataA; 126 POSVERSIONINFOW pOSVersionInfoW = (POSVERSIONINFOW)pDataW; 127 ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize); 128 ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize); 129 } 130 else if (strcmp(p->pszName, "OSVersionEx") == 0) 131 { 132 POSVERSIONINFOEXA pOSVersionInfoA = (POSVERSIONINFOEXA)pDataA; 133 POSVERSIONINFOEXW pOSVersionInfoW = (POSVERSIONINFOEXW)pDataW; 134 ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize); 135 ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize); 136 } 137 138 // Shortly test SetPrinterDataExW by setting the same data we just retrieved. 139 if (p->bSettable) 140 { 141 dwReturnCode = SetPrinterDataExW(hPrinter, NULL, p->pwszName, dwType, pDataW, cbNeeded); 142 ok(dwReturnCode == ERROR_SUCCESS, "SetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName); 143 } 144 145 HeapFree(GetProcessHeap(), 0, pDataA); 146 HeapFree(GetProcessHeap(), 0, pDataW); 147 } 148 149 // Try an invalid one. 150 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Invalid", NULL, NULL, 0, &cbNeeded); 151 ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 152 153 ClosePrinter(hPrinter); 154 155 // Open a handle to the default printer. 156 cchDefaultPrinter = _countof(wszDefaultPrinter); 157 ok(GetDefaultPrinterW(wszDefaultPrinter, &cchDefaultPrinter), "GetDefaultPrinterW returns FALSE and requires %lu characters!\n", cchDefaultPrinter); 158 if (!OpenPrinterW(wszDefaultPrinter, &hPrinter, NULL)) 159 { 160 skip("Could not retrieve a handle to the default printer!\n"); 161 return; 162 } 163 164 // Using NULL or L"" for pKeyName on a Printer handle yields ERROR_INVALID_PARAMETER. 165 dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Name", NULL, NULL, 0, &cbNeeded); 166 ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 167 dwReturnCode = GetPrinterDataExW(hPrinter, L"", L"Name", NULL, NULL, 0, &cbNeeded); 168 ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 169 170 // Using L"\\" allows us to examine the contents of the main printer key anyway. 171 dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", &dwType, NULL, 0, &cbNeeded); 172 ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 173 ok(dwType == REG_SZ, "dwType is %lu!\n", dwType); 174 ok(cbNeeded > 0, "cbNeeded is 0!\n"); 175 176 pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded); 177 dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", NULL, pDataW, cbNeeded, &cbNeeded); 178 ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu!\n", dwReturnCode); 179 180 // The following test fails if the default printer is a remote printer. 181 ok(wcscmp((PWSTR)pDataW, wszDefaultPrinter) == 0, "pDataW is \"%S\", default printer is \"%S\"!\n", (PWSTR)pDataW, wszDefaultPrinter); 182 183 // SetPrinterDataExW should return ERROR_ACCESS_DENIED when attempting to set the Name. 184 dwReturnCode = SetPrinterDataExW(hPrinter, L"\\", L"Name", REG_SZ, pDataW, cbNeeded); 185 ok(dwReturnCode == ERROR_ACCESS_DENIED, "SetPrinterDataExW returns %lu!\n", dwReturnCode); 186 187 HeapFree(GetProcessHeap(), 0, pDataW); 188 } 189