[Printing] Part of GDI Support
[reactos.git] / win32ss / printing / providers / localspl / printerdrivers.c
1 /*
2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions for printer driver information
5 * COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8 #include "precomp.h"
9
10 // Local Constants
11 static DWORD dwDriverInfo1Offsets[] = {
12 FIELD_OFFSET(DRIVER_INFO_1W, pName),
13 MAXDWORD
14 };
15
16 static DWORD dwDriverInfo2Offsets[] = {
17 FIELD_OFFSET(DRIVER_INFO_2W, pName),
18 FIELD_OFFSET(DRIVER_INFO_2W, pEnvironment),
19 FIELD_OFFSET(DRIVER_INFO_2W, pDriverPath),
20 FIELD_OFFSET(DRIVER_INFO_2W, pDataFile),
21 FIELD_OFFSET(DRIVER_INFO_2W, pConfigFile),
22 MAXDWORD
23 };
24
25 static DWORD dwDriverInfo3Offsets[] = {
26 FIELD_OFFSET(DRIVER_INFO_3W, pName),
27 FIELD_OFFSET(DRIVER_INFO_3W, pEnvironment),
28 FIELD_OFFSET(DRIVER_INFO_3W, pDriverPath),
29 FIELD_OFFSET(DRIVER_INFO_3W, pDataFile),
30 FIELD_OFFSET(DRIVER_INFO_3W, pConfigFile),
31 FIELD_OFFSET(DRIVER_INFO_3W, pHelpFile),
32 FIELD_OFFSET(DRIVER_INFO_3W, pDependentFiles),
33 FIELD_OFFSET(DRIVER_INFO_3W, pMonitorName),
34 FIELD_OFFSET(DRIVER_INFO_3W, pDefaultDataType),
35 MAXDWORD
36 };
37
38 static DWORD dwDriverInfo4Offsets[] = {
39 FIELD_OFFSET(DRIVER_INFO_4W, pName),
40 FIELD_OFFSET(DRIVER_INFO_4W, pEnvironment),
41 FIELD_OFFSET(DRIVER_INFO_4W, pDriverPath),
42 FIELD_OFFSET(DRIVER_INFO_4W, pDataFile),
43 FIELD_OFFSET(DRIVER_INFO_4W, pConfigFile),
44 FIELD_OFFSET(DRIVER_INFO_4W, pHelpFile),
45 FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles),
46 FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName),
47 FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType),
48 FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames),
49 MAXDWORD
50 };
51
52 static DWORD dwDriverInfo5Offsets[] = {
53 FIELD_OFFSET(DRIVER_INFO_5W, pName),
54 FIELD_OFFSET(DRIVER_INFO_5W, pEnvironment),
55 FIELD_OFFSET(DRIVER_INFO_5W, pDriverPath),
56 FIELD_OFFSET(DRIVER_INFO_5W, pDataFile),
57 FIELD_OFFSET(DRIVER_INFO_5W, pConfigFile),
58 MAXDWORD
59 };
60
61 static void
62 ToMultiSz(LPWSTR pString)
63 {
64 while (*pString)
65 {
66 if (*pString == '|')
67 *pString = '\0';
68 pString++;
69 }
70 }
71
72
73 static void
74 _LocalGetPrinterDriverLevel1(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_1W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
75 {
76 DWORD n;
77 PCWSTR pwszStrings[1];
78
79 /* This value is only here to send something, I have not verified if it is actually correct */
80 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver;
81
82 // Calculate the string lengths.
83 if (!ppDriverInfo)
84 {
85 for (n = 0; n < _countof(pwszStrings); ++n)
86 {
87 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
88 }
89
90 *pcbNeeded += sizeof(DRIVER_INFO_1W);
91 return;
92 }
93
94
95 // Finally copy the structure and advance to the next one in the output buffer.
96 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo1Offsets, *ppDriverInfoEnd);
97 (*ppDriverInfo)++;
98 }
99
100 static void
101 _LocalGetPrinterDriverLevel2(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_2W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
102 {
103 DWORD n;
104 PCWSTR pwszStrings[5];
105
106 /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
107 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
108 pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
109 pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
110 pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
111 pwszStrings[4] = L"c:\\reactos\\system32\\localspl.dll"; // pConfigFile
112
113 // Calculate the string lengths.
114 if (!ppDriverInfo)
115 {
116 for (n = 0; n < _countof(pwszStrings); ++n)
117 {
118 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
119 }
120
121 *pcbNeeded += sizeof(DRIVER_INFO_2W);
122 return;
123 }
124
125 (*ppDriverInfo)->cVersion = 3;
126
127 // Finally copy the structure and advance to the next one in the output buffer.
128 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo2Offsets, *ppDriverInfoEnd);
129 (*ppDriverInfo)++;
130 }
131
132 static void
133 _LocalGetPrinterDriverLevel3(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_3W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
134 {
135 DWORD n;
136 PCWSTR pwszStrings[9];
137
138 /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
139 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
140 pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
141 pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
142 pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
143 pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile
144 pwszStrings[5] = L""; // pHelpFile
145 pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
146 pwszStrings[7] = NULL; // pMonitorName
147 pwszStrings[8] = NULL; // pDefaultDataType
148
149
150 // Calculate the string lengths.
151 if (!ppDriverInfo)
152 {
153 for (n = 0; n < _countof(pwszStrings); ++n)
154 {
155 if (pwszStrings[n])
156 {
157 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
158 }
159 }
160
161 *pcbNeeded += sizeof(DRIVER_INFO_3W);
162 return;
163 }
164
165 (*ppDriverInfo)->cVersion = 3;
166
167 // Finally copy the structure and advance to the next one in the output buffer.
168 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo3Offsets, *ppDriverInfoEnd);
169 ToMultiSz((*ppDriverInfo)->pDependentFiles);
170 (*ppDriverInfo)++;
171 }
172
173 static void
174 _LocalGetPrinterDriverLevel4(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_4W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
175 {
176 DWORD n;
177 PCWSTR pwszStrings[10];
178
179 /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
180 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
181 pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
182 pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
183 pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
184 pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile
185 pwszStrings[5] = L""; // pHelpFile
186 pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
187 pwszStrings[7] = NULL; // pMonitorName
188 pwszStrings[8] = NULL; // pDefaultDataType
189 pwszStrings[9] = NULL; // pszzPreviousNames
190
191 // Calculate the string lengths.
192 if (!ppDriverInfo)
193 {
194 for (n = 0; n < _countof(pwszStrings); ++n)
195 {
196 if (pwszStrings[n])
197 {
198 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
199 }
200 }
201
202 *pcbNeeded += sizeof(DRIVER_INFO_4W);
203 return;
204 }
205
206 (*ppDriverInfo)->cVersion = 3;
207
208 // Finally copy the structure and advance to the next one in the output buffer.
209 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo4Offsets, *ppDriverInfoEnd);
210 ToMultiSz((*ppDriverInfo)->pDependentFiles);
211 (*ppDriverInfo)++;
212 }
213
214 static void
215 _LocalGetPrinterDriverLevel5(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_5W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
216 {
217 DWORD n;
218 PCWSTR pwszStrings[5];
219
220 /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
221 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
222 pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
223 pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath UniDrv.dll
224 pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile.ppd
225 pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile UniDrvUI.dll
226
227 // Calculate the string lengths.
228 if (!ppDriverInfo)
229 {
230 for (n = 0; n < _countof(pwszStrings); ++n)
231 {
232 if (pwszStrings[n])
233 {
234 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
235 }
236 }
237
238 *pcbNeeded += sizeof(DRIVER_INFO_5W);
239 return;
240 }
241
242 (*ppDriverInfo)->cVersion = 3;
243 // Driver attributes, like UMPD/KMPD.
244 (*ppDriverInfo)->dwDriverAttributes = 0; // UMPD/KMPD, So where are they?
245 // Number of times the configuration file for this driver has been upgraded or downgraded since the last spooler restart.
246 (*ppDriverInfo)->dwConfigVersion = 1;
247 // Number of times the driver file for this driver has been upgraded or downgraded since the last spooler restart.
248 (*ppDriverInfo)->dwDriverVersion = 1;
249
250 // Finally copy the structure and advance to the next one in the output buffer.
251 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo5Offsets, *ppDriverInfoEnd);
252 (*ppDriverInfo)++;
253 }
254
255 BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
256 {
257 DWORD dwErrorCode;
258 PBYTE pEnd = &pDriverInfo[cbBuf];
259 PLOCAL_HANDLE pHandle;
260 PLOCAL_PRINTER_HANDLE pPrinterHandle;
261
262 TRACE("LocalGetPrinterDriver(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
263
264 // Check if this is a printer handle.
265 pHandle = (PLOCAL_HANDLE)hPrinter;
266 if (pHandle->HandleType != HandleType_Printer)
267 {
268 dwErrorCode = ERROR_INVALID_HANDLE;
269 goto Cleanup;
270 }
271
272 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
273
274 // Only support 5 levels for now
275 if (Level > 5)
276 {
277 // The caller supplied an invalid level.
278 dwErrorCode = ERROR_INVALID_LEVEL;
279 goto Cleanup;
280 }
281
282 // Count the required buffer size.
283 *pcbNeeded = 0;
284
285 if (Level == 1)
286 _LocalGetPrinterDriverLevel1(pPrinterHandle, NULL, NULL, pcbNeeded);
287 else if (Level == 2)
288 _LocalGetPrinterDriverLevel2(pPrinterHandle, NULL, NULL, pcbNeeded);
289 else if (Level == 3)
290 _LocalGetPrinterDriverLevel3(pPrinterHandle, NULL, NULL, pcbNeeded);
291 else if (Level == 4)
292 _LocalGetPrinterDriverLevel4(pPrinterHandle, NULL, NULL, pcbNeeded);
293 else if (Level == 5)
294 _LocalGetPrinterDriverLevel5(pPrinterHandle, NULL, NULL, pcbNeeded);
295
296 // Check if the supplied buffer is large enough.
297 if (cbBuf < *pcbNeeded)
298 {
299 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
300 goto Cleanup;
301 }
302
303 // Copy over the information.
304 pEnd = &pDriverInfo[*pcbNeeded];
305
306 if (Level == 1)
307 _LocalGetPrinterDriverLevel1(pPrinterHandle, (PDRIVER_INFO_1W*)&pDriverInfo, &pEnd, NULL);
308 else if (Level == 2)
309 _LocalGetPrinterDriverLevel2(pPrinterHandle, (PDRIVER_INFO_2W*)&pDriverInfo, &pEnd, NULL);
310 else if (Level == 3)
311 _LocalGetPrinterDriverLevel3(pPrinterHandle, (PDRIVER_INFO_3W*)&pDriverInfo, &pEnd, NULL);
312 else if (Level == 4)
313 _LocalGetPrinterDriverLevel4(pPrinterHandle, (PDRIVER_INFO_4W*)&pDriverInfo, &pEnd, NULL);
314 else if (Level == 5)
315 _LocalGetPrinterDriverLevel5(pPrinterHandle, (PDRIVER_INFO_5W*)&pDriverInfo, &pEnd, NULL);
316
317 dwErrorCode = ERROR_SUCCESS;
318
319 Cleanup:
320 SetLastError(dwErrorCode);
321 return (dwErrorCode == ERROR_SUCCESS);
322 }