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 typedef struct {
13     WCHAR   src[MAX_PATH+MAX_PATH];
14     WCHAR   dst[MAX_PATH+MAX_PATH];
15     DWORD   srclen;
16     DWORD   dstlen;
17     DWORD   copyflags;
18     BOOL    lazy;
19 } apd_data_t;
20 
21 static const WCHAR backslashW[] = {'\\',0};
22 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
23 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
24 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
25 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
26 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
27 static const WCHAR emptyW[] = {0};
28 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
29                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
30                                   'c','o','n','t','r','o','l','\\',
31                                   'P','r','i','n','t','\\',
32                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
33                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
34 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
35 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
36 
37 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
38 
39 static const WCHAR spoolW[] = {'\\','s','p','o','o','l',0};
40 static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
41 static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
42 static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
43 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
44 static const WCHAR version3_subdirW[] = {'\\','3',0};
45 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
46 static const WCHAR version0_subdirW[] = {'\\','0',0};
47 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
48 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
49 static const WCHAR x64_subdirW[] = {'x','6','4',0};
50 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
51 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
52 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
53 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
54 
55 static PRINTENV_T env_ia64 =  {ia64_envnameW, ia64_subdirW, 3, version3_regpathW, version3_subdirW};
56 
57 static PRINTENV_T env_x86 =   {x86_envnameW, x86_subdirW, 3, version3_regpathW, version3_subdirW};
58 
59 static PRINTENV_T env_x64 =   {x64_envnameW, x64_subdirW, 3, version3_regpathW, version3_subdirW};
60 
61 static PRINTENV_T env_win40 = {win40_envnameW, win40_subdirW, 0, version0_regpathW, version0_subdirW};
62 
63 static PPRINTENV_T all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
64 
65 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
66                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
67                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
68                                   0, sizeof(DRIVER_INFO_8W)};
69 
70 static WCHAR wszScratchPad[MAX_PATH] = L"";
71 
72 static WCHAR wszLocalSplFile[MAX_PATH] = L"";
73 static WCHAR wszPrintUiFile[MAX_PATH] = L"";
74 static WCHAR wszDriverPath[MAX_PATH] = L"";
75 
76 BOOL
77 InitializePrinterDrivers(VOID)
78 {
79     WCHAR szSysDir[MAX_PATH];
80     DWORD cbBuf;
81 
82     if (wszLocalSplFile[0] && wszPrintUiFile[0])
83         return TRUE;
84 
85     if (!GetSystemDirectoryW(szSysDir, _countof(szSysDir)))
86     {
87         ERR("GetSystemDirectoryW failed\n");
88         return FALSE;
89     }
90 
91     StringCbCopyW(wszLocalSplFile, sizeof(wszLocalSplFile), szSysDir);
92     StringCbCatW(wszLocalSplFile, sizeof(wszLocalSplFile), L"\\localspl.dll");
93 
94     StringCbCopyW(wszPrintUiFile, sizeof(wszPrintUiFile), szSysDir);
95     StringCbCatW(wszPrintUiFile, sizeof(wszPrintUiFile), L"\\printui.dll");
96 
97     if (!LocalGetPrinterDriverDirectory(NULL, (PWSTR)wszCurrentEnvironment, 1, (PBYTE)szSysDir, (DWORD)sizeof(szSysDir), &cbBuf))
98     {
99         ERR("LocalGetPrinterDriverDirectory failed\n");
100         return FALSE;
101     }
102 
103     StringCbCopyW(wszDriverPath, sizeof(wszDriverPath), szSysDir);
104     StringCbCatW(wszDriverPath, sizeof(wszDriverPath), version3_subdirW);
105     StringCbCatW(wszDriverPath, sizeof(wszDriverPath), backslashW);
106 
107     // HAX! need to get it from the Reg Key L"Driver"!
108     StringCbCatW(wszDriverPath, sizeof(wszDriverPath), L"UniDrv.dll");
109 
110     FIXME("DriverPath : %S\n",wszDriverPath);
111 
112     return TRUE;
113 }
114 
115 // Local Constants
116 static DWORD dwDriverInfo1Offsets[] = {
117     FIELD_OFFSET(DRIVER_INFO_1W, pName),
118     MAXDWORD
119 };
120 
121 static DWORD dwDriverInfo2Offsets[] = {
122     FIELD_OFFSET(DRIVER_INFO_2W, pName),
123     FIELD_OFFSET(DRIVER_INFO_2W, pEnvironment),
124     FIELD_OFFSET(DRIVER_INFO_2W, pDriverPath),
125     FIELD_OFFSET(DRIVER_INFO_2W, pDataFile),
126     FIELD_OFFSET(DRIVER_INFO_2W, pConfigFile),
127     MAXDWORD
128 };
129 
130 static DWORD dwDriverInfo3Offsets[] = {
131     FIELD_OFFSET(DRIVER_INFO_3W, pName),
132     FIELD_OFFSET(DRIVER_INFO_3W, pEnvironment),
133     FIELD_OFFSET(DRIVER_INFO_3W, pDriverPath),
134     FIELD_OFFSET(DRIVER_INFO_3W, pDataFile),
135     FIELD_OFFSET(DRIVER_INFO_3W, pConfigFile),
136     FIELD_OFFSET(DRIVER_INFO_3W, pHelpFile),
137     FIELD_OFFSET(DRIVER_INFO_3W, pDependentFiles),
138     FIELD_OFFSET(DRIVER_INFO_3W, pMonitorName),
139     FIELD_OFFSET(DRIVER_INFO_3W, pDefaultDataType),
140     MAXDWORD
141 };
142 
143 static DWORD dwDriverInfo4Offsets[] = {
144     FIELD_OFFSET(DRIVER_INFO_4W, pName),
145     FIELD_OFFSET(DRIVER_INFO_4W, pEnvironment),
146     FIELD_OFFSET(DRIVER_INFO_4W, pDriverPath),
147     FIELD_OFFSET(DRIVER_INFO_4W, pDataFile),
148     FIELD_OFFSET(DRIVER_INFO_4W, pConfigFile),
149     FIELD_OFFSET(DRIVER_INFO_4W, pHelpFile),
150     FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles),
151     FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName),
152     FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType),
153     FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames),
154     MAXDWORD
155 };
156 
157 static DWORD dwDriverInfo5Offsets[] = {
158     FIELD_OFFSET(DRIVER_INFO_5W, pName),
159     FIELD_OFFSET(DRIVER_INFO_5W, pEnvironment),
160     FIELD_OFFSET(DRIVER_INFO_5W, pDriverPath),
161     FIELD_OFFSET(DRIVER_INFO_5W, pDataFile),
162     FIELD_OFFSET(DRIVER_INFO_5W, pConfigFile),
163     MAXDWORD
164 };
165 
166 static DWORD dwDriverInfo6Offsets[] = {
167     FIELD_OFFSET(DRIVER_INFO_6W, pName),
168     FIELD_OFFSET(DRIVER_INFO_6W, pEnvironment),
169     FIELD_OFFSET(DRIVER_INFO_6W, pDriverPath),
170     FIELD_OFFSET(DRIVER_INFO_6W, pDataFile),
171     FIELD_OFFSET(DRIVER_INFO_6W, pConfigFile),
172     FIELD_OFFSET(DRIVER_INFO_6W, pHelpFile),
173     FIELD_OFFSET(DRIVER_INFO_6W, pDependentFiles),
174     FIELD_OFFSET(DRIVER_INFO_6W, pMonitorName),
175     FIELD_OFFSET(DRIVER_INFO_6W, pDefaultDataType),
176     FIELD_OFFSET(DRIVER_INFO_6W, pszzPreviousNames),
177     FIELD_OFFSET(DRIVER_INFO_6W, pszMfgName),
178     FIELD_OFFSET(DRIVER_INFO_6W, pszOEMUrl),
179     FIELD_OFFSET(DRIVER_INFO_6W, pszHardwareID),
180     FIELD_OFFSET(DRIVER_INFO_6W, pszProvider),
181     MAXDWORD
182 };
183 
184 static DWORD dwDriverInfo8Offsets[] = {
185     FIELD_OFFSET(DRIVER_INFO_8W, pName),
186     FIELD_OFFSET(DRIVER_INFO_8W, pEnvironment),
187     FIELD_OFFSET(DRIVER_INFO_8W, pDriverPath),
188     FIELD_OFFSET(DRIVER_INFO_8W, pDataFile),
189     FIELD_OFFSET(DRIVER_INFO_8W, pConfigFile),
190     FIELD_OFFSET(DRIVER_INFO_8W, pHelpFile),
191     FIELD_OFFSET(DRIVER_INFO_8W, pDependentFiles),
192     FIELD_OFFSET(DRIVER_INFO_8W, pMonitorName),
193     FIELD_OFFSET(DRIVER_INFO_8W, pDefaultDataType),
194     FIELD_OFFSET(DRIVER_INFO_8W, pszzPreviousNames),
195     FIELD_OFFSET(DRIVER_INFO_8W, pszMfgName),
196     FIELD_OFFSET(DRIVER_INFO_8W, pszOEMUrl),
197     FIELD_OFFSET(DRIVER_INFO_8W, pszHardwareID),
198     FIELD_OFFSET(DRIVER_INFO_8W, pszProvider),
199     FIELD_OFFSET(DRIVER_INFO_8W, pszPrintProcessor),
200     FIELD_OFFSET(DRIVER_INFO_8W, pszVendorSetup),
201     FIELD_OFFSET(DRIVER_INFO_8W, pszzColorProfiles),
202     FIELD_OFFSET(DRIVER_INFO_8W, pszInfPath),
203     FIELD_OFFSET(DRIVER_INFO_8W, pszzCoreDriverDependencies),
204     MAXDWORD
205 };
206 
207 static void
208 ToMultiSz(LPWSTR pString)
209 {
210     while (*pString)
211     {
212         if (*pString == '|')
213             *pString = '\0';
214         pString++;
215     }
216 }
217 
218 static void
219 _LocalGetPrinterDriverLevel1(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_1W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
220 {
221     DWORD n;
222     PCWSTR pwszStrings[1];
223 
224     /* This value is only here to send something, I have not verified if it is actually correct */
225     pwszStrings[0] = pPrinter->pwszPrinterDriver;
226 
227     // Calculate the string lengths.
228     if (!ppDriverInfo)
229     {
230         for (n = 0; n < _countof(pwszStrings); ++n)
231         {
232             *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
233         }
234 
235         *pcbNeeded += sizeof(DRIVER_INFO_1W);
236         return;
237     }
238 
239     // Finally copy the structure and advance to the next one in the output buffer.
240     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo1Offsets, *ppDriverInfoEnd);
241     (*ppDriverInfo)++;
242 }
243 
244 static void
245 _LocalGetPrinterDriverLevel2(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_2W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
246 {
247     DWORD n;
248     PCWSTR pwszStrings[5];
249 
250     pwszStrings[0] = pPrinter->pwszPrinterDriver;  // pName
251     pwszStrings[1] = wszCurrentEnvironment;  // pEnvironment
252     pwszStrings[2] = wszDriverPath;          // pDriverPath
253     pwszStrings[3] = wszLocalSplFile;        // pDataFile
254     pwszStrings[4] = wszPrintUiFile;         // pConfigFile
255 
256     // Calculate the string lengths.
257     if (!ppDriverInfo)
258     {
259         for (n = 0; n < _countof(pwszStrings); ++n)
260         {
261             if (pwszStrings[n])
262             {
263                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
264             }
265         }
266 
267         *pcbNeeded += sizeof(DRIVER_INFO_2W);
268         return;
269     }
270 
271     (*ppDriverInfo)->cVersion = 3;
272 
273     // Finally copy the structure and advance to the next one in the output buffer.
274     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo2Offsets, *ppDriverInfoEnd);
275     (*ppDriverInfo)++;
276 }
277 
278 static void
279 _LocalGetPrinterDriverLevel3(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_3W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
280 {
281     DWORD n;
282     PCWSTR pwszStrings[9];
283 
284     pwszStrings[0] = pPrinter->pwszPrinterDriver;  // pName
285     pwszStrings[1] = wszCurrentEnvironment;  // pEnvironment
286     pwszStrings[2] = wszDriverPath;          // pDriverPath
287     pwszStrings[3] = wszLocalSplFile;        // pDataFile
288     pwszStrings[4] = wszPrintUiFile;         // pConfigFile
289     pwszStrings[5] = L"";  // pHelpFile
290     pwszStrings[6] = L"localspl.dll|printui.dll|";  // pDependentFiles, | is separator and terminator!
291     pwszStrings[7] = NULL;
292     if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
293     {
294         pwszStrings[7]  = pPrinter->pPort->pPrintMonitor->pwszName;
295     }
296     pwszStrings[8] = pPrinter->pwszDefaultDatatype;
297 
298 
299     // Calculate the string lengths.
300     if (!ppDriverInfo)
301     {
302         for (n = 0; n < _countof(pwszStrings); ++n)
303         {
304             if (pwszStrings[n])
305             {
306                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
307             }
308         }
309 
310         *pcbNeeded += sizeof(DRIVER_INFO_3W);
311         return;
312     }
313 
314     (*ppDriverInfo)->cVersion = 3;
315 
316     // Finally copy the structure and advance to the next one in the output buffer.
317     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo3Offsets, *ppDriverInfoEnd);
318     ToMultiSz((*ppDriverInfo)->pDependentFiles);
319     (*ppDriverInfo)++;
320 }
321 
322 static void
323 _LocalGetPrinterDriverLevel4(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_4W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
324 {
325     DWORD n;
326     PCWSTR pwszStrings[10];
327 
328     pwszStrings[0] = pPrinter->pwszPrinterDriver;  // pName
329     pwszStrings[1] = wszCurrentEnvironment;  // pEnvironment
330     pwszStrings[2] = wszDriverPath;          // pDriverPath
331     pwszStrings[3] = wszLocalSplFile;        // pDataFile
332     pwszStrings[4] = wszPrintUiFile;         // pConfigFile
333     pwszStrings[5] = L"";  // pHelpFile
334     pwszStrings[6] = L"localspl.dll|printui.dll|";  // pDependentFiles, | is separator and terminator!
335     pwszStrings[7] = NULL;
336     if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
337     {
338         pwszStrings[7] = pPrinter->pPort->pPrintMonitor->pwszName;
339     }
340     pwszStrings[8] = pPrinter->pwszDefaultDatatype;
341     pwszStrings[9] = NULL; // pszzPreviousNames
342 
343     // Calculate the string lengths.
344     if (!ppDriverInfo)
345     {
346         for (n = 0; n < _countof(pwszStrings); ++n)
347         {
348             if (pwszStrings[n])
349             {
350                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
351             }
352         }
353 
354         *pcbNeeded += sizeof(DRIVER_INFO_4W);
355         return;
356     }
357 
358     (*ppDriverInfo)->cVersion = 3;
359 
360     // Finally copy the structure and advance to the next one in the output buffer.
361     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo4Offsets, *ppDriverInfoEnd);
362     ToMultiSz((*ppDriverInfo)->pDependentFiles);
363     (*ppDriverInfo)++;
364 }
365 
366 static void
367 _LocalGetPrinterDriverLevel5(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_5W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
368 {
369     DWORD n;
370     PCWSTR pwszStrings[5];
371 
372     pwszStrings[0] = pPrinter->pwszPrinterDriver;  // pName
373     pwszStrings[1] = wszCurrentEnvironment;  // pEnvironment
374     pwszStrings[2] = wszDriverPath;          // pDriverPath UniDrv.dll
375     pwszStrings[3] = wszLocalSplFile;        // pDataFile.ppd
376     pwszStrings[4] = wszPrintUiFile;         // pConfigFile UniDrvUI.dll
377 
378     // Calculate the string lengths.
379     if (!ppDriverInfo)
380     {
381         for (n = 0; n < _countof(pwszStrings); ++n)
382         {
383             if (pwszStrings[n])
384             {
385                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
386             }
387         }
388 
389         *pcbNeeded += sizeof(DRIVER_INFO_5W);
390         return;
391     }
392 
393     (*ppDriverInfo)->cVersion = 3;
394     // Driver attributes, like UMPD/KMPD.
395     (*ppDriverInfo)->dwDriverAttributes = 0; // UMPD/KMPD, So where are they?
396     // Number of times the configuration file for this driver has been upgraded or downgraded since the last spooler restart.
397     (*ppDriverInfo)->dwConfigVersion = 1;
398     // Number of times the driver file for this driver has been upgraded or downgraded since the last spooler restart.
399     (*ppDriverInfo)->dwDriverVersion = 1;
400 
401     // Finally copy the structure and advance to the next one in the output buffer.
402     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo5Offsets, *ppDriverInfoEnd);
403     (*ppDriverInfo)++;
404 }
405 
406 
407 static void
408 _LocalGetPrinterDriverLevel6(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_6W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
409 {
410     DWORD n;
411     PCWSTR pwszStrings[14];
412 
413     StringCbCopyW(wszScratchPad, sizeof(wszPrintProviderInfo[1]), wszPrintProviderInfo[1]); // Provider Name
414 
415     pwszStrings[0]  = pPrinter->pwszPrinterDriver;  // pName
416     pwszStrings[1]  = wszCurrentEnvironment;  // pEnvironment
417     pwszStrings[2]  = wszDriverPath;          // pDriverPath
418     pwszStrings[3]  = wszLocalSplFile;        // pDataFile
419     pwszStrings[4]  = wszPrintUiFile;         // pConfigFile
420     pwszStrings[5]  = L"";  // pHelpFile
421     pwszStrings[6]  = L"localspl.dll|printui.dll|";  // pDependentFiles, | is separator and terminator!
422     pwszStrings[7]  = NULL;
423     if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
424     {
425         pwszStrings[7] = pPrinter->pPort->pPrintMonitor->pwszName;
426     }
427     pwszStrings[8]  = pPrinter->pwszDefaultDatatype;
428     pwszStrings[9]  = NULL; // pszzPreviousNames
429     pwszStrings[10] = NULL; // pszMfgName
430     pwszStrings[11] = NULL; // pszOEMUrl
431     pwszStrings[12] = NULL; // pszHardwareID
432     pwszStrings[13] = wszScratchPad;
433 
434     // Calculate the string lengths.
435     if (!ppDriverInfo)
436     {
437         for (n = 0; n < _countof(pwszStrings); ++n)
438         {
439             if (pwszStrings[n])
440             {
441                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
442             }
443         }
444 
445         *pcbNeeded += sizeof(DRIVER_INFO_6W);
446         return;
447     }
448 
449     (*ppDriverInfo)->cVersion = 3;
450 
451     // Finally copy the structure and advance to the next one in the output buffer.
452     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo6Offsets, *ppDriverInfoEnd);
453     ToMultiSz((*ppDriverInfo)->pDependentFiles);
454     (*ppDriverInfo)++;
455 }
456 
457 static void
458 _LocalGetPrinterDriverLevel8(PLOCAL_PRINTER pPrinter, PDRIVER_INFO_8W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
459 {
460     DWORD n;
461     PCWSTR pwszStrings[19];
462 
463     StringCbCopyW(wszScratchPad, sizeof(wszPrintProviderInfo[1]), wszPrintProviderInfo[1]); // Provider Name
464 
465     pwszStrings[0]  = pPrinter->pwszPrinterDriver;  // pName
466     pwszStrings[1]  = wszCurrentEnvironment;  // pEnvironment
467     pwszStrings[2]  = wszDriverPath;          // pDriverPath
468     pwszStrings[3]  = wszLocalSplFile;        // pDataFile
469     pwszStrings[4]  = wszPrintUiFile;         // pConfigFile
470     pwszStrings[5]  = L"";  // pHelpFile
471     pwszStrings[6]  = L"localspl.dll|printui.dll|";  // pDependentFiles, | is separator and terminator!
472     pwszStrings[7]  = NULL;
473     if (pPrinter->pPort && pPrinter->pPort->pPrintMonitor)
474     {
475         pwszStrings[7] = pPrinter->pPort->pPrintMonitor->pwszName;
476     }
477     pwszStrings[8]  = pPrinter->pwszDefaultDatatype;
478     pwszStrings[9]  = NULL; // pszzPreviousNames
479     pwszStrings[10] = NULL; // pszMfgName
480     pwszStrings[11] = NULL; // pszOEMUrl
481     pwszStrings[12] = NULL; // pszHardwareID
482     pwszStrings[13] = wszScratchPad;
483     pwszStrings[14] = NULL;
484     if ( pPrinter->pPrintProcessor )
485     {
486         pwszStrings[14] = pPrinter->pPrintProcessor->pwszName;
487     }
488     pwszStrings[15] = NULL; // pszVendorSetup
489     pwszStrings[16] = NULL; // pszzColorProfiles
490     pwszStrings[17] = NULL; // pszInfPath
491     pwszStrings[18] = NULL; // pszzCoreDriverDependencies
492 
493     // Calculate the string lengths.
494     if (!ppDriverInfo)
495     {
496         for (n = 0; n < _countof(pwszStrings); ++n)
497         {
498             if (pwszStrings[n])
499             {
500                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
501             }
502         }
503 
504         *pcbNeeded += sizeof(DRIVER_INFO_8W);
505         return;
506     }
507 
508     (*ppDriverInfo)->cVersion = 3;
509 
510     // Finally copy the structure and advance to the next one in the output buffer.
511     *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo8Offsets, *ppDriverInfoEnd);
512     ToMultiSz((*ppDriverInfo)->pDependentFiles);
513     (*ppDriverInfo)++;
514 }
515 
516 typedef void (*PLocalPrinterDriverLevelFunc)(PLOCAL_PRINTER, PVOID, PBYTE*, PDWORD);
517 
518 static const PLocalPrinterDriverLevelFunc pfnPrinterDriverLevels[] = {
519     NULL,
520     (PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel1,
521     (PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel2,
522     (PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel3,
523     (PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel4,
524     (PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel5,
525     (PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel6,
526     NULL,
527     (PLocalPrinterDriverLevelFunc)&_LocalGetPrinterDriverLevel8
528 };
529 
530 BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
531 {
532     DWORD dwErrorCode;
533     PBYTE pEnd = &pDriverInfo[cbBuf];
534     PLOCAL_HANDLE pHandle;
535     PLOCAL_PRINTER_HANDLE pPrinterHandle;
536 
537     TRACE("LocalGetPrinterDriver(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
538 
539     // Check if this is a printer handle.
540     pHandle = (PLOCAL_HANDLE)hPrinter;
541     if (pHandle->HandleType != HandleType_Printer)
542     {
543         dwErrorCode = ERROR_INVALID_HANDLE;
544         goto Cleanup;
545     }
546 
547     pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
548 
549     // Only support 8 levels and not 7
550     if (Level < 1 || Level == 7 || Level > 8)
551     {
552         // The caller supplied an invalid level.
553         dwErrorCode = ERROR_INVALID_LEVEL;
554         goto Cleanup;
555     }
556 
557     // Count the required buffer size.
558     *pcbNeeded = 0;
559 
560     pfnPrinterDriverLevels[Level](pPrinterHandle->pPrinter, NULL, NULL, pcbNeeded);
561 
562     // Check if the supplied buffer is large enough.
563     if (cbBuf < *pcbNeeded)
564     {
565         ERR("Insuffisient Buffer size\n");
566         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
567         goto Cleanup;
568     }
569 
570     // Copy over the information.
571     pEnd = &pDriverInfo[*pcbNeeded];
572 
573     pfnPrinterDriverLevels[Level](pPrinterHandle->pPrinter, &pDriverInfo, &pEnd, NULL);
574 
575     dwErrorCode = ERROR_SUCCESS;
576 
577 Cleanup:
578     SetLastError(dwErrorCode);
579     return (dwErrorCode == ERROR_SUCCESS);
580 }
581 
582 BOOL WINAPI LocalGetPrinterDriverEx(
583     HANDLE hPrinter,
584     LPWSTR pEnvironment,
585     DWORD Level,
586     LPBYTE pDriverInfo,
587     DWORD cbBuf,
588     LPDWORD pcbNeeded,
589     DWORD dwClientMajorVersion,
590     DWORD dwClientMinorVersion,
591     PDWORD pdwServerMajorVersion,
592     PDWORD pdwServerMinorVersion )
593 {
594     FIXME("LocalGetPrinterDriverEx(%p, %lu, %lu, %p, %lu, %p, %lu, %lu, %p, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, dwClientMajorVersion, dwClientMinorVersion, pdwServerMajorVersion, pdwServerMinorVersion);
595     //// HACK-plement
596     return LocalGetPrinterDriver( hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded );
597 }
598 
599 BOOL WINAPI
600 LocalEnumPrinterDrivers(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
601 {
602     DWORD dwErrorCode;
603     PSKIPLIST_NODE pNode;
604     PBYTE pEnd;
605     PLOCAL_PRINTER pPrinter;
606 
607     FIXME("LocalEnumPrinterDrivers(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned);
608 
609     // Only support 8 levels and not 7
610     if (Level < 1 || Level == 7 || Level > 8)
611     {
612         // The caller supplied an invalid level.
613         dwErrorCode = ERROR_INVALID_LEVEL;
614         goto Cleanup;
615     }
616 
617     // Count the required buffer size.
618     *pcbNeeded = 0;
619 
620     // Count the required buffer size and the number of printers.
621     for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
622     {
623         pPrinter = (PLOCAL_PRINTER)pNode->Element;
624 
625         pfnPrinterDriverLevels[Level](pPrinter, NULL, NULL, pcbNeeded);
626     }
627 
628     // Check if the supplied buffer is large enough.
629     if (cbBuf < *pcbNeeded)
630     {
631         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
632         goto Cleanup;
633     }
634 
635     // Copy over the Printer information.
636     pEnd = &pDriverInfo[*pcbNeeded];
637 
638     for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
639     {
640         pPrinter = (PLOCAL_PRINTER)pNode->Element;
641 
642         pfnPrinterDriverLevels[Level](pPrinter, &pDriverInfo, &pEnd, NULL);
643         (*pcReturned)++;
644     }
645 
646     dwErrorCode = ERROR_SUCCESS;
647 
648 Cleanup:
649     SetLastError(dwErrorCode);
650     return (dwErrorCode == ERROR_SUCCESS);
651 }
652 
653 /******************************************************************
654  * Return the number of bytes for an multi_sz string.
655  * The result includes all \0s
656  * (specifically the extra \0, that is needed as multi_sz terminator).
657  */
658 static int multi_sz_lenW(const WCHAR *str)
659 {
660     const WCHAR *ptr = str;
661     if (!str) return 0;
662     do
663     {
664         ptr += lstrlenW(ptr) + 1;
665     } while (*ptr);
666 
667     return (ptr - str + 1) * sizeof(WCHAR);
668 }
669 
670 
671 /******************************************************************
672  * validate_envW [internal]
673  *
674  * validate the user-supplied printing-environment
675  *
676  * PARAMS
677  *  env  [I] PTR to Environment-String or NULL
678  *
679  * RETURNS
680  *  Success:  PTR to printenv_t
681  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
682  *
683  * NOTES
684  *  An empty string is handled the same way as NULL.
685  *
686  */
687 PPRINTENV_T validate_envW(LPCWSTR env)
688 {
689     PPRINTENV_T result = NULL;
690     unsigned int i;
691 
692     TRACE("(%s)\n", debugstr_w(env));
693     if (env && env[0])
694     {
695         for (i = 0; i < ARRAYSIZE(all_printenv); i++)
696         {
697             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
698             {
699                 result = all_printenv[i];
700                 break;
701             }
702         }
703         if (result == NULL)
704         {
705             FIXME("unsupported Environment: %s\n", debugstr_w(env));
706             SetLastError(ERROR_INVALID_ENVIRONMENT);
707         }
708         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
709     }
710     else
711     {
712         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
713     }
714 
715     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
716     return result;
717 }
718 
719 /*****************************************************************************
720  * open_driver_reg [internal]
721  *
722  * opens the registry for the printer drivers depending on the given input
723  * variable pEnvironment
724  *
725  * RETURNS:
726  *    Success: the opened hkey
727  *    Failure: NULL
728  */
729 HKEY open_driver_reg(LPCWSTR pEnvironment)
730 {
731     HKEY  retval = NULL;
732     LPWSTR buffer;
733     const PRINTENV_T * env;
734 
735     TRACE("(%s)\n", debugstr_w(pEnvironment));
736 
737     env = validate_envW(pEnvironment);
738     if (!env) return NULL;
739 
740     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
741                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
742 
743     if (buffer)
744     {
745         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
746         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
747         HeapFree(GetProcessHeap(), 0, buffer);
748     }
749     return retval;
750 }
751 
752 
753 /******************************************************************************
754  * LocalGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
755  *
756  * Return the PATH for the Print-Processors
757  *
758  * PARAMS
759  *  pName        [I] Servername or NULL (this computer)
760  *  pEnvironment [I] Printing-Environment or NULL (Default)
761  *  level        [I] Structure-Level (must be 1)
762  *  pPPInfo      [O] PTR to Buffer that receives the Result
763  *  cbBuf        [I] Size of Buffer at pPPInfo
764  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
765  *
766  * RETURNS
767  *  Success: TRUE
768  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
769  *
770  *  Native Values returned in pPPInfo on Success for this computer:
771  *| NT(Windows x64):    "%winsysdir%\\spool\\PRTPROCS\\x64"
772  *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
773  *| NT(Windows 4.0):    "%winsysdir%\\spool\\PRTPROCS\\win40"
774  *
775  *  "%winsysdir%" is the Value from GetSystemDirectoryW()
776  *
777  */
778 BOOL WINAPI LocalGetPrinterDriverDirectory(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
779 {
780     DWORD needed;
781     const PRINTENV_T * env = NULL;
782     WCHAR * const dir = (WCHAR *)pDriverDirectory;
783 
784     FIXME("LocalGetPrinterDriverDirectory(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
785 
786     if (pName != NULL && pName[0])
787     {
788         FIXME("server %s not supported\n", debugstr_w(pName));
789         SetLastError(ERROR_INVALID_PARAMETER);
790         return FALSE;
791     }
792 
793     env = validate_envW(pEnvironment);
794     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
795 
796     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
797     needed = GetSystemDirectoryW(NULL, 0);
798     /* add the Size for the Subdirectories */
799     needed += lstrlenW(spoolW);
800     needed += lstrlenW(driversW);
801     needed += lstrlenW(env->subdir);
802     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
803 
804     *pcbNeeded = needed;
805 
806     if (needed > cbBuf)
807     {
808         SetLastError(ERROR_INSUFFICIENT_BUFFER);
809         return FALSE;
810     }
811 
812     if (dir == NULL)
813     {
814         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
815         SetLastError(ERROR_INVALID_USER_BUFFER);
816         return FALSE;
817     }
818 
819     GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
820     /* add the Subdirectories */
821     lstrcatW( dir, spoolW );
822     CreateDirectoryW( dir, NULL );
823     lstrcatW( dir, driversW );
824     CreateDirectoryW( dir, NULL );
825     lstrcatW( dir, env->subdir );
826     CreateDirectoryW( dir, NULL );
827 
828     FIXME( "=> %s\n", debugstr_w( dir ) );
829     return TRUE;
830 }
831 
832 /******************************************************************
833  *  apd_copyfile [internal]
834  *
835  * Copy a file from the driverdirectory to the versioned directory
836  *
837  * RETURNS
838  *  Success: TRUE
839  *  Failure: FALSE
840  *
841  */
842 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
843 {
844     WCHAR *srcname;
845     BOOL res;
846 
847     apd->src[apd->srclen] = '\0';
848     apd->dst[apd->dstlen] = '\0';
849 
850     if (!pathname || !pathname[0]) {
851         /* nothing to copy */
852         return TRUE;
853     }
854 
855     if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
856         srcname = pathname;
857     else
858     {
859         srcname = apd->src;
860         lstrcatW( srcname, file_part );
861     }
862     lstrcatW( apd->dst, file_part );
863 
864     FIXME("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
865 
866     /* FIXME: handle APD_COPY_NEW_FILES */
867     res = CopyFileW(srcname, apd->dst, FALSE);
868     FIXME("got %d with %u\n", res, GetLastError());
869 
870     return apd->lazy || res;
871 }
872 
873 /******************************************************************
874  * driver_load [internal]
875  *
876  * load a driver user interface dll
877  *
878  * On failure, NULL is returned
879  *
880  */
881 
882 static HMODULE driver_load(const PRINTENV_T * env, LPWSTR dllname)
883 {
884     WCHAR fullname[MAX_PATH];
885     HMODULE hui;
886     DWORD len;
887 
888     FIXME("(%p, %s)\n", env, debugstr_w(dllname));
889 
890     /* build the driverdir */
891     len = sizeof(fullname) - (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
892 
893     if (!LocalGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1, (LPBYTE) fullname, len, &len))
894     {
895         /* Should never fail */
896         SetLastError(ERROR_BUFFER_OVERFLOW);
897         return NULL;
898     }
899 
900     lstrcatW(fullname, env->versionsubdir);
901     lstrcatW(fullname, backslashW);
902     lstrcatW(fullname, dllname);
903 
904     hui = LoadLibraryW(fullname);
905     FIXME("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
906 
907     return hui;
908 }
909 
910 static inline WCHAR *get_file_part( WCHAR *name )
911 {
912     WCHAR *ptr = wcsrchr( name, '\\' );
913     if (ptr) return ptr + 1;
914     return name;
915 }
916 
917 /******************************************************************************
918  *  myAddPrinterDriverEx [internal]
919  *
920  * Install a Printer Driver with the Option to upgrade / downgrade the Files
921  * and a special mode with lazy error checking.
922  *
923  */
924 BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
925 {
926     const PRINTENV_T *env;
927     apd_data_t apd;
928     DRIVER_INFO_8W di;
929     BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
930     HMODULE hui;
931     WCHAR *file;
932     HKEY    hroot;
933     HKEY    hdrv;
934     DWORD   disposition;
935     DWORD   len;
936     LONG    lres;
937     BOOL    res;
938 
939     /* we need to set all entries in the Registry, independent from the Level of
940        DRIVER_INFO, that the caller supplied */
941 
942     ZeroMemory(&di, sizeof(di));
943     if (pDriverInfo && (level < ARRAYSIZE(di_sizeof)))
944     {
945         memcpy(&di, pDriverInfo, di_sizeof[level]);
946     }
947 
948     /* dump the most used infos */
949     FIXME("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
950     FIXME("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
951     FIXME("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
952     FIXME("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
953     FIXME("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
954     FIXME("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
955     FIXME("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
956     /* dump only the first of the additional Files */
957     FIXME("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
958 
959 
960     /* check environment */
961     env = validate_envW(di.pEnvironment);
962     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
963 
964     /* fill the copy-data / get the driverdir */
965     len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
966     if (!LocalGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1, (LPBYTE) apd.src, len, &len))
967     {
968         /* Should never fail */
969         return FALSE;
970     }
971     memcpy(apd.dst, apd.src, len);
972     lstrcatW(apd.src, backslashW);
973     apd.srclen = lstrlenW(apd.src);
974     lstrcatW(apd.dst, env->versionsubdir);
975     lstrcatW(apd.dst, backslashW);
976     apd.dstlen = lstrlenW(apd.dst);
977     apd.copyflags = dwFileCopyFlags;
978     apd.lazy = lazy;
979     CreateDirectoryW(apd.src, NULL);
980     CreateDirectoryW(apd.dst, NULL);
981 
982     hroot = open_driver_reg(env->envname);
983     if (!hroot)
984     {
985         ERR("Can't create Drivers key\n");
986         return FALSE;
987     }
988 
989     /* Fill the Registry for the Driver */
990     if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
991                                 KEY_WRITE | KEY_QUERY_VALUE, NULL,
992                                 &hdrv, &disposition)) != ERROR_SUCCESS)
993     {
994         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
995         RegCloseKey(hroot);
996         SetLastError(lres);
997         return FALSE;
998     }
999     RegCloseKey(hroot);
1000 
1001     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1002     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1003                    sizeof(DWORD));
1004 
1005     file = get_file_part( di.pDriverPath );
1006     RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1007     apd_copyfile( di.pDriverPath, file, &apd );
1008 
1009     file = get_file_part( di.pDataFile );
1010     RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1011     apd_copyfile( di.pDataFile, file, &apd );
1012 
1013     file = get_file_part( di.pConfigFile );
1014     RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1015     apd_copyfile( di.pConfigFile, file, &apd );
1016 
1017     /* settings for level 3 */
1018     if (di.pHelpFile)
1019     {
1020         file = get_file_part( di.pHelpFile );
1021         RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1022         apd_copyfile( di.pHelpFile, file, &apd );
1023     }
1024     else
1025         RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
1026 
1027     if (di.pDependentFiles && *di.pDependentFiles)
1028     {
1029         WCHAR *reg, *reg_ptr, *in_ptr;
1030         reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1031 
1032         for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += lstrlenW( in_ptr ) + 1)
1033         {
1034             file = get_file_part( in_ptr );
1035             len = lstrlenW( file ) + 1;
1036             memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1037             reg_ptr += len;
1038             apd_copyfile( in_ptr, file, &apd );
1039         }
1040         *reg_ptr = 0;
1041 
1042         RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1043         HeapFree( GetProcessHeap(), 0, reg );
1044     }
1045     else
1046         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1047 
1048     /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1049     if (di.pMonitorName)
1050         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1051                        (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1052     else
1053         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1054 
1055     if (di.pDefaultDataType)
1056         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1057                        (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1058     else
1059         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1060 
1061     /* settings for level 4 */
1062     if (di.pszzPreviousNames)
1063         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1064                        multi_sz_lenW(di.pszzPreviousNames));
1065     else
1066         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1067 
1068     if (level > 5) FIXME("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1069 
1070     RegCloseKey(hdrv);
1071 
1072     //
1073     // Locate driver and send the event.
1074     //
1075 
1076     hui = driver_load(env, di.pConfigFile);
1077 
1078     pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1079 
1080     if (hui && pDrvDriverEvent)
1081     {
1082         /* Support for DrvDriverEvent is optional */
1083         TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1084         /* MSDN: level for DRIVER_INFO is 1 to 3 */
1085         res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1086         TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1087     }
1088     FreeLibrary(hui);
1089 
1090     FIXME("=> TRUE with %u\n", GetLastError());
1091     return TRUE;
1092 }
1093 
1094 /******************************************************************************
1095  * AddPrinterDriverEx [exported through PRINTPROVIDOR]
1096  *
1097  * Install a Printer Driver with the Option to upgrade / downgrade the Files
1098  *
1099  * PARAMS
1100  *  pName           [I] Servername or NULL (local Computer)
1101  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
1102  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1103  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1104  *
1105  * RESULTS
1106  *  Success: TRUE
1107  *  Failure: FALSE
1108  *
1109  */
1110 BOOL WINAPI LocalAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1111 {
1112     LONG lres;
1113 
1114     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1115 
1116     lres = copy_servername_from_name(pName, NULL);
1117 
1118     if (lres)
1119     {
1120         FIXME("server %s not supported\n", debugstr_w(pName));
1121         SetLastError(ERROR_ACCESS_DENIED);
1122         return FALSE;
1123     }
1124 
1125     if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES)
1126     {
1127         TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1128     }
1129 
1130     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1131 }
1132 
1133 BOOL WINAPI LocalAddPrinterDriver(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
1134 {
1135     LONG lres;
1136 
1137     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo);
1138 
1139     lres = copy_servername_from_name(pName, NULL);
1140 
1141     if (lres)
1142     {
1143         FIXME("server %s not supported\n", debugstr_w(pName));
1144         SetLastError(ERROR_ACCESS_DENIED);
1145         return FALSE;
1146     }
1147 
1148     // Should be APD_COPY_NEW_FILES. Cheap wine.
1149 
1150     return myAddPrinterDriverEx(level, pDriverInfo, APD_COPY_NEW_FILES, TRUE);
1151 }
1152