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