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