2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Functions related to Printer Configuration Data
5 * COPYRIGHT: Copyright 2017 Colin Finck <colin@reactos.org>
11 LocalGetPrinterData(HANDLE hPrinter
, PWSTR pValueName
, PDWORD pType
, PBYTE pData
, DWORD nSize
, PDWORD pcbNeeded
)
13 // The ReactOS Printing Stack forwards all GetPrinterData calls to GetPrinterDataEx as soon as possible.
14 // This function may only be called if localspl.dll is used together with Windows Printing Stack components.
15 WARN("This function should never be called!\n");
16 return LocalGetPrinterDataEx(hPrinter
, L
"PrinterDriverData", pValueName
, pType
, pData
, nSize
, pcbNeeded
);
20 _MakePrinterSubKey(PLOCAL_PRINTER_HANDLE pPrinterHandle
, PCWSTR pKeyName
, PWSTR
* ppwszSubKey
)
22 const WCHAR wszBackslash
[] = L
"\\";
28 if (!pKeyName
|| !*pKeyName
)
29 return ERROR_INVALID_PARAMETER
;
31 // Allocate a buffer for the subkey "PrinterName\KeyName".
32 cbSubKey
= (wcslen(pPrinterHandle
->pPrinter
->pwszPrinterName
) + 1 + wcslen(pKeyName
) + 1) * sizeof(WCHAR
);
33 *ppwszSubKey
= DllAllocSplMem(cbSubKey
);
35 return ERROR_NOT_ENOUGH_MEMORY
;
37 // Concatenate the subkey.
39 StringCbCopyExW(p
, cbSubKey
, pPrinterHandle
->pPrinter
->pwszPrinterName
, &p
, &cbSubKey
, 0);
40 StringCbCopyExW(p
, cbSubKey
, wszBackslash
, &p
, &cbSubKey
, 0);
41 StringCbCopyExW(p
, cbSubKey
, pKeyName
, &p
, &cbSubKey
, 0);
47 _LocalGetPrinterHandleData(PLOCAL_PRINTER_HANDLE pPrinterHandle
, PCWSTR pKeyName
, PCWSTR pValueName
, PDWORD pType
, PBYTE pData
, DWORD nSize
, PDWORD pcbNeeded
)
51 PWSTR pwszSubKey
= NULL
;
53 dwErrorCode
= _MakePrinterSubKey(pPrinterHandle
, pKeyName
, &pwszSubKey
);
54 if (dwErrorCode
!= ERROR_SUCCESS
)
58 dwErrorCode
= (DWORD
)RegOpenKeyExW(hPrintersKey
, pwszSubKey
, 0, KEY_READ
, &hKey
);
59 if (dwErrorCode
!= ERROR_SUCCESS
)
61 ERR("RegOpenKeyExW failed for \"%S\" with error %lu!\n", pwszSubKey
, dwErrorCode
);
65 // Query the desired value.
67 dwErrorCode
= (DWORD
)RegQueryValueExW(hKey
, pValueName
, NULL
, pType
, pData
, pcbNeeded
);
74 DllFreeSplMem(pwszSubKey
);
80 _LocalGetPrintServerHandleData(PCWSTR pValueName
, PDWORD pType
, PBYTE pData
, DWORD nSize
, PDWORD pcbNeeded
)
84 if (wcsicmp(pValueName
, SPLREG_DEFAULT_SPOOL_DIRECTORY
) == 0 ||
85 wcsicmp(pValueName
, SPLREG_PORT_THREAD_PRIORITY
) == 0 ||
86 wcsicmp(pValueName
, SPLREG_SCHEDULER_THREAD_PRIORITY
) == 0 ||
87 wcsicmp(pValueName
, SPLREG_BEEP_ENABLED
) == 0 ||
88 wcsicmp(pValueName
, SPLREG_ALLOW_USER_MANAGEFORMS
) == 0)
91 return (DWORD
)RegQueryValueExW(hPrintersKey
, pValueName
, NULL
, pType
, pData
, pcbNeeded
);
93 else if (wcsicmp(pValueName
, SPLREG_PORT_THREAD_PRIORITY_DEFAULT
) == 0 ||
94 wcsicmp(pValueName
, SPLREG_SCHEDULER_THREAD_PRIORITY_DEFAULT
) == 0)
96 // Store a DWORD value as REG_NONE.
98 *pcbNeeded
= sizeof(DWORD
);
99 if (nSize
< *pcbNeeded
)
100 return ERROR_MORE_DATA
;
102 // Apparently, these values don't serve a purpose anymore.
103 *((PDWORD
)pData
) = 0;
104 return ERROR_SUCCESS
;
106 else if (wcsicmp(pValueName
, SPLREG_NET_POPUP
) == 0 ||
107 wcsicmp(pValueName
, SPLREG_RETRY_POPUP
) == 0 ||
108 wcsicmp(pValueName
, SPLREG_NET_POPUP_TO_COMPUTER
) == 0 ||
109 wcsicmp(pValueName
, SPLREG_EVENT_LOG
) == 0 ||
110 wcsicmp(pValueName
, SPLREG_RESTART_JOB_ON_POOL_ERROR
) == 0 ||
111 wcsicmp(pValueName
, SPLREG_RESTART_JOB_ON_POOL_ENABLED
) == 0)
115 dwErrorCode
= (DWORD
)RegOpenKeyExW(hPrintKey
, L
"Providers", 0, KEY_READ
, &hKey
);
116 if (dwErrorCode
!= ERROR_SUCCESS
)
118 ERR("RegOpenKeyExW failed for \"Providers\" with error %lu!\n", dwErrorCode
);
123 dwErrorCode
= (DWORD
)RegQueryValueExW(hKey
, pValueName
, NULL
, pType
, pData
, pcbNeeded
);
127 else if (wcsicmp(pValueName
, SPLREG_MAJOR_VERSION
) == 0)
129 // Store a DWORD value as REG_NONE.
131 *pcbNeeded
= sizeof(DWORD
);
132 if (nSize
< *pcbNeeded
)
133 return ERROR_MORE_DATA
;
135 // Apparently, these values don't serve a purpose anymore.
136 *((PDWORD
)pData
) = dwSpoolerMajorVersion
;
137 return ERROR_SUCCESS
;
139 else if (wcsicmp(pValueName
, SPLREG_MINOR_VERSION
) == 0)
141 // Store a DWORD value as REG_NONE.
143 *pcbNeeded
= sizeof(DWORD
);
144 if (nSize
< *pcbNeeded
)
145 return ERROR_MORE_DATA
;
147 // Apparently, these values don't serve a purpose anymore.
148 *((PDWORD
)pData
) = dwSpoolerMinorVersion
;
149 return ERROR_SUCCESS
;
151 else if (wcsicmp(pValueName
, SPLREG_ARCHITECTURE
) == 0)
153 // Store a string as REG_NONE with the length of the environment name string.
155 *pcbNeeded
= cbCurrentEnvironment
;
156 if (nSize
< *pcbNeeded
)
157 return ERROR_MORE_DATA
;
159 // Copy the environment name as the output value for SPLREG_ARCHITECTURE.
160 CopyMemory(pData
, wszCurrentEnvironment
, cbCurrentEnvironment
);
161 return ERROR_SUCCESS
;
163 else if (wcsicmp(pValueName
, SPLREG_OS_VERSION
) == 0)
165 POSVERSIONINFOW pInfo
= (POSVERSIONINFOW
)pData
;
167 // Store the OSVERSIONINFOW structure as REG_NONE.
169 *pcbNeeded
= sizeof(OSVERSIONINFOW
);
170 if (nSize
< *pcbNeeded
)
171 return ERROR_MORE_DATA
;
173 // Return OS version information.
174 pInfo
->dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
175 GetVersionExW(pInfo
);
176 return ERROR_SUCCESS
;
178 else if (wcsicmp(pValueName
, SPLREG_OS_VERSIONEX
) == 0)
180 POSVERSIONINFOEXW pInfo
= (POSVERSIONINFOEXW
)pData
;
182 // Store the OSVERSIONINFOEXW structure as REG_NONE.
184 *pcbNeeded
= sizeof(OSVERSIONINFOEXW
);
185 if (nSize
< *pcbNeeded
)
186 return ERROR_MORE_DATA
;
188 // Return extended OS version information.
189 pInfo
->dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEXW
);
190 GetVersionExW((POSVERSIONINFOW
)pInfo
);
191 return ERROR_SUCCESS
;
193 else if (wcsicmp(pValueName
, SPLREG_DS_PRESENT
) == 0)
195 PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pInfo
;
197 // We want to store a REG_DWORD value.
199 *pcbNeeded
= sizeof(DWORD
);
200 if (nSize
< *pcbNeeded
)
201 return ERROR_MORE_DATA
;
203 // Get information about the domain membership of this computer.
204 dwErrorCode
= DsRoleGetPrimaryDomainInformation(NULL
, DsRolePrimaryDomainInfoBasic
, (PBYTE
*)&pInfo
);
205 if (dwErrorCode
!= ERROR_SUCCESS
)
207 ERR("DsRoleGetPrimaryDomainInformation failed with error %lu!\n", dwErrorCode
);
211 // Return whether this computer is a workstation or server inside a domain.
212 *((PDWORD
)pData
) = (pInfo
->MachineRole
== DsRole_RoleMemberWorkstation
|| pInfo
->MachineRole
== DsRole_RoleMemberServer
);
213 DsRoleFreeMemory(pInfo
);
214 return ERROR_SUCCESS
;
216 else if (wcsicmp(pValueName
, SPLREG_DS_PRESENT_FOR_USER
) == 0)
220 WCHAR wszComputerName
[MAX_COMPUTERNAME_LENGTH
+ 1];
221 WCHAR wszUserSam
[UNLEN
+ 1];
223 // We want to store a REG_DWORD value.
225 *pcbNeeded
= sizeof(DWORD
);
226 if (nSize
< *pcbNeeded
)
227 return ERROR_MORE_DATA
;
229 // Get the local Computer Name.
230 cch
= MAX_COMPUTERNAME_LENGTH
+ 1;
231 if (!GetComputerNameW(wszComputerName
, &cch
))
233 dwErrorCode
= GetLastError();
234 ERR("GetComputerNameW failed with error %lu!\n", dwErrorCode
);
238 // Get the User Name in the SAM format.
239 // This could either be:
243 if (!GetUserNameExW(NameSamCompatible
, wszUserSam
, &cch
))
245 dwErrorCode
= GetLastError();
246 ERR("GetUserNameExW failed with error %lu!\n", dwErrorCode
);
250 // Terminate the SAM-formatted User Name at the backslash.
251 p
= wcschr(wszUserSam
, L
'\\');
254 // Compare it with the Computer Name.
255 // If they differ, this User is part of a domain.
256 *((PDWORD
)pData
) = (wcscmp(wszUserSam
, wszComputerName
) != 0);
257 return ERROR_SUCCESS
;
259 else if (wcsicmp(pValueName
, SPLREG_REMOTE_FAX
) == 0)
261 // Store a DWORD value as REG_NONE.
263 *pcbNeeded
= sizeof(DWORD
);
264 if (nSize
< *pcbNeeded
)
265 return ERROR_MORE_DATA
;
267 // TODO: We don't support any fax service yet, but let's return the same value as Windows Server 2003 here.
268 *((PDWORD
)pData
) = 1;
269 return ERROR_SUCCESS
;
271 else if (wcsicmp(pValueName
, SPLREG_DNS_MACHINE_NAME
) == 0)
273 DWORD cchDnsName
= 0;
275 // Get the length of the fully-qualified computer DNS name.
276 GetComputerNameExW(ComputerNameDnsFullyQualified
, NULL
, &cchDnsName
);
277 dwErrorCode
= GetLastError();
278 if (dwErrorCode
!= ERROR_MORE_DATA
)
280 ERR("GetComputerNameExW failed with error %lu!\n", dwErrorCode
);
284 // Check if our supplied buffer is large enough.
286 *pcbNeeded
= cchDnsName
* sizeof(WCHAR
);
287 if (nSize
< *pcbNeeded
)
288 return ERROR_MORE_DATA
;
290 // Get the actual DNS name.
291 if (!GetComputerNameExW(ComputerNameDnsFullyQualified
, (PWSTR
)pData
, &cchDnsName
))
293 dwErrorCode
= GetLastError();
294 ERR("GetComputerNameExW failed with error %lu!\n", dwErrorCode
);
298 // Lowercase the output just like Windows does.
299 _wcslwr((PWSTR
)pData
);
300 return ERROR_SUCCESS
;
304 // For all other, unknown settings, we just return ERROR_INVALID_PARAMETER.
305 // That also includes SPLREG_WEBSHAREMGMT, which is supported in Windows Server 2003 according to the documentation,
306 // but is actually not!
307 return ERROR_INVALID_PARAMETER
;
312 LocalGetPrinterDataEx(HANDLE hPrinter
, PCWSTR pKeyName
, PCWSTR pValueName
, PDWORD pType
, PBYTE pData
, DWORD nSize
, PDWORD pcbNeeded
)
317 PLOCAL_HANDLE pHandle
= (PLOCAL_HANDLE
)hPrinter
;
319 // Even if GetPrinterDataExW in winspool ensures that the RPC function is never called without a valid pointer for pType,
320 // it's officially optional. Windows' fpGetPrinterDataEx also works with NULL for pType!
321 // Ensure here that it is always set to simplify the code later.
325 // pData is later fed to RegQueryValueExW in many cases. When calling it with zero buffer size, RegQueryValueExW returns a
326 // different error code based on whether pData is NULL or something else.
327 // Ensure here that ERROR_MORE_DATA is always returned.
333 dwErrorCode
= ERROR_INVALID_HANDLE
;
337 dwErrorCode
= ERROR_INVALID_PARAMETER
;
339 else if (pHandle
->HandleType
== HandleType_Printer
)
341 dwErrorCode
= _LocalGetPrinterHandleData(pHandle
->pSpecificHandle
, pKeyName
, pValueName
, pType
, pData
, nSize
, pcbNeeded
);
343 else if (pHandle
->HandleType
== HandleType_PrintServer
)
345 dwErrorCode
= _LocalGetPrintServerHandleData(pValueName
, pType
, pData
, nSize
, pcbNeeded
);
349 dwErrorCode
= ERROR_INVALID_HANDLE
;
352 SetLastError(dwErrorCode
);
357 LocalSetPrinterData(HANDLE hPrinter
, PWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
359 // The ReactOS Printing Stack forwards all SetPrinterData calls to SetPrinterDataEx as soon as possible.
360 // This function may only be called if localspl.dll is used together with Windows Printing Stack components.
361 WARN("This function should never be called!\n");
362 return LocalSetPrinterDataEx(hPrinter
, L
"PrinterDriverData", pValueName
, Type
, pData
, cbData
);
366 _LocalSetPrinterHandleData(PLOCAL_PRINTER_HANDLE pPrinterHandle
, PCWSTR pKeyName
, PCWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
370 PWSTR pwszSubKey
= NULL
;
372 dwErrorCode
= _MakePrinterSubKey(pPrinterHandle
, pKeyName
, &pwszSubKey
);
373 if (dwErrorCode
!= ERROR_SUCCESS
)
377 dwErrorCode
= (DWORD
)RegOpenKeyExW(hPrintersKey
, pwszSubKey
, 0, KEY_SET_VALUE
, &hKey
);
378 if (dwErrorCode
!= ERROR_SUCCESS
)
380 ERR("RegOpenKeyExW failed for \"%S\" with error %lu!\n", pwszSubKey
, dwErrorCode
);
385 dwErrorCode
= (DWORD
)RegSetValueExW(hKey
, pValueName
, 0, Type
, pData
, cbData
);
392 DllFreeSplMem(pwszSubKey
);
398 _LocalSetPrintServerHandleData(PCWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
402 if (wcsicmp(pValueName
, SPLREG_DEFAULT_SPOOL_DIRECTORY
) == 0 ||
403 wcsicmp(pValueName
, SPLREG_PORT_THREAD_PRIORITY
) == 0 ||
404 wcsicmp(pValueName
, SPLREG_SCHEDULER_THREAD_PRIORITY
) == 0 ||
405 wcsicmp(pValueName
, SPLREG_BEEP_ENABLED
) == 0 ||
406 wcsicmp(pValueName
, SPLREG_ALLOW_USER_MANAGEFORMS
) == 0)
408 return (DWORD
)RegSetValueExW(hPrintersKey
, pValueName
, 0, Type
, pData
, cbData
);
410 else if (wcsicmp(pValueName
, SPLREG_NET_POPUP
) == 0 ||
411 wcsicmp(pValueName
, SPLREG_RETRY_POPUP
) == 0 ||
412 wcsicmp(pValueName
, SPLREG_NET_POPUP_TO_COMPUTER
) == 0 ||
413 wcsicmp(pValueName
, SPLREG_EVENT_LOG
) == 0 ||
414 wcsicmp(pValueName
, SPLREG_RESTART_JOB_ON_POOL_ERROR
) == 0 ||
415 wcsicmp(pValueName
, SPLREG_RESTART_JOB_ON_POOL_ENABLED
) == 0 ||
416 wcsicmp(pValueName
, L
"NoRemotePrinterDrivers") == 0)
420 dwErrorCode
= (DWORD
)RegOpenKeyExW(hPrintKey
, L
"Providers", 0, KEY_SET_VALUE
, &hKey
);
421 if (dwErrorCode
!= ERROR_SUCCESS
)
423 ERR("RegOpenKeyExW failed for \"Providers\" with error %lu!\n", dwErrorCode
);
427 dwErrorCode
= (DWORD
)RegSetValueExW(hKey
, pValueName
, 0, Type
, pData
, cbData
);
431 else if (wcsicmp(pValueName
, SPLREG_WEBSHAREMGMT
) == 0)
433 WARN("Attempting to set WebShareMgmt, which is based on IIS and therefore not supported. Returning fake success!\n");
434 return ERROR_SUCCESS
;
438 // For all other, unknown settings, we just return ERROR_INVALID_PARAMETER.
439 return ERROR_INVALID_PARAMETER
;
444 LocalSetPrinterDataEx(HANDLE hPrinter
, PCWSTR pKeyName
, PCWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
447 PLOCAL_HANDLE pHandle
= (PLOCAL_HANDLE
)hPrinter
;
451 dwErrorCode
= ERROR_INVALID_HANDLE
;
453 else if (pHandle
->HandleType
== HandleType_Printer
)
455 dwErrorCode
= _LocalSetPrinterHandleData(pHandle
->pSpecificHandle
, pKeyName
, pValueName
, Type
, pData
, cbData
);
457 else if (pHandle
->HandleType
== HandleType_PrintServer
)
459 dwErrorCode
= _LocalSetPrintServerHandleData(pValueName
, Type
, pData
, cbData
);
463 dwErrorCode
= ERROR_INVALID_HANDLE
;
466 SetLastError(dwErrorCode
);