[PRINTING] Semi-implement GetPrinterDriverW
[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
11 // Local Constants
12 static DWORD dwDriverInfo1Offsets[] = {
13 FIELD_OFFSET(DRIVER_INFO_1W, pName),
14 MAXDWORD
15 };
16
17 static DWORD dwDriverInfo2Offsets[] = {
18 FIELD_OFFSET(DRIVER_INFO_2W, pName),
19 FIELD_OFFSET(DRIVER_INFO_2W, pEnvironment),
20 FIELD_OFFSET(DRIVER_INFO_2W, pDriverPath),
21 FIELD_OFFSET(DRIVER_INFO_2W, pDataFile),
22 FIELD_OFFSET(DRIVER_INFO_2W, pConfigFile),
23 MAXDWORD
24 };
25
26 static DWORD dwDriverInfo3Offsets[] = {
27 FIELD_OFFSET(DRIVER_INFO_3W, pName),
28 FIELD_OFFSET(DRIVER_INFO_3W, pEnvironment),
29 FIELD_OFFSET(DRIVER_INFO_3W, pDriverPath),
30 FIELD_OFFSET(DRIVER_INFO_3W, pDataFile),
31 FIELD_OFFSET(DRIVER_INFO_3W, pConfigFile),
32 FIELD_OFFSET(DRIVER_INFO_3W, pHelpFile),
33 FIELD_OFFSET(DRIVER_INFO_3W, pDependentFiles),
34 FIELD_OFFSET(DRIVER_INFO_3W, pMonitorName),
35 FIELD_OFFSET(DRIVER_INFO_3W, pDefaultDataType),
36 MAXDWORD
37 };
38
39 static void
40 ToMultiSz(LPWSTR pString)
41 {
42 while (*pString)
43 {
44 if (*pString == '|')
45 *pString = '\0';
46 pString++;
47 }
48 }
49
50
51 static void
52 _LocalGetPrinterDriverLevel1(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_1W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
53 {
54 DWORD n;
55 PCWSTR pwszStrings[1];
56
57 /* This value is only here to send something, I have not verified if it is actually correct */
58 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver;
59
60 // Calculate the string lengths.
61 if (!ppDriverInfo)
62 {
63 for (n = 0; n < _countof(pwszStrings); ++n)
64 {
65 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
66 }
67
68 *pcbNeeded += sizeof(DRIVER_INFO_1W);
69 return;
70 }
71
72
73 // Finally copy the structure and advance to the next one in the output buffer.
74 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo1Offsets, *ppDriverInfoEnd);
75 (*ppDriverInfo)++;
76 }
77
78 static void
79 _LocalGetPrinterDriverLevel2(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_2W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
80 {
81 DWORD n;
82 PCWSTR pwszStrings[5];
83
84 /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
85 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
86 pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
87 pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
88 pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
89 pwszStrings[4] = L"c:\\reactos\\system32\\localspl.dll"; // pConfigFile
90
91 // Calculate the string lengths.
92 if (!ppDriverInfo)
93 {
94 for (n = 0; n < _countof(pwszStrings); ++n)
95 {
96 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
97 }
98
99 *pcbNeeded += sizeof(DRIVER_INFO_2W);
100 return;
101 }
102
103 (*ppDriverInfo)->cVersion = 3;
104
105 // Finally copy the structure and advance to the next one in the output buffer.
106 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo2Offsets, *ppDriverInfoEnd);
107 (*ppDriverInfo)++;
108 }
109
110 static void
111 _LocalGetPrinterDriverLevel3(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_3W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
112 {
113 DWORD n;
114 PCWSTR pwszStrings[9];
115
116 /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
117 pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
118 pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
119 pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
120 pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
121 pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile
122 pwszStrings[5] = L""; // pHelpFile
123 pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
124 pwszStrings[7] = NULL; // pMonitorName
125 pwszStrings[8] = NULL; // pDefaultDataType
126
127
128 // Calculate the string lengths.
129 if (!ppDriverInfo)
130 {
131 for (n = 0; n < _countof(pwszStrings); ++n)
132 {
133 if (pwszStrings[n])
134 {
135 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
136 }
137 }
138
139 *pcbNeeded += sizeof(DRIVER_INFO_3W);
140 return;
141 }
142
143 (*ppDriverInfo)->cVersion = 3;
144
145 // Finally copy the structure and advance to the next one in the output buffer.
146 *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo3Offsets, *ppDriverInfoEnd);
147 ToMultiSz((*ppDriverInfo)->pDependentFiles);
148 (*ppDriverInfo)++;
149 }
150
151
152 BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
153 {
154 DWORD dwErrorCode;
155 PBYTE pEnd = &pDriverInfo[cbBuf];
156 PLOCAL_HANDLE pHandle;
157 PLOCAL_PRINTER_HANDLE pPrinterHandle;
158
159 TRACE("LocalGetPrinterDriver(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
160
161 // Check if this is a printer handle.
162 pHandle = (PLOCAL_HANDLE)hPrinter;
163 if (pHandle->HandleType != HandleType_Printer)
164 {
165 dwErrorCode = ERROR_INVALID_HANDLE;
166 goto Cleanup;
167 }
168
169 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
170
171 // Only support 3 levels for now
172 if (Level > 3)
173 {
174 // The caller supplied an invalid level.
175 dwErrorCode = ERROR_INVALID_LEVEL;
176 goto Cleanup;
177 }
178
179 // Count the required buffer size.
180 *pcbNeeded = 0;
181
182 if (Level == 1)
183 _LocalGetPrinterDriverLevel1(pPrinterHandle, NULL, NULL, pcbNeeded);
184 else if (Level == 2)
185 _LocalGetPrinterDriverLevel2(pPrinterHandle, NULL, NULL, pcbNeeded);
186 else if (Level == 3)
187 _LocalGetPrinterDriverLevel3(pPrinterHandle, NULL, NULL, pcbNeeded);
188
189 // Check if the supplied buffer is large enough.
190 if (cbBuf < *pcbNeeded)
191 {
192 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
193 goto Cleanup;
194 }
195
196 // Copy over the information.
197 pEnd = &pDriverInfo[*pcbNeeded];
198
199 if (Level == 1)
200 _LocalGetPrinterDriverLevel1(pPrinterHandle, (PDRIVER_INFO_1W*)&pDriverInfo, &pEnd, NULL);
201 else if (Level == 2)
202 _LocalGetPrinterDriverLevel2(pPrinterHandle, (PDRIVER_INFO_2W*)&pDriverInfo, &pEnd, NULL);
203 else if (Level == 3)
204 _LocalGetPrinterDriverLevel3(pPrinterHandle, (PDRIVER_INFO_3W*)&pDriverInfo, &pEnd, NULL);
205
206 dwErrorCode = ERROR_SUCCESS;
207
208 Cleanup:
209 SetLastError(dwErrorCode);
210 return (dwErrorCode == ERROR_SUCCESS);
211 }