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)
11 HKEY hPrintKey
= NULL
;
12 HKEY hPrintersKey
= NULL
;
13 WCHAR wszJobDirectory
[MAX_PATH
];
14 DWORD cchJobDirectory
;
15 WCHAR wszSpoolDirectory
[MAX_PATH
];
16 DWORD cchSpoolDirectory
;
19 #include <prtprocenv.h>
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;
25 const WCHAR wszDefaultDocumentName
[] = L
"Local Downlevel Document";
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
34 static const PRINTPROVIDOR _PrintProviderFunctions
= {
35 LocalOpenPrinter
, // fpOpenPrinter
36 LocalSetJob
, // fpSetJob
37 LocalGetJob
, // fpGetJob
38 LocalEnumJobs
, // fpEnumJobs
40 NULL
, // fpDeletePrinter
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
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
124 _InitializeLocalSpooler(void)
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
);
133 BOOL bReturnValue
= FALSE
;
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"
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
)
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
)
151 ERR("RegSetValueExW failed for the Printers symlink with error %lu!\n", dwErrorCode
);
155 else if (dwErrorCode
!= ERROR_ALREADY_EXISTS
)
157 ERR("RegCreateKeyExW failed for the Printers symlink with error %lu!\n", dwErrorCode
);
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
)
165 ERR("RegOpenKeyExW failed for \"Print\" with error %lu!\n", dwErrorCode
);
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
)
172 ERR("RegOpenKeyExW failed for \"Printers\" with error %lu!\n", dwErrorCode
);
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
;
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
)
187 cchJobDirectory
= cbData
/ sizeof(WCHAR
) - 1;
189 else if (dwErrorCode
== ERROR_FILE_NOT_FOUND
)
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
;
196 // Save this for next time.
197 RegSetValueExW(hPrintersKey
, SPLREG_DEFAULT_SPOOL_DIRECTORY
, 0, REG_SZ
, (PBYTE
)wszJobDirectory
, (cchJobDirectory
+ 1) * sizeof(WCHAR
));
201 ERR("RegQueryValueExW failed for \"%S\" with error %lu!\n", SPLREG_DEFAULT_SPOOL_DIRECTORY
, dwErrorCode
);
205 // Initialize all lists.
206 if (!InitializePrintMonitorList())
209 if (!InitializePortList())
212 if (!InitializePrintProcessorList())
215 if (!InitializePrinterList())
218 if (!InitializeGlobalJobList())
221 if (!InitializeFormList())
224 if (!InitializePrinterDrivers())
227 // Local Spooler Initialization finished successfully!
238 DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
242 case DLL_PROCESS_ATTACH
:
243 DisableThreadLibraryCalls(hinstDLL
);
244 return _InitializeLocalSpooler();
252 InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
, DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
254 TRACE("InitializePrintProvidor(%p, %lu, %S)\n", pPrintProvidor
, cbPrintProvidor
, pFullRegistryPath
);
256 CopyMemory(pPrintProvidor
, &_PrintProviderFunctions
, min(cbPrintProvidor
, sizeof(PRINTPROVIDOR
)));
258 SetLastError(ERROR_SUCCESS
);