crypt32: Support the KeyId type of signer in CMSG_SIGNER_INFO_PARAM.
[wine] / dlls / localspl / localspl_main.c
1 /*
2  * Implementation of the Local Printmonitor
3  *
4  * Copyright 2006-2008 Detlef Riekenberg
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winspool.h"
31 #include "ddk/winsplp.h"
32 #include "winuser.h"
33
34 #include "wine/list.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "localspl_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
40
41 /* ############################### */
42
43 typedef struct {
44     WCHAR   src[MAX_PATH+MAX_PATH];
45     WCHAR   dst[MAX_PATH+MAX_PATH];
46     DWORD   srclen;
47     DWORD   dstlen;
48     DWORD   copyflags;
49     BOOL    lazy;
50 } apd_data_t;
51
52 typedef struct {
53     struct list     entry;
54     LPWSTR          name;
55     LPWSTR          dllname;
56     PMONITORUI      monitorUI;
57     LPMONITOR       monitor;
58     HMODULE         hdll;
59     DWORD           refcount;
60     DWORD           dwMonitorSize;
61 } monitor_t;
62
63 typedef struct {
64     LPCWSTR  envname;
65     LPCWSTR  subdir;
66     DWORD    driverversion;
67     LPCWSTR  versionregpath;
68     LPCWSTR  versionsubdir;
69 } printenv_t;
70
71
72 /* ############################### */
73
74 HINSTANCE LOCALSPL_hInstance = NULL;
75
76 static const PRINTPROVIDOR * pp = NULL;
77
78 static const WCHAR backslashW[] = {'\\',0};
79 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
80 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
81 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
82 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
83 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
84 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
85 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
86 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
87                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
88                                   'c','o','n','t','r','o','l','\\',
89                                   'P','r','i','n','t','\\',
90                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
91                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
92 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
93 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
94 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
95 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
96 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
97 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
98                                 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
99                                 'C','o','n','t','r','o','l','\\',
100                                 'P','r','i','n','t','\\',
101                                 'M','o','n','i','t','o','r','s','\\',0};
102 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
103 static const WCHAR nameW[] = {'N','a','m','e',0};
104 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
105 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
106 static const WCHAR portW[] = {'P','o','r','t',0};
107 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
108 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
109 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
110
111 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
112 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
113 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
114 static const WCHAR version0_subdirW[] = {'\\','0',0};
115
116 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
117 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
118 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
119 static const WCHAR version3_subdirW[] = {'\\','3',0};
120
121
122 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
123                                      version3_regpathW, version3_subdirW};
124
125 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
126                                      version0_regpathW, version0_subdirW};
127
128 static const printenv_t * const all_printenv[] = {&env_x86, &env_win40};
129
130
131 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
132                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
133                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
134                                   0, sizeof(DRIVER_INFO_8W)};
135
136
137 /******************************************************************
138  *  apd_copyfile [internal]
139  *
140  * Copy a file from the driverdirectory to the versioned directory
141  *
142  * RETURNS
143  *  Success: TRUE
144  *  Failure: FALSE
145  *
146  */
147 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
148 {
149     LPWSTR  ptr;
150     LPWSTR  srcname;
151     DWORD   res;
152
153     apd->src[apd->srclen] = '\0';
154     apd->dst[apd->dstlen] = '\0';
155
156     if (!filename || !filename[0]) {
157         /* nothing to copy */
158         return TRUE;
159     }
160
161     ptr = strrchrW(filename, '\\');
162     if (ptr) {
163         ptr++;
164     }
165     else
166     {
167         ptr = filename;
168     }
169
170     if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
171         /* we have an absolute Path */
172         srcname = filename;
173     }
174     else
175     {
176         srcname = apd->src;
177         lstrcatW(srcname, ptr);
178     }
179     lstrcatW(apd->dst, ptr);
180
181     TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
182
183     /* FIXME: handle APD_COPY_NEW_FILES */
184     res = CopyFileW(srcname, apd->dst, FALSE);
185     TRACE("got %u with %u\n", res, GetLastError());
186
187     return (apd->lazy) ? TRUE : res;
188 }
189
190 /******************************************************************
191  * copy_servername_from_name  (internal)
192  *
193  * for an external server, the serverpart from the name is copied.
194  *
195  * RETURNS
196  *  the length (in WCHAR) of the serverpart (0 for the local computer)
197  *  (-length), when the name is to long
198  *
199  */
200 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
201 {
202     LPCWSTR server;
203     LPWSTR  ptr;
204     WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
205     DWORD   len;
206     DWORD   serverlen;
207
208     if (target) *target = '\0';
209
210     if (name == NULL) return 0;
211     if ((name[0] != '\\') || (name[1] != '\\')) return 0;
212
213     server = &name[2];
214     /* skip over both backslash, find separator '\' */
215     ptr = strchrW(server, '\\');
216     serverlen = (ptr) ? ptr - server : lstrlenW(server);
217
218     /* servername is empty or to long */
219     if (serverlen == 0) return 0;
220
221     TRACE("found %s\n", debugstr_wn(server, serverlen));
222
223     if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
224
225     len = sizeof(buffer) / sizeof(buffer[0]);
226     if (GetComputerNameW(buffer, &len)) {
227         if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
228             /* The requested Servername is our computername */
229             if (target) {
230                 memcpy(target, server, serverlen * sizeof(WCHAR));
231                 target[serverlen] = '\0';
232             }
233             return serverlen;
234         }
235     }
236     return 0;
237 }
238
239 /******************************************************************
240  * Return the number of bytes for an multi_sz string.
241  * The result includes all \0s
242  * (specifically the extra \0, that is needed as multi_sz terminator).
243  */
244 static int multi_sz_lenW(const WCHAR *str)
245 {
246     const WCHAR *ptr = str;
247     if (!str) return 0;
248     do
249     {
250         ptr += lstrlenW(ptr) + 1;
251     } while (*ptr);
252
253     return (ptr - str + 1) * sizeof(WCHAR);
254 }
255
256 /******************************************************************
257  * validate_envW [internal]
258  *
259  * validate the user-supplied printing-environment
260  *
261  * PARAMS
262  *  env  [I] PTR to Environment-String or NULL
263  *
264  * RETURNS
265  *  Success:  PTR to printenv_t
266  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
267  *
268  * NOTES
269  *  An empty string is handled the same way as NULL.
270  *
271  */
272
273 static const  printenv_t * validate_envW(LPCWSTR env)
274 {
275     const printenv_t *result = NULL;
276     unsigned int i;
277
278     TRACE("(%s)\n", debugstr_w(env));
279     if (env && env[0])
280     {
281         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
282         {
283             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
284             {
285                 result = all_printenv[i];
286                 break;
287             }
288         }
289         if (result == NULL) {
290             FIXME("unsupported Environment: %s\n", debugstr_w(env));
291             SetLastError(ERROR_INVALID_ENVIRONMENT);
292         }
293         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
294     }
295     else
296     {
297         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
298     }
299
300     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
301     return result;
302 }
303
304 /*****************************************************************************
305  * enumerate the local monitors (INTERNAL)
306  *
307  * returns the needed size (in bytes) for pMonitors
308  * and  *lpreturned is set to number of entries returned in pMonitors
309  *
310  * Language-Monitors are also installed in the same Registry-Location but
311  * they are filtered in Windows (not returned by EnumMonitors).
312  * We do no filtering to simplify our Code.
313  *
314  */
315 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
316 {
317     HKEY    hroot = NULL;
318     HKEY    hentry = NULL;
319     LPWSTR  ptr;
320     LPMONITOR_INFO_2W mi;
321     WCHAR   buffer[MAX_PATH];
322     WCHAR   dllname[MAX_PATH];
323     DWORD   dllsize;
324     DWORD   len;
325     DWORD   index = 0;
326     DWORD   needed = 0;
327     DWORD   numentries;
328     DWORD   entrysize;
329
330     entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
331
332     numentries = *lpreturned;       /* this is 0, when we scan the registry */
333     len = entrysize * numentries;
334     ptr = (LPWSTR) &pMonitors[len];
335
336     numentries = 0;
337     len = sizeof(buffer)/sizeof(buffer[0]);
338     buffer[0] = '\0';
339
340     /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
341     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
342         /* Scan all Monitor-Registry-Keys */
343         while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
344             TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
345             dllsize = sizeof(dllname);
346             dllname[0] = '\0';
347
348             /* The Monitor must have a Driver-DLL */
349             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
350                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
351                     /* We found a valid DLL for this Monitor. */
352                     TRACE("using Driver: %s\n", debugstr_w(dllname));
353                 }
354                 RegCloseKey(hentry);
355             }
356
357             /* Windows returns only Port-Monitors here, but to simplify our code,
358                we do no filtering for Language-Monitors */
359             if (dllname[0]) {
360                 numentries++;
361                 needed += entrysize;
362                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
363                 if (level > 1) {
364                     /* we install and return only monitors for "Windows NT x86" */
365                     needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
366                     needed += dllsize;
367                 }
368
369                 /* required size is calculated. Now fill the user-buffer */
370                 if (pMonitors && (cbBuf >= needed)){
371                     mi = (LPMONITOR_INFO_2W) pMonitors;
372                     pMonitors += entrysize;
373
374                     TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
375                     mi->pName = ptr;
376                     lstrcpyW(ptr, buffer);      /* Name of the Monitor */
377                     ptr += (len+1);               /* len is lstrlenW(monitorname) */
378                     if (level > 1) {
379                         mi->pEnvironment = ptr;
380                         lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
381                         ptr += (lstrlenW(x86_envnameW)+1);
382
383                         mi->pDLLName = ptr;
384                         lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
385                         ptr += (dllsize / sizeof(WCHAR));
386                     }
387                 }
388             }
389             index++;
390             len = sizeof(buffer)/sizeof(buffer[0]);
391             buffer[0] = '\0';
392         }
393         RegCloseKey(hroot);
394     }
395     *lpreturned = numentries;
396     TRACE("need %d byte for %d entries\n", needed, numentries);
397     return needed;
398 }
399
400 /*****************************************************************************
401  * open_driver_reg [internal]
402  *
403  * opens the registry for the printer drivers depending on the given input
404  * variable pEnvironment
405  *
406  * RETURNS:
407  *    Success: the opened hkey
408  *    Failure: NULL
409  */
410 static HKEY open_driver_reg(LPCWSTR pEnvironment)
411 {
412     HKEY  retval = NULL;
413     LPWSTR buffer;
414     const printenv_t * env;
415
416     TRACE("(%s)\n", debugstr_w(pEnvironment));
417
418     env = validate_envW(pEnvironment);
419     if (!env) return NULL;
420
421     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
422                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
423
424     if (buffer) {
425         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
426         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
427         HeapFree(GetProcessHeap(), 0, buffer);
428     }
429     return retval;
430 }
431
432 /*****************************************************************************
433  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
434  *
435  * Return the PATH for the Printer-Drivers
436  *
437  * PARAMS
438  *   pName            [I] Servername (NT only) or NULL (local Computer)
439  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
440  *   Level            [I] Structure-Level (must be 1)
441  *   pDriverDirectory [O] PTR to Buffer that receives the Result
442  *   cbBuf            [I] Size of Buffer at pDriverDirectory
443  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
444  *                        required for pDriverDirectory
445  *
446  * RETURNS
447  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
448  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
449  *            if cbBuf is too small
450  *
451  *   Native Values returned in pDriverDirectory on Success:
452  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
453  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
454  *|  win9x(Windows 4.0):  "%winsysdir%"
455  *
456  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
457  *
458  */
459 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
460             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
461 {
462     DWORD needed;
463     const printenv_t * env;
464
465     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
466           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
467
468     if (pName != NULL && pName[0]) {
469         FIXME("server %s not supported\n", debugstr_w(pName));
470         SetLastError(ERROR_INVALID_PARAMETER);
471         return FALSE;
472     }
473
474     env = validate_envW(pEnvironment);
475     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
476
477
478     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
479     needed = GetSystemDirectoryW(NULL, 0);
480     /* add the Size for the Subdirectories */
481     needed += lstrlenW(spooldriversW);
482     needed += lstrlenW(env->subdir);
483     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
484
485     *pcbNeeded = needed;
486
487     if (needed > cbBuf) {
488         SetLastError(ERROR_INSUFFICIENT_BUFFER);
489         return FALSE;
490     }
491
492     if (pDriverDirectory == NULL) {
493         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
494         SetLastError(ERROR_INVALID_USER_BUFFER);
495         return FALSE;
496     }
497
498     GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
499     /* add the Subdirectories */
500     lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
501     lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
502
503     TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
504     return TRUE;
505 }
506
507 /******************************************************************************
508  *  myAddPrinterDriverEx [internal]
509  *
510  * Install a Printer Driver with the Option to upgrade / downgrade the Files
511  * and a special mode with lazy error checking.
512  *
513  */
514 static BOOL WINAPI myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
515 {
516     static const WCHAR emptyW[1];
517     const printenv_t *env;
518     apd_data_t apd;
519     DRIVER_INFO_8W di;
520     LPWSTR  ptr;
521     HKEY    hroot;
522     HKEY    hdrv;
523     DWORD   disposition;
524     DWORD   len;
525     LONG    lres;
526
527     /* we need to set all entries in the Registry, independent from the Level of
528        DRIVER_INFO, that the caller supplied */
529
530     ZeroMemory(&di, sizeof(di));
531     if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
532         memcpy(&di, pDriverInfo, di_sizeof[level]);
533     }
534
535     /* dump the most used infos */
536     TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
537     TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
538     TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
539     TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
540     TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
541     TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
542     TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
543     /* dump only the first of the additional Files */
544     TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
545
546
547     /* check environment */
548     env = validate_envW(di.pEnvironment);
549     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
550
551     /* fill the copy-data / get the driverdir */
552     len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
553     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
554                                     (LPBYTE) apd.src, len, &len)) {
555         /* Should never Fail */
556         return FALSE;
557     }
558     memcpy(apd.dst, apd.src, len);
559     lstrcatW(apd.src, backslashW);
560     apd.srclen = lstrlenW(apd.src);
561     lstrcatW(apd.dst, env->versionsubdir);
562     lstrcatW(apd.dst, backslashW);
563     apd.dstlen = lstrlenW(apd.dst);
564     apd.copyflags = dwFileCopyFlags;
565     apd.lazy = lazy;
566     CreateDirectoryW(apd.src, NULL);
567     CreateDirectoryW(apd.dst, NULL);
568
569     hroot = open_driver_reg(env->envname);
570     if (!hroot) {
571         ERR("Can't create Drivers key\n");
572         return FALSE;
573     }
574
575     /* Fill the Registry for the Driver */
576     if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
577                                 KEY_WRITE | KEY_QUERY_VALUE, NULL,
578                                 &hdrv, &disposition)) != ERROR_SUCCESS) {
579
580         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
581         RegCloseKey(hroot);
582         SetLastError(lres);
583         return FALSE;
584     }
585     RegCloseKey(hroot);
586
587     if (disposition == REG_OPENED_EXISTING_KEY) {
588         TRACE("driver %s already installed\n", debugstr_w(di.pName));
589         RegCloseKey(hdrv);
590         SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
591         return FALSE;
592     }
593
594     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
595     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
596                    sizeof(DWORD));
597
598     RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
599                    (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
600     apd_copyfile(di.pDriverPath, &apd);
601
602     RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
603                    (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
604     apd_copyfile(di.pDataFile, &apd);
605
606     RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
607                    (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
608     apd_copyfile(di.pConfigFile, &apd);
609
610     /* settings for level 3 */
611     if (di.pHelpFile)
612         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
613                        (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
614     else
615         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
616     apd_copyfile(di.pHelpFile, &apd);
617
618
619     ptr = di.pDependentFiles;
620     if (ptr)
621         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
622                        multi_sz_lenW(di.pDependentFiles));
623     else
624         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
625     while ((ptr != NULL) && (ptr[0])) {
626         if (apd_copyfile(ptr, &apd)) {
627             ptr += lstrlenW(ptr) + 1;
628         }
629         else
630         {
631             WARN("Failed to copy %s\n", debugstr_w(ptr));
632             ptr = NULL;
633         }
634     }
635     /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
636     if (di.pMonitorName)
637         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
638                        (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
639     else
640         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
641
642     if (di.pDefaultDataType)
643         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
644                        (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
645     else
646         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
647
648     /* settings for level 4 */
649     if (di.pszzPreviousNames)
650         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
651                        multi_sz_lenW(di.pszzPreviousNames));
652     else
653         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
654
655     if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
656
657     RegCloseKey(hdrv);
658     TRACE("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
659
660     TRACE("=> TRUE with %u\n", GetLastError());
661     return TRUE;
662
663 }
664
665 /******************************************************************************
666  * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
667  *
668  * Install a Printer Driver with the Option to upgrade / downgrade the Files
669  *
670  * PARAMS
671  *  pName           [I] Servername or NULL (local Computer)
672  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
673  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
674  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
675  *
676  * RESULTS
677  *  Success: TRUE
678  *  Failure: FALSE
679  *
680  */
681 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
682 {
683     LONG lres;
684
685     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
686     lres = copy_servername_from_name(pName, NULL);
687     if (lres) {
688         FIXME("server %s not supported\n", debugstr_w(pName));
689         SetLastError(ERROR_ACCESS_DENIED);
690         return FALSE;
691     }
692
693     if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
694         TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
695     }
696
697     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
698 }
699 /******************************************************************
700  * fpDeleteMonitor [exported through PRINTPROVIDOR]
701  *
702  * Delete a specific Printmonitor from a Printing-Environment
703  *
704  * PARAMS
705  *  pName        [I] Servername or NULL (local Computer)
706  *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
707  *  pMonitorName [I] Name of the Monitor, that should be deleted
708  *
709  * RETURNS
710  *  Success: TRUE
711  *  Failure: FALSE
712  *
713  * NOTES
714  *  pEnvironment is ignored in Windows for the local Computer.
715  *
716  */
717
718 BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
719 {
720     HKEY    hroot = NULL;
721     LONG    lres;
722
723     TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
724            debugstr_w(pMonitorName));
725
726     lres = copy_servername_from_name(pName, NULL);
727     if (lres) {
728         FIXME("server %s not supported\n", debugstr_w(pName));
729         SetLastError(ERROR_INVALID_NAME);
730         return FALSE;
731     }
732
733     /*  pEnvironment is ignored in Windows for the local Computer */
734     if (!pMonitorName || !pMonitorName[0]) {
735         TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
736         SetLastError(ERROR_INVALID_PARAMETER);
737         return FALSE;
738     }
739
740     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
741         ERR("unable to create key %s\n", debugstr_w(monitorsW));
742         return FALSE;
743     }
744
745     if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
746         TRACE("%s deleted\n", debugstr_w(pMonitorName));
747         RegCloseKey(hroot);
748         return TRUE;
749     }
750
751     TRACE("%s does not exist\n", debugstr_w(pMonitorName));
752     RegCloseKey(hroot);
753
754     /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
755     SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
756     return FALSE;
757 }
758
759 /*****************************************************************************
760  * fpEnumMonitors [exported through PRINTPROVIDOR]
761  *
762  * Enumerate available Port-Monitors
763  *
764  * PARAMS
765  *  pName       [I] Servername or NULL (local Computer)
766  *  Level       [I] Structure-Level (1:Win9x+NT or 2:NT only)
767  *  pMonitors   [O] PTR to Buffer that receives the Result
768  *  cbBuf       [I] Size of Buffer at pMonitors
769  *  pcbNeeded   [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
770  *  pcReturned  [O] PTR to DWORD that receives the number of Monitors in pMonitors
771  *
772  * RETURNS
773  *  Success: TRUE
774  *  Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
775  *
776  * NOTES
777  *  Windows reads the Registry once and cache the Results.
778  *
779  */
780 BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
781                             LPDWORD pcbNeeded, LPDWORD pcReturned)
782 {
783     DWORD   numentries = 0;
784     DWORD   needed = 0;
785     LONG    lres;
786     BOOL    res = FALSE;
787
788     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
789           cbBuf, pcbNeeded, pcReturned);
790
791     lres = copy_servername_from_name(pName, NULL);
792     if (lres) {
793         FIXME("server %s not supported\n", debugstr_w(pName));
794         SetLastError(ERROR_INVALID_NAME);
795         goto em_cleanup;
796     }
797
798     if (!Level || (Level > 2)) {
799         WARN("level (%d) is ignored in win9x\n", Level);
800         SetLastError(ERROR_INVALID_LEVEL);
801         return FALSE;
802     }
803
804     /* Scan all Monitor-Keys */
805     numentries = 0;
806     needed = get_local_monitors(Level, NULL, 0, &numentries);
807
808     /* we calculated the needed buffersize. now do more error-checks */
809     if (cbBuf < needed) {
810         SetLastError(ERROR_INSUFFICIENT_BUFFER);
811         goto em_cleanup;
812     }
813
814     /* fill the Buffer with the Monitor-Keys */
815     needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
816     res = TRUE;
817
818 em_cleanup:
819     if (pcbNeeded)  *pcbNeeded = needed;
820     if (pcReturned) *pcReturned = numentries;
821
822     TRACE("returning %d with %d (%d byte for %d entries)\n",
823             res, GetLastError(), needed, numentries);
824
825     return (res);
826 }
827
828 /*****************************************************
829  *  get_backend [internal]
830  */
831 static const PRINTPROVIDOR * get_backend(void)
832 {
833     static const PRINTPROVIDOR backend = {
834         NULL,   /* fpOpenPrinter */
835         NULL,   /* fpSetJob */
836         NULL,   /* fpGetJob */
837         NULL,   /* fpEnumJobs */
838         NULL,   /* fpAddPrinter */
839         NULL,   /* fpDeletePrinter */
840         NULL,   /* fpSetPrinter */
841         NULL,   /* fpGetPrinter */
842         NULL,   /* fpEnumPrinters */
843         NULL,   /* fpAddPrinterDriver */
844         NULL,   /* fpEnumPrinterDrivers */
845         NULL,   /* fpGetPrinterDriver */
846         fpGetPrinterDriverDirectory,
847         NULL,   /* fpDeletePrinterDriver */
848         NULL,   /* fpAddPrintProcessor */
849         NULL,   /* fpEnumPrintProcessors */
850         NULL,   /* fpGetPrintProcessorDirectory */
851         NULL,   /* fpDeletePrintProcessor */
852         NULL,   /* fpEnumPrintProcessorDatatypes */
853         NULL,   /* fpStartDocPrinter */
854         NULL,   /* fpStartPagePrinter */
855         NULL,   /* fpWritePrinter */
856         NULL,   /* fpEndPagePrinter */
857         NULL,   /* fpAbortPrinter */
858         NULL,   /* fpReadPrinter */
859         NULL,   /* fpEndDocPrinter */
860         NULL,   /* fpAddJob */
861         NULL,   /* fpScheduleJob */
862         NULL,   /* fpGetPrinterData */
863         NULL,   /* fpSetPrinterData */
864         NULL,   /* fpWaitForPrinterChange */
865         NULL,   /* fpClosePrinter */
866         NULL,   /* fpAddForm */
867         NULL,   /* fpDeleteForm */
868         NULL,   /* fpGetForm */
869         NULL,   /* fpSetForm */
870         NULL,   /* fpEnumForms */
871         fpEnumMonitors,
872         NULL,   /* fpEnumPorts */
873         NULL,   /* fpAddPort */
874         NULL,   /* fpConfigurePort */
875         NULL,   /* fpDeletePort */
876         NULL,   /* fpCreatePrinterIC */
877         NULL,   /* fpPlayGdiScriptOnPrinterIC */
878         NULL,   /* fpDeletePrinterIC */
879         NULL,   /* fpAddPrinterConnection */
880         NULL,   /* fpDeletePrinterConnection */
881         NULL,   /* fpPrinterMessageBox */
882         NULL,   /* fpAddMonitor */
883         fpDeleteMonitor,
884         NULL,   /* fpResetPrinter */
885         NULL,   /* fpGetPrinterDriverEx */
886         NULL,   /* fpFindFirstPrinterChangeNotification */
887         NULL,   /* fpFindClosePrinterChangeNotification */
888         NULL,   /* fpAddPortEx */
889         NULL,   /* fpShutDown */
890         NULL,   /* fpRefreshPrinterChangeNotification */
891         NULL,   /* fpOpenPrinterEx */
892         NULL,   /* fpAddPrinterEx */
893         NULL,   /* fpSetPort */
894         NULL,   /* fpEnumPrinterData */
895         NULL,   /* fpDeletePrinterData */
896         NULL,   /* fpClusterSplOpen */
897         NULL,   /* fpClusterSplClose */
898         NULL,   /* fpClusterSplIsAlive */
899         NULL,   /* fpSetPrinterDataEx */
900         NULL,   /* fpGetPrinterDataEx */
901         NULL,   /* fpEnumPrinterDataEx */
902         NULL,   /* fpEnumPrinterKey */
903         NULL,   /* fpDeletePrinterDataEx */
904         NULL,   /* fpDeletePrinterKey */
905         NULL,   /* fpSeekPrinter */
906         NULL,   /* fpDeletePrinterDriverEx */
907         NULL,   /* fpAddPerMachineConnection */
908         NULL,   /* fpDeletePerMachineConnection */
909         NULL,   /* fpEnumPerMachineConnections */
910         NULL,   /* fpXcvData */
911         fpAddPrinterDriverEx,
912         NULL,   /* fpSplReadPrinter */
913         NULL,   /* fpDriverUnloadComplete */
914         NULL,   /* fpGetSpoolFileInfo */
915         NULL,   /* fpCommitSpoolData */
916         NULL,   /* fpCloseSpoolFileHandle */
917         NULL,   /* fpFlushPrinter */
918         NULL,   /* fpSendRecvBidiData */
919         NULL    /* fpAddDriverCatalog */
920     };
921     TRACE("=> %p\n", &backend);
922     return &backend;
923
924 }
925
926 /*****************************************************
927  *      DllMain
928  */
929 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
930 {
931     TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
932
933     switch(fdwReason)
934     {
935         case DLL_WINE_PREATTACH:
936             return FALSE;           /* prefer native version */
937
938         case DLL_PROCESS_ATTACH:
939             DisableThreadLibraryCalls( hinstDLL );
940             LOCALSPL_hInstance = hinstDLL;
941             pp = get_backend();
942             break;
943     }
944     return TRUE;
945 }
946
947
948 /*****************************************************
949  * InitializePrintProvidor     (localspl.@)
950  *
951  * Initialize the Printprovider
952  *
953  * PARAMS
954  *  pPrintProvidor    [I] Buffer to fill with a struct PRINTPROVIDOR
955  *  cbPrintProvidor   [I] Size of Buffer in Bytes
956  *  pFullRegistryPath [I] Registry-Path for the Printprovidor
957  *
958  * RETURNS
959  *  Success: TRUE and pPrintProvidor filled
960  *  Failure: FALSE
961  *
962  * NOTES
963  *  The RegistryPath should be:
964  *  "System\CurrentControlSet\Control\Print\Providers\<providername>",
965  *  but this Parameter is ignored in "localspl.dll".
966  *
967  */
968
969 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
970                                     DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
971 {
972
973     TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
974     memcpy(pPrintProvidor, pp, (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
975
976     return TRUE;
977 }