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 PCWSTR 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     LocalAddPrinterDriver,                      // fpAddPrinterDriver
45     LocalEnumPrinterDrivers,                    // fpEnumPrinterDrivers
46     LocalGetPrinterDriver,                      // fpGetPrinterDriver
47     LocalGetPrinterDriverDirectory,             // 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     LocalAddForm,                               // fpAddForm
68     LocalDeleteForm,                            // fpDeleteForm
69     LocalGetForm,                               // fpGetForm
70     LocalSetForm,                               // fpSetForm
71     LocalEnumForms,                             // fpEnumForms
72     LocalEnumMonitors,                          // fpEnumMonitors
73     LocalEnumPorts,                             // fpEnumPorts
74     LocalAddPort,                               // fpAddPort
75     LocalConfigurePort,                         // fpConfigurePort
76     LocalDeletePort,                            // fpDeletePort
77     NULL,                                       // fpCreatePrinterIC
78     NULL,                                       // fpPlayGdiScriptOnPrinterIC
79     NULL,                                       // fpDeletePrinterIC
80     NULL,                                       // fpAddPrinterConnection
81     NULL,                                       // fpDeletePrinterConnection
82     LocalPrinterMessageBox,                     // fpPrinterMessageBox
83     LocalAddMonitor,                            // fpAddMonitor
84     LocalDeleteMonitor,                         // fpDeleteMonitor
85     NULL,                                       // fpResetPrinter
86     LocalGetPrinterDriverEx,                    // fpGetPrinterDriverEx
87     NULL,                                       // fpFindFirstPrinterChangeNotification
88     NULL,                                       // fpFindClosePrinterChangeNotification
89     LocalAddPortEx,                             // fpAddPortEx
90     NULL,                                       // fpShutDown
91     NULL,                                       // fpRefreshPrinterChangeNotification
92     NULL,                                       // fpOpenPrinterEx
93     NULL,                                       // fpAddPrinterEx
94     LocalSetPort,                               // 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     LocalXcvData,                               // fpXcvData
112     LocalAddPrinterDriverEx,                    // fpAddPrinterDriverEx
113     NULL,                                       // fpSplReadPrinter
114     NULL,                                       // fpDriverUnloadComplete
115     LocalGetSpoolFileInfo,                      // fpGetSpoolFileInfo
116     LocalCommitSpoolData,                       // fpCommitSpoolData
117     LocalCloseSpoolFileHandle,                  // fpCloseSpoolFileHandle
118     NULL,                                       // fpFlushPrinter
119     NULL,                                       // fpSendRecvBidiData
120     NULL,                                       // fpAddDriverCatalog
121 };
122 
123 static BOOL
_InitializeLocalSpooler(void)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     if (!InitializeFormList())
222         goto Cleanup;
223 
224     if (!InitializePrinterDrivers())
225         goto Cleanup;
226 
227     // Local Spooler Initialization finished successfully!
228     bReturnValue = TRUE;
229 
230 Cleanup:
231     if (hKey)
232         RegCloseKey(hKey);
233 
234     return bReturnValue;
235 }
236 
237 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)238 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
239 {
240     switch (fdwReason)
241     {
242         case DLL_PROCESS_ATTACH:
243             DisableThreadLibraryCalls(hinstDLL);
244             return _InitializeLocalSpooler();
245 
246         default:
247             return TRUE;
248     }
249 }
250 
251 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,DWORD cbPrintProvidor,LPWSTR pFullRegistryPath)252 InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
253 {
254     TRACE("InitializePrintProvidor(%p, %lu, %S)\n", pPrintProvidor, cbPrintProvidor, pFullRegistryPath);
255 
256     CopyMemory(pPrintProvidor, &_PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR)));
257 
258     SetLastError(ERROR_SUCCESS);
259     return TRUE;
260 }
261