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
"\\";
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", GetLastError());
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)
221 WCHAR wszComputerName
[MAX_COMPUTERNAME_LENGTH
+ 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 ERR("GetComputerNameW failed with error %lu!\n", GetLastError());
234 return GetLastError();
237 // Get the User Name in the SAM format.
238 // This could either be:
242 GetUserNameExW(NameSamCompatible
, NULL
, &cch
);
243 dwErrorCode
= GetLastError();
244 if (dwErrorCode
!= ERROR_MORE_DATA
)
246 ERR("GetUserNameExW failed with error %lu!\n", dwErrorCode
);
250 pwszUserSam
= DllAllocSplMem(cch
* sizeof(WCHAR
));
253 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
254 ERR("DllAllocSplMem failed!\n");
258 if (!GetUserNameExW(NameSamCompatible
, pwszUserSam
, &cch
))
260 dwErrorCode
= GetLastError();
261 ERR("GetUserNameExW failed with error %lu!\n", dwErrorCode
);
262 DllFreeSplMem(pwszUserSam
);
266 // Terminate the SAM-formatted User Name at the backslash.
267 p
= wcschr(pwszUserSam
, L
'\\');
270 // Compare it with the Computer Name.
271 // If they differ, this User is part of a domain.
272 *((PDWORD
)pData
) = (wcscmp(pwszUserSam
, wszComputerName
) != 0);
273 DllFreeSplMem(pwszUserSam
);
274 return ERROR_SUCCESS
;
276 else if (wcsicmp(pValueName
, SPLREG_REMOTE_FAX
) == 0)
278 // Store a DWORD value as REG_NONE.
280 *pcbNeeded
= sizeof(DWORD
);
281 if (nSize
< *pcbNeeded
)
282 return ERROR_MORE_DATA
;
284 // TODO: We don't support any fax service yet, but let's return the same value as Windows Server 2003 here.
285 *((PDWORD
)pData
) = 1;
286 return ERROR_SUCCESS
;
288 else if (wcsicmp(pValueName
, SPLREG_DNS_MACHINE_NAME
) == 0)
290 DWORD cchDnsName
= 0;
292 // Get the length of the fully-qualified computer DNS name.
293 GetComputerNameExW(ComputerNameDnsFullyQualified
, NULL
, &cchDnsName
);
294 dwErrorCode
= GetLastError();
295 if (dwErrorCode
!= ERROR_MORE_DATA
)
297 ERR("GetComputerNameExW failed with error %lu!\n", dwErrorCode
);
301 // Check if our supplied buffer is large enough.
303 *pcbNeeded
= cchDnsName
* sizeof(WCHAR
);
304 if (nSize
< *pcbNeeded
)
305 return ERROR_MORE_DATA
;
307 // Get the actual DNS name.
308 if (!GetComputerNameExW(ComputerNameDnsFullyQualified
, (PWSTR
)pData
, &cchDnsName
))
310 dwErrorCode
= GetLastError();
311 ERR("GetComputerNameExW failed with error %lu!\n", dwErrorCode
);
315 // Lowercase the output just like Windows does.
316 _wcslwr((PWSTR
)pData
);
317 return ERROR_SUCCESS
;
321 // For all other, unknown settings, we just return ERROR_INVALID_PARAMETER.
322 // That also includes SPLREG_WEBSHAREMGMT, which is supported in Windows Server 2003 according to the documentation,
323 // but is actually not!
324 return ERROR_INVALID_PARAMETER
;
329 LocalGetPrinterDataEx(HANDLE hPrinter
, PCWSTR pKeyName
, PCWSTR pValueName
, PDWORD pType
, PBYTE pData
, DWORD nSize
, PDWORD pcbNeeded
)
333 PLOCAL_HANDLE pHandle
= (PLOCAL_HANDLE
)hPrinter
;
335 // Even if GetPrinterDataExW in winspool ensures that the RPC function is never called without a valid pointer for pType,
336 // it's officially optional. Windows' fpGetPrinterDataEx also works with NULL for pType!
337 // Ensure here that it is always set to simplify the code later.
343 dwErrorCode
= ERROR_INVALID_HANDLE
;
347 dwErrorCode
= ERROR_INVALID_PARAMETER
;
349 else if (pHandle
->HandleType
== HandleType_Printer
)
351 dwErrorCode
= _LocalGetPrinterHandleData(pHandle
->pSpecificHandle
, pKeyName
, pValueName
, pType
, pData
, nSize
, pcbNeeded
);
353 else if (pHandle
->HandleType
== HandleType_PrintServer
)
355 dwErrorCode
= _LocalGetPrintServerHandleData(pValueName
, pType
, pData
, nSize
, pcbNeeded
);
359 dwErrorCode
= ERROR_INVALID_HANDLE
;
362 SetLastError(dwErrorCode
);
367 LocalSetPrinterData(HANDLE hPrinter
, PWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
369 // The ReactOS Printing Stack forwards all SetPrinterData calls to SetPrinterDataEx as soon as possible.
370 // This function may only be called if localspl.dll is used together with Windows Printing Stack components.
371 WARN("This function should never be called!\n");
372 return LocalSetPrinterDataEx(hPrinter
, L
"PrinterDriverData", pValueName
, Type
, pData
, cbData
);
376 _LocalSetPrinterHandleData(PLOCAL_PRINTER_HANDLE pPrinterHandle
, PCWSTR pKeyName
, PCWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
380 PWSTR pwszSubKey
= NULL
;
382 dwErrorCode
= _MakePrinterSubKey(pPrinterHandle
, pKeyName
, &pwszSubKey
);
383 if (dwErrorCode
!= ERROR_SUCCESS
)
387 dwErrorCode
= (DWORD
)RegOpenKeyExW(hPrintersKey
, pwszSubKey
, 0, KEY_SET_VALUE
, &hKey
);
388 if (dwErrorCode
!= ERROR_SUCCESS
)
390 ERR("RegOpenKeyExW failed for \"%S\" with error %lu!\n", pwszSubKey
, dwErrorCode
);
395 dwErrorCode
= (DWORD
)RegSetValueExW(hKey
, pValueName
, 0, Type
, pData
, cbData
);
402 DllFreeSplMem(pwszSubKey
);
408 _LocalSetPrintServerHandleData(PCWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
412 if (wcsicmp(pValueName
, SPLREG_DEFAULT_SPOOL_DIRECTORY
) == 0 ||
413 wcsicmp(pValueName
, SPLREG_PORT_THREAD_PRIORITY
) == 0 ||
414 wcsicmp(pValueName
, SPLREG_SCHEDULER_THREAD_PRIORITY
) == 0 ||
415 wcsicmp(pValueName
, SPLREG_BEEP_ENABLED
) == 0 ||
416 wcsicmp(pValueName
, SPLREG_ALLOW_USER_MANAGEFORMS
) == 0)
418 return (DWORD
)RegSetValueExW(hPrintersKey
, pValueName
, 0, Type
, pData
, cbData
);
420 else if (wcsicmp(pValueName
, SPLREG_NET_POPUP
) == 0 ||
421 wcsicmp(pValueName
, SPLREG_RETRY_POPUP
) == 0 ||
422 wcsicmp(pValueName
, SPLREG_NET_POPUP_TO_COMPUTER
) == 0 ||
423 wcsicmp(pValueName
, SPLREG_EVENT_LOG
) == 0 ||
424 wcsicmp(pValueName
, SPLREG_RESTART_JOB_ON_POOL_ERROR
) == 0 ||
425 wcsicmp(pValueName
, SPLREG_RESTART_JOB_ON_POOL_ENABLED
) == 0 ||
426 wcsicmp(pValueName
, L
"NoRemotePrinterDrivers") == 0)
430 dwErrorCode
= (DWORD
)RegOpenKeyExW(hPrintKey
, L
"Providers", 0, KEY_SET_VALUE
, &hKey
);
431 if (dwErrorCode
!= ERROR_SUCCESS
)
433 ERR("RegOpenKeyExW failed for \"Providers\" with error %lu!\n", dwErrorCode
);
437 dwErrorCode
= (DWORD
)RegSetValueExW(hKey
, pValueName
, 0, Type
, pData
, cbData
);
441 else if (wcsicmp(pValueName
, SPLREG_WEBSHAREMGMT
) == 0)
443 WARN("Attempting to set WebShareMgmt, which is based on IIS and therefore not supported. Returning fake success!\n");
444 return ERROR_SUCCESS
;
448 // For all other, unknown settings, we just return ERROR_INVALID_PARAMETER.
449 return ERROR_INVALID_PARAMETER
;
454 LocalSetPrinterDataEx(HANDLE hPrinter
, PCWSTR pKeyName
, PCWSTR pValueName
, DWORD Type
, PBYTE pData
, DWORD cbData
)
457 PLOCAL_HANDLE pHandle
= (PLOCAL_HANDLE
)hPrinter
;
461 dwErrorCode
= ERROR_INVALID_HANDLE
;
463 else if (pHandle
->HandleType
== HandleType_Printer
)
465 dwErrorCode
= _LocalSetPrinterHandleData(pHandle
->pSpecificHandle
, pKeyName
, pValueName
, Type
, pData
, cbData
);
467 else if (pHandle
->HandleType
== HandleType_PrintServer
)
469 dwErrorCode
= _LocalSetPrintServerHandleData(pValueName
, Type
, pData
, cbData
);
473 dwErrorCode
= ERROR_INVALID_HANDLE
;
476 SetLastError(dwErrorCode
);