[PRINTING] [SKIPLIST] Use the new header with SPDX license identifier and relicense...
[reactos.git] / reactos / win32ss / printing / providers / localspl / main.c
1 /*
2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Main functions
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6 */
7
8 #include "precomp.h"
9
10 // Global Variables
11 HKEY hPrintKey = NULL;
12 HKEY hPrintersKey = NULL;
13 WCHAR wszJobDirectory[MAX_PATH];
14 DWORD cchJobDirectory;
15 WCHAR wszSpoolDirectory[MAX_PATH];
16 DWORD cchSpoolDirectory;
17
18 // Global Constants
19 #include <prtprocenv.h>
20
21 /** This is what the Spooler of Windows Server 2003 returns (for example using GetPrinterDataExW, SPLREG_MAJOR_VERSION/SPLREG_MINOR_VERSION) */
22 const DWORD dwSpoolerMajorVersion = 3;
23 const DWORD dwSpoolerMinorVersion = 0;
24
25 const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
26
27 PWSTR wszPrintProviderInfo[3] = {
28 L"Windows NT Local Print Providor", // Name
29 L"Locally connected Printers", // Comment
30 L"Windows NT Local Printers" // Description
31 };
32
33 // Local Constants
34 static const PRINTPROVIDOR _PrintProviderFunctions = {
35 LocalOpenPrinter, // fpOpenPrinter
36 LocalSetJob, // fpSetJob
37 LocalGetJob, // fpGetJob
38 LocalEnumJobs, // fpEnumJobs
39 NULL, // fpAddPrinter
40 NULL, // fpDeletePrinter
41 NULL, // fpSetPrinter
42 LocalGetPrinter, // fpGetPrinter
43 LocalEnumPrinters, // fpEnumPrinters
44 NULL, // fpAddPrinterDriver
45 NULL, // fpEnumPrinterDrivers
46 NULL, // fpGetPrinterDriver
47 NULL, // fpGetPrinterDriverDirectory
48 NULL, // fpDeletePrinterDriver
49 NULL, // fpAddPrintProcessor
50 LocalEnumPrintProcessors, // fpEnumPrintProcessors
51 LocalGetPrintProcessorDirectory, // fpGetPrintProcessorDirectory
52 NULL, // fpDeletePrintProcessor
53 LocalEnumPrintProcessorDatatypes, // fpEnumPrintProcessorDatatypes
54 LocalStartDocPrinter, // fpStartDocPrinter
55 LocalStartPagePrinter, // fpStartPagePrinter
56 LocalWritePrinter, // fpWritePrinter
57 LocalEndPagePrinter, // fpEndPagePrinter
58 NULL, // fpAbortPrinter
59 LocalReadPrinter, // fpReadPrinter
60 LocalEndDocPrinter, // fpEndDocPrinter
61 LocalAddJob, // fpAddJob
62 LocalScheduleJob, // fpScheduleJob
63 LocalGetPrinterData, // fpGetPrinterData
64 LocalSetPrinterData, // fpSetPrinterData
65 NULL, // fpWaitForPrinterChange
66 LocalClosePrinter, // fpClosePrinter
67 NULL, // fpAddForm
68 NULL, // fpDeleteForm
69 NULL, // fpGetForm
70 NULL, // fpSetForm
71 NULL, // fpEnumForms
72 LocalEnumMonitors, // fpEnumMonitors
73 LocalEnumPorts, // fpEnumPorts
74 NULL, // fpAddPort
75 NULL, // fpConfigurePort
76 NULL, // fpDeletePort
77 NULL, // fpCreatePrinterIC
78 NULL, // fpPlayGdiScriptOnPrinterIC
79 NULL, // fpDeletePrinterIC
80 NULL, // fpAddPrinterConnection
81 NULL, // fpDeletePrinterConnection
82 NULL, // fpPrinterMessageBox
83 NULL, // fpAddMonitor
84 NULL, // fpDeleteMonitor
85 NULL, // fpResetPrinter
86 NULL, // fpGetPrinterDriverEx
87 NULL, // fpFindFirstPrinterChangeNotification
88 NULL, // fpFindClosePrinterChangeNotification
89 NULL, // fpAddPortEx
90 NULL, // fpShutDown
91 NULL, // fpRefreshPrinterChangeNotification
92 NULL, // fpOpenPrinterEx
93 NULL, // fpAddPrinterEx
94 NULL, // fpSetPort
95 NULL, // fpEnumPrinterData
96 NULL, // fpDeletePrinterData
97 NULL, // fpClusterSplOpen
98 NULL, // fpClusterSplClose
99 NULL, // fpClusterSplIsAlive
100 LocalSetPrinterDataEx, // fpSetPrinterDataEx
101 LocalGetPrinterDataEx, // fpGetPrinterDataEx
102 NULL, // fpEnumPrinterDataEx
103 NULL, // fpEnumPrinterKey
104 NULL, // fpDeletePrinterDataEx
105 NULL, // fpDeletePrinterKey
106 NULL, // fpSeekPrinter
107 NULL, // fpDeletePrinterDriverEx
108 NULL, // fpAddPerMachineConnection
109 NULL, // fpDeletePerMachineConnection
110 NULL, // fpEnumPerMachineConnections
111 NULL, // fpXcvData
112 NULL, // fpAddPrinterDriverEx
113 NULL, // fpSplReadPrinter
114 NULL, // fpDriverUnloadComplete
115 NULL, // fpGetSpoolFileInfo
116 NULL, // fpCommitSpoolData
117 NULL, // fpCloseSpoolFileHandle
118 NULL, // fpFlushPrinter
119 NULL, // fpSendRecvBidiData
120 NULL, // fpAddDriverCatalog
121 };
122
123 static BOOL
124 _InitializeLocalSpooler(void)
125 {
126 const WCHAR wszPrintersPath[] = L"\\PRINTERS";
127 const DWORD cchPrintersPath = _countof(wszPrintersPath) - 1;
128 const WCHAR wszSpoolPath[] = L"\\spool";
129 const DWORD cchSpoolPath = _countof(wszSpoolPath) - 1;
130 const WCHAR wszSymbolicLinkValue[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers";
131 const DWORD cbSymbolicLinkValue = sizeof(wszSymbolicLinkValue) - sizeof(WCHAR);
132
133 BOOL bReturnValue = FALSE;
134 DWORD cbData;
135 DWORD dwErrorCode;
136 HKEY hKey = NULL;
137
138 // On startup, always create a volatile symbolic link in the registry if it doesn't exist yet.
139 // "SYSTEM\CurrentControlSet\Control\Print\Printers" -> "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers"
140 //
141 // According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51
142 // this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive.
143 dwErrorCode = (DWORD)RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers", 0, NULL, REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, KEY_CREATE_LINK | KEY_SET_VALUE, NULL, &hKey, NULL);
144 if (dwErrorCode == ERROR_SUCCESS)
145 {
146 // Note that wszSymbolicLink has to be stored WITHOUT the terminating null character for the symbolic link to work!
147 // See cbSymbolicLinkValue above.
148 dwErrorCode = (DWORD)RegSetValueExW(hKey, L"SymbolicLinkValue", 0, REG_LINK, (PBYTE)wszSymbolicLinkValue, cbSymbolicLinkValue);
149 if (dwErrorCode != ERROR_SUCCESS)
150 {
151 ERR("RegSetValueExW failed for the Printers symlink with error %lu!\n", dwErrorCode);
152 goto Cleanup;
153 }
154 }
155 else if (dwErrorCode != ERROR_ALREADY_EXISTS)
156 {
157 ERR("RegCreateKeyExW failed for the Printers symlink with error %lu!\n", dwErrorCode);
158 goto Cleanup;
159 }
160
161 // Open some registry keys and leave them open. We need them multiple times throughout the Local Spooler.
162 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print", 0, KEY_ALL_ACCESS, &hPrintKey);
163 if (dwErrorCode != ERROR_SUCCESS)
164 {
165 ERR("RegOpenKeyExW failed for \"Print\" with error %lu!\n", dwErrorCode);
166 goto Cleanup;
167 }
168
169 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers", 0, KEY_ALL_ACCESS, &hPrintersKey);
170 if (dwErrorCode != ERROR_SUCCESS)
171 {
172 ERR("RegOpenKeyExW failed for \"Printers\" with error %lu!\n", dwErrorCode);
173 goto Cleanup;
174 }
175
176 // Construct the path to "%SystemRoot%\system32\spool".
177 // Forget about length checks here. If this doesn't fit into MAX_PATH, our OS has more serious problems...
178 cchSpoolDirectory = GetSystemDirectoryW(wszSpoolDirectory, MAX_PATH);
179 CopyMemory(&wszSpoolDirectory[cchSpoolDirectory], wszSpoolPath, (cchSpoolPath + 1) * sizeof(WCHAR));
180 cchSpoolDirectory += cchSpoolPath;
181
182 // Query the job directory.
183 cbData = sizeof(wszJobDirectory);
184 dwErrorCode = (DWORD)RegQueryValueExW(hPrintersKey, SPLREG_DEFAULT_SPOOL_DIRECTORY, NULL, NULL, (PBYTE)wszJobDirectory, &cbData);
185 if (dwErrorCode == ERROR_SUCCESS)
186 {
187 cchJobDirectory = cbData / sizeof(WCHAR) - 1;
188 }
189 else if (dwErrorCode == ERROR_FILE_NOT_FOUND)
190 {
191 // Use the default "%SystemRoot%\system32\spool\PRINTERS".
192 CopyMemory(wszJobDirectory, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
193 CopyMemory(&wszJobDirectory[cchSpoolDirectory], wszPrintersPath, (cchPrintersPath + 1) * sizeof(WCHAR));
194 cchJobDirectory = cchSpoolDirectory + cchPrintersPath;
195
196 // Save this for next time.
197 RegSetValueExW(hPrintersKey, SPLREG_DEFAULT_SPOOL_DIRECTORY, 0, REG_SZ, (PBYTE)wszJobDirectory, (cchJobDirectory + 1) * sizeof(WCHAR));
198 }
199 else
200 {
201 ERR("RegQueryValueExW failed for \"%S\" with error %lu!\n", SPLREG_DEFAULT_SPOOL_DIRECTORY, dwErrorCode);
202 goto Cleanup;
203 }
204
205 // Initialize all lists.
206 if (!InitializePrintMonitorList())
207 goto Cleanup;
208
209 if (!InitializePortList())
210 goto Cleanup;
211
212 if (!InitializePrintProcessorList())
213 goto Cleanup;
214
215 if (!InitializePrinterList())
216 goto Cleanup;
217
218 if (!InitializeGlobalJobList())
219 goto Cleanup;
220
221 // Local Spooler Initialization finished successfully!
222 bReturnValue = TRUE;
223
224 Cleanup:
225 if (hKey)
226 RegCloseKey(hKey);
227
228 return bReturnValue;
229 }
230
231 BOOL WINAPI
232 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
233 {
234 switch (fdwReason)
235 {
236 case DLL_PROCESS_ATTACH:
237 DisableThreadLibraryCalls(hinstDLL);
238 return _InitializeLocalSpooler();
239
240 default:
241 return TRUE;
242 }
243 }
244
245 BOOL WINAPI
246 InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
247 {
248 TRACE("InitializePrintProvidor(%p, %lu, %S)\n", pPrintProvidor, cbPrintProvidor, pFullRegistryPath);
249
250 CopyMemory(pPrintProvidor, &_PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR)));
251
252 SetLastError(ERROR_SUCCESS);
253 return TRUE;
254 }