ntdll/tests: Create the server port before starting the client thread.
[wine] / dlls / localspl / provider.c
1 /*
2  * Implementation of the Local Printprovider
3  *
4  * Copyright 2006-2009 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 "winuser.h"
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
34
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "localspl_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
41
42 /* ############################### */
43
44 static CRITICAL_SECTION monitor_handles_cs;
45 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
46 {
47     0, 0, &monitor_handles_cs,
48     { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
49       0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
50 };
51 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
52
53 /* ############################### */
54
55 typedef struct {
56     WCHAR   src[MAX_PATH+MAX_PATH];
57     WCHAR   dst[MAX_PATH+MAX_PATH];
58     DWORD   srclen;
59     DWORD   dstlen;
60     DWORD   copyflags;
61     BOOL    lazy;
62 } apd_data_t;
63
64 typedef struct {
65     struct list     entry;
66     LPWSTR          name;
67     LPWSTR          dllname;
68     PMONITORUI      monitorUI;
69     LPMONITOR       monitor;
70     HMODULE         hdll;
71     DWORD           refcount;
72     DWORD           dwMonitorSize;
73 } monitor_t;
74
75 typedef struct {
76     LPCWSTR  envname;
77     LPCWSTR  subdir;
78     DWORD    driverversion;
79     LPCWSTR  versionregpath;
80     LPCWSTR  versionsubdir;
81 } printenv_t;
82
83 /* ############################### */
84
85 static struct list monitor_handles = LIST_INIT( monitor_handles );
86 static monitor_t * pm_localport;
87
88 static const PRINTPROVIDOR * pprovider = NULL;
89
90 static const WCHAR backslashW[] = {'\\',0};
91 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
92 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
93 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
94 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
95 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
96 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
97 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
98 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
99                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
100                                   'c','o','n','t','r','o','l','\\',
101                                   'P','r','i','n','t','\\',
102                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
103                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
104 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
105 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
106 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
107 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
108 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
109 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
110 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
111                                 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
112                                 'C','o','n','t','r','o','l','\\',
113                                 'P','r','i','n','t','\\',
114                                 'M','o','n','i','t','o','r','s','\\',0};
115 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
116 static const WCHAR nameW[] = {'N','a','m','e',0};
117 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
118 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
119 static const WCHAR portW[] = {'P','o','r','t',0};
120 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
121 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
122 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
123
124 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
125 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
126 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
127 static const WCHAR version0_subdirW[] = {'\\','0',0};
128
129 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
130 static const WCHAR x64_subdirW[] = {'x','6','4',0};
131 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
132 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
133 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
134 static const WCHAR version3_subdirW[] = {'\\','3',0};
135
136
137 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
138                                      version3_regpathW, version3_subdirW};
139
140 static const printenv_t env_x64 =   {x64_envnameW, x64_subdirW, 3,
141                                      version3_regpathW, version3_subdirW};
142
143 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
144                                      version0_regpathW, version0_subdirW};
145
146 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
147
148
149 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
150                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
151                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
152                                   0, sizeof(DRIVER_INFO_8W)};
153
154
155 /******************************************************************
156  * strdupW [internal]
157  *
158  * create a copy of a unicode-string
159  *
160  */
161 static LPWSTR strdupW(LPCWSTR p)
162 {
163     LPWSTR ret;
164     DWORD len;
165
166     if(!p) return NULL;
167     len = (lstrlenW(p) + 1) * sizeof(WCHAR);
168     ret = heap_alloc(len);
169     memcpy(ret, p, len);
170     return ret;
171 }
172
173 /******************************************************************
174  *  apd_copyfile [internal]
175  *
176  * Copy a file from the driverdirectory to the versioned directory
177  *
178  * RETURNS
179  *  Success: TRUE
180  *  Failure: FALSE
181  *
182  */
183 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
184 {
185     LPWSTR  ptr;
186     LPWSTR  srcname;
187     DWORD   res;
188
189     apd->src[apd->srclen] = '\0';
190     apd->dst[apd->dstlen] = '\0';
191
192     if (!filename || !filename[0]) {
193         /* nothing to copy */
194         return TRUE;
195     }
196
197     ptr = strrchrW(filename, '\\');
198     if (ptr) {
199         ptr++;
200     }
201     else
202     {
203         ptr = filename;
204     }
205
206     if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
207         /* we have an absolute Path */
208         srcname = filename;
209     }
210     else
211     {
212         srcname = apd->src;
213         lstrcatW(srcname, ptr);
214     }
215     lstrcatW(apd->dst, ptr);
216
217     TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
218
219     /* FIXME: handle APD_COPY_NEW_FILES */
220     res = CopyFileW(srcname, apd->dst, FALSE);
221     TRACE("got %u with %u\n", res, GetLastError());
222
223     return (apd->lazy) ? TRUE : res;
224 }
225
226 /******************************************************************
227  * copy_servername_from_name  (internal)
228  *
229  * for an external server, the serverpart from the name is copied.
230  *
231  * RETURNS
232  *  the length (in WCHAR) of the serverpart (0 for the local computer)
233  *  (-length), when the name is to long
234  *
235  */
236 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
237 {
238     LPCWSTR server;
239     LPWSTR  ptr;
240     WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
241     DWORD   len;
242     DWORD   serverlen;
243
244     if (target) *target = '\0';
245
246     if (name == NULL) return 0;
247     if ((name[0] != '\\') || (name[1] != '\\')) return 0;
248
249     server = &name[2];
250     /* skip over both backslash, find separator '\' */
251     ptr = strchrW(server, '\\');
252     serverlen = (ptr) ? ptr - server : lstrlenW(server);
253
254     /* servername is empty or to long */
255     if (serverlen == 0) return 0;
256
257     TRACE("found %s\n", debugstr_wn(server, serverlen));
258
259     if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
260
261     len = sizeof(buffer) / sizeof(buffer[0]);
262     if (GetComputerNameW(buffer, &len)) {
263         if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
264             /* The requested Servername is our computername */
265             if (target) {
266                 memcpy(target, server, serverlen * sizeof(WCHAR));
267                 target[serverlen] = '\0';
268             }
269             return serverlen;
270         }
271     }
272     return 0;
273 }
274
275 /******************************************************************
276  * monitor_unload [internal]
277  *
278  * release a printmonitor and unload it from memory, when needed
279  *
280  */
281 static void monitor_unload(monitor_t * pm)
282 {
283     if (pm == NULL) return;
284     TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
285
286     EnterCriticalSection(&monitor_handles_cs);
287
288     if (pm->refcount) pm->refcount--;
289
290     if (pm->refcount == 0) {
291         list_remove(&pm->entry);
292         FreeLibrary(pm->hdll);
293         heap_free(pm->name);
294         heap_free(pm->dllname);
295         heap_free(pm);
296     }
297     LeaveCriticalSection(&monitor_handles_cs);
298 }
299
300 /******************************************************************
301  * monitor_unloadall [internal]
302  *
303  * release all printmonitors and unload them from memory, when needed
304  *
305  */
306
307 static void monitor_unloadall(void)
308 {
309     monitor_t * pm;
310     monitor_t * next;
311
312     EnterCriticalSection(&monitor_handles_cs);
313     /* iterate through the list, with safety against removal */
314     LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
315     {
316         monitor_unload(pm);
317     }
318     LeaveCriticalSection(&monitor_handles_cs);
319 }
320
321 /******************************************************************
322  * monitor_load [internal]
323  *
324  * load a printmonitor, get the dllname from the registry, when needed
325  * initialize the monitor and dump found function-pointers
326  *
327  * On failure, SetLastError() is called and NULL is returned
328  */
329
330 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
331 {
332     LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
333     PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
334     LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
335     DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
336     DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
337
338     monitor_t * pm = NULL;
339     monitor_t * cursor;
340     LPWSTR  regroot = NULL;
341     LPWSTR  driver = dllname;
342
343     TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
344     /* Is the Monitor already loaded? */
345     EnterCriticalSection(&monitor_handles_cs);
346
347     if (name) {
348         LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
349         {
350             if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
351                 pm = cursor;
352                 break;
353             }
354         }
355     }
356
357     if (pm == NULL) {
358         pm = heap_alloc_zero(sizeof(monitor_t));
359         if (pm == NULL) goto cleanup;
360         list_add_tail(&monitor_handles, &pm->entry);
361     }
362     pm->refcount++;
363
364     if (pm->name == NULL) {
365         /* Load the monitor */
366         LPMONITOREX pmonitorEx;
367         DWORD   len;
368
369         if (name) {
370             len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
371             regroot = heap_alloc(len * sizeof(WCHAR));
372         }
373
374         if (regroot) {
375             lstrcpyW(regroot, monitorsW);
376             lstrcatW(regroot, name);
377             /* Get the Driver from the Registry */
378             if (driver == NULL) {
379                 HKEY    hroot;
380                 DWORD   namesize;
381                 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
382                     if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
383                                         &namesize) == ERROR_SUCCESS) {
384                         driver = heap_alloc(namesize);
385                         RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
386                     }
387                     RegCloseKey(hroot);
388                 }
389             }
390         }
391
392         pm->name = strdupW(name);
393         pm->dllname = strdupW(driver);
394
395         if ((name && (!regroot || !pm->name)) || !pm->dllname) {
396             monitor_unload(pm);
397             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
398             pm = NULL;
399             goto cleanup;
400         }
401
402         pm->hdll = LoadLibraryW(driver);
403         TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
404
405         if (pm->hdll == NULL) {
406             monitor_unload(pm);
407             SetLastError(ERROR_MOD_NOT_FOUND);
408             pm = NULL;
409             goto cleanup;
410         }
411
412         pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
413         pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
414         pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
415         pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
416         pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
417
418
419         TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
420         TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
421         TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
422         TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
423         TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
424
425         if (pInitializePrintMonitorUI  != NULL) {
426             pm->monitorUI = pInitializePrintMonitorUI();
427             TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
428             if (pm->monitorUI) {
429                 TRACE("0x%08x: dwMonitorSize (%d)\n",
430                         pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
431
432             }
433         }
434
435         if (pInitializePrintMonitor && regroot) {
436             pmonitorEx = pInitializePrintMonitor(regroot);
437             TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
438                     pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
439
440             if (pmonitorEx) {
441                 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
442                 pm->monitor = &(pmonitorEx->Monitor);
443             }
444         }
445
446         if (pm->monitor) {
447             TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
448
449         }
450
451         if (!pm->monitor && regroot) {
452             if (pInitializePrintMonitor2 != NULL) {
453                 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
454             }
455             if (pInitializeMonitorEx != NULL) {
456                 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
457             }
458             if (pInitializeMonitor != NULL) {
459                 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
460             }
461         }
462         if (!pm->monitor && !pm->monitorUI) {
463             monitor_unload(pm);
464             SetLastError(ERROR_PROC_NOT_FOUND);
465             pm = NULL;
466         }
467     }
468 cleanup:
469     if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
470         pm->refcount++;
471         pm_localport = pm;
472     }
473     LeaveCriticalSection(&monitor_handles_cs);
474     if (driver != dllname) heap_free(driver);
475     heap_free(regroot);
476     TRACE("=> %p\n", pm);
477     return pm;
478 }
479
480 /******************************************************************
481  * monitor_loadall [internal]
482  *
483  * Load all registered monitors
484  *
485  */
486 static DWORD monitor_loadall(void)
487 {
488     monitor_t * pm;
489     DWORD   registered = 0;
490     DWORD   loaded = 0;
491     HKEY    hmonitors;
492     WCHAR   buffer[MAX_PATH];
493     DWORD   id = 0;
494
495     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
496         RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
497                         NULL, NULL, NULL, NULL, NULL);
498
499         TRACE("%d monitors registered\n", registered);
500
501         while (id < registered) {
502             buffer[0] = '\0';
503             RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
504             pm = monitor_load(buffer, NULL);
505             if (pm) loaded++;
506             id++;
507         }
508         RegCloseKey(hmonitors);
509     }
510     TRACE("%d monitors loaded\n", loaded);
511     return loaded;
512 }
513
514 /******************************************************************
515  * Return the number of bytes for an multi_sz string.
516  * The result includes all \0s
517  * (specifically the extra \0, that is needed as multi_sz terminator).
518  */
519 static int multi_sz_lenW(const WCHAR *str)
520 {
521     const WCHAR *ptr = str;
522     if (!str) return 0;
523     do
524     {
525         ptr += lstrlenW(ptr) + 1;
526     } while (*ptr);
527
528     return (ptr - str + 1) * sizeof(WCHAR);
529 }
530
531 /******************************************************************
532  * validate_envW [internal]
533  *
534  * validate the user-supplied printing-environment
535  *
536  * PARAMS
537  *  env  [I] PTR to Environment-String or NULL
538  *
539  * RETURNS
540  *  Success:  PTR to printenv_t
541  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
542  *
543  * NOTES
544  *  An empty string is handled the same way as NULL.
545  *
546  */
547
548 static const  printenv_t * validate_envW(LPCWSTR env)
549 {
550     const printenv_t *result = NULL;
551     unsigned int i;
552
553     TRACE("(%s)\n", debugstr_w(env));
554     if (env && env[0])
555     {
556         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
557         {
558             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
559             {
560                 result = all_printenv[i];
561                 break;
562             }
563         }
564         if (result == NULL) {
565             FIXME("unsupported Environment: %s\n", debugstr_w(env));
566             SetLastError(ERROR_INVALID_ENVIRONMENT);
567         }
568         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
569     }
570     else
571     {
572         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
573     }
574
575     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
576     return result;
577 }
578
579 /*****************************************************************************
580  * enumerate the local monitors (INTERNAL)
581  *
582  * returns the needed size (in bytes) for pMonitors
583  * and  *lpreturned is set to number of entries returned in pMonitors
584  *
585  * Language-Monitors are also installed in the same Registry-Location but
586  * they are filtered in Windows (not returned by EnumMonitors).
587  * We do no filtering to simplify our Code.
588  *
589  */
590 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
591 {
592     HKEY    hroot = NULL;
593     HKEY    hentry = NULL;
594     LPWSTR  ptr;
595     LPMONITOR_INFO_2W mi;
596     WCHAR   buffer[MAX_PATH];
597     WCHAR   dllname[MAX_PATH];
598     DWORD   dllsize;
599     DWORD   len;
600     DWORD   index = 0;
601     DWORD   needed = 0;
602     DWORD   numentries;
603     DWORD   entrysize;
604
605     entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
606
607     numentries = *lpreturned;       /* this is 0, when we scan the registry */
608     len = entrysize * numentries;
609     ptr = (LPWSTR) &pMonitors[len];
610
611     numentries = 0;
612     len = sizeof(buffer)/sizeof(buffer[0]);
613     buffer[0] = '\0';
614
615     /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
616     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
617         /* Scan all Monitor-Registry-Keys */
618         while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
619             TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
620             dllsize = sizeof(dllname);
621             dllname[0] = '\0';
622
623             /* The Monitor must have a Driver-DLL */
624             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
625                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
626                     /* We found a valid DLL for this Monitor. */
627                     TRACE("using Driver: %s\n", debugstr_w(dllname));
628                 }
629                 RegCloseKey(hentry);
630             }
631
632             /* Windows returns only Port-Monitors here, but to simplify our code,
633                we do no filtering for Language-Monitors */
634             if (dllname[0]) {
635                 numentries++;
636                 needed += entrysize;
637                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
638                 if (level > 1) {
639                     /* we install and return only monitors for "Windows NT x86" */
640                     needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
641                     needed += dllsize;
642                 }
643
644                 /* required size is calculated. Now fill the user-buffer */
645                 if (pMonitors && (cbBuf >= needed)){
646                     mi = (LPMONITOR_INFO_2W) pMonitors;
647                     pMonitors += entrysize;
648
649                     TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
650                     mi->pName = ptr;
651                     lstrcpyW(ptr, buffer);      /* Name of the Monitor */
652                     ptr += (len+1);               /* len is lstrlenW(monitorname) */
653                     if (level > 1) {
654                         mi->pEnvironment = ptr;
655                         lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
656                         ptr += (lstrlenW(x86_envnameW)+1);
657
658                         mi->pDLLName = ptr;
659                         lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
660                         ptr += (dllsize / sizeof(WCHAR));
661                     }
662                 }
663             }
664             index++;
665             len = sizeof(buffer)/sizeof(buffer[0]);
666             buffer[0] = '\0';
667         }
668         RegCloseKey(hroot);
669     }
670     *lpreturned = numentries;
671     TRACE("need %d byte for %d entries\n", needed, numentries);
672     return needed;
673 }
674
675 /******************************************************************
676  * enumerate the local Ports from all loaded monitors (internal)
677  *
678  * returns the needed size (in bytes) for pPorts
679  * and  *lpreturned is set to number of entries returned in pPorts
680  *
681  */
682 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
683 {
684     monitor_t * pm;
685     LPWSTR      ptr;
686     LPPORT_INFO_2W cache;
687     LPPORT_INFO_2W out;
688     LPBYTE  pi_buffer = NULL;
689     DWORD   pi_allocated = 0;
690     DWORD   pi_needed;
691     DWORD   pi_index;
692     DWORD   pi_returned;
693     DWORD   res;
694     DWORD   outindex = 0;
695     DWORD   needed;
696     DWORD   numentries;
697     DWORD   entrysize;
698
699
700     TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
701     entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
702
703     numentries = *lpreturned;       /* this is 0, when we scan the registry */
704     needed = entrysize * numentries;
705     ptr = (LPWSTR) &pPorts[needed];
706
707     numentries = 0;
708     needed = 0;
709
710     LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
711     {
712         if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
713             pi_needed = 0;
714             pi_returned = 0;
715             res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
716             if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
717                 /* Do not use heap_realloc (we do not need the old data in the buffer) */
718                 heap_free(pi_buffer);
719                 pi_buffer = heap_alloc(pi_needed);
720                 pi_allocated = (pi_buffer) ? pi_needed : 0;
721                 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
722             }
723             TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
724                   debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
725
726             numentries += pi_returned;
727             needed += pi_needed;
728
729             /* fill the output-buffer (pPorts), if we have one */
730             if (pPorts && (cbBuf >= needed ) && pi_buffer) {
731                 pi_index = 0;
732                 while (pi_returned > pi_index) {
733                     cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
734                     out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
735                     out->pPortName = ptr;
736                     lstrcpyW(ptr, cache->pPortName);
737                     ptr += (lstrlenW(ptr)+1);
738                     if (level > 1) {
739                         out->pMonitorName = ptr;
740                         lstrcpyW(ptr,  cache->pMonitorName);
741                         ptr += (lstrlenW(ptr)+1);
742
743                         out->pDescription = ptr;
744                         lstrcpyW(ptr,  cache->pDescription);
745                         ptr += (lstrlenW(ptr)+1);
746                         out->fPortType = cache->fPortType;
747                         out->Reserved = cache->Reserved;
748                     }
749                     pi_index++;
750                     outindex++;
751                 }
752             }
753         }
754     }
755     /* the temporary portinfo-buffer is no longer needed */
756     heap_free(pi_buffer);
757
758     *lpreturned = numentries;
759     TRACE("need %d byte for %d entries\n", needed, numentries);
760     return needed;
761 }
762
763
764 /*****************************************************************************
765  * open_driver_reg [internal]
766  *
767  * opens the registry for the printer drivers depending on the given input
768  * variable pEnvironment
769  *
770  * RETURNS:
771  *    Success: the opened hkey
772  *    Failure: NULL
773  */
774 static HKEY open_driver_reg(LPCWSTR pEnvironment)
775 {
776     HKEY  retval = NULL;
777     LPWSTR buffer;
778     const printenv_t * env;
779
780     TRACE("(%s)\n", debugstr_w(pEnvironment));
781
782     env = validate_envW(pEnvironment);
783     if (!env) return NULL;
784
785     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
786                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
787
788     if (buffer) {
789         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
790         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
791         HeapFree(GetProcessHeap(), 0, buffer);
792     }
793     return retval;
794 }
795
796 /*****************************************************************************
797  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
798  *
799  * Return the PATH for the Printer-Drivers
800  *
801  * PARAMS
802  *   pName            [I] Servername (NT only) or NULL (local Computer)
803  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
804  *   Level            [I] Structure-Level (must be 1)
805  *   pDriverDirectory [O] PTR to Buffer that receives the Result
806  *   cbBuf            [I] Size of Buffer at pDriverDirectory
807  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
808  *                        required for pDriverDirectory
809  *
810  * RETURNS
811  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
812  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
813  *            if cbBuf is too small
814  *
815  *   Native Values returned in pDriverDirectory on Success:
816  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
817  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
818  *|  win9x(Windows 4.0):  "%winsysdir%"
819  *
820  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
821  *
822  */
823 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
824             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
825 {
826     DWORD needed;
827     const printenv_t * env;
828
829     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
830           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
831
832     if (pName != NULL && pName[0]) {
833         FIXME("server %s not supported\n", debugstr_w(pName));
834         SetLastError(ERROR_INVALID_PARAMETER);
835         return FALSE;
836     }
837
838     env = validate_envW(pEnvironment);
839     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
840
841
842     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
843     needed = GetSystemDirectoryW(NULL, 0);
844     /* add the Size for the Subdirectories */
845     needed += lstrlenW(spooldriversW);
846     needed += lstrlenW(env->subdir);
847     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
848
849     *pcbNeeded = needed;
850
851     if (needed > cbBuf) {
852         SetLastError(ERROR_INSUFFICIENT_BUFFER);
853         return FALSE;
854     }
855
856     if (pDriverDirectory == NULL) {
857         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
858         SetLastError(ERROR_INVALID_USER_BUFFER);
859         return FALSE;
860     }
861
862     GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
863     /* add the Subdirectories */
864     lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
865     lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
866
867     TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
868     return TRUE;
869 }
870
871 /******************************************************************
872  * driver_load [internal]
873  *
874  * load a driver user interface dll
875  *
876  * On failure, NULL is returned
877  *
878  */
879
880 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
881 {
882     WCHAR fullname[MAX_PATH];
883     HMODULE hui;
884     DWORD len;
885
886     TRACE("(%p, %s)\n", env, debugstr_w(dllname));
887
888     /* build the driverdir */
889     len = sizeof(fullname) -
890           (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
891
892     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
893                                      (LPBYTE) fullname, len, &len)) {
894         /* Should never Fail */
895         SetLastError(ERROR_BUFFER_OVERFLOW);
896         return NULL;
897     }
898
899     lstrcatW(fullname, env->versionsubdir);
900     lstrcatW(fullname, backslashW);
901     lstrcatW(fullname, dllname);
902
903     hui = LoadLibraryW(fullname);
904     TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
905
906     return hui;
907 }
908
909 /******************************************************************************
910  *  myAddPrinterDriverEx [internal]
911  *
912  * Install a Printer Driver with the Option to upgrade / downgrade the Files
913  * and a special mode with lazy error checking.
914  *
915  */
916 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
917 {
918     static const WCHAR emptyW[1];
919     const printenv_t *env;
920     apd_data_t apd;
921     DRIVER_INFO_8W di;
922     BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
923     HMODULE hui;
924     LPWSTR  ptr;
925     HKEY    hroot;
926     HKEY    hdrv;
927     DWORD   disposition;
928     DWORD   len;
929     LONG    lres;
930     BOOL    res;
931
932     /* we need to set all entries in the Registry, independent from the Level of
933        DRIVER_INFO, that the caller supplied */
934
935     ZeroMemory(&di, sizeof(di));
936     if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
937         memcpy(&di, pDriverInfo, di_sizeof[level]);
938     }
939
940     /* dump the most used infos */
941     TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
942     TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
943     TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
944     TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
945     TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
946     TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
947     TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
948     /* dump only the first of the additional Files */
949     TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
950
951
952     /* check environment */
953     env = validate_envW(di.pEnvironment);
954     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
955
956     /* fill the copy-data / get the driverdir */
957     len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
958     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
959                                     (LPBYTE) apd.src, len, &len)) {
960         /* Should never Fail */
961         return FALSE;
962     }
963     memcpy(apd.dst, apd.src, len);
964     lstrcatW(apd.src, backslashW);
965     apd.srclen = lstrlenW(apd.src);
966     lstrcatW(apd.dst, env->versionsubdir);
967     lstrcatW(apd.dst, backslashW);
968     apd.dstlen = lstrlenW(apd.dst);
969     apd.copyflags = dwFileCopyFlags;
970     apd.lazy = lazy;
971     CreateDirectoryW(apd.src, NULL);
972     CreateDirectoryW(apd.dst, NULL);
973
974     hroot = open_driver_reg(env->envname);
975     if (!hroot) {
976         ERR("Can't create Drivers key\n");
977         return FALSE;
978     }
979
980     /* Fill the Registry for the Driver */
981     if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
982                                 KEY_WRITE | KEY_QUERY_VALUE, NULL,
983                                 &hdrv, &disposition)) != ERROR_SUCCESS) {
984
985         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
986         RegCloseKey(hroot);
987         SetLastError(lres);
988         return FALSE;
989     }
990     RegCloseKey(hroot);
991
992     if (disposition == REG_OPENED_EXISTING_KEY) {
993         TRACE("driver %s already installed\n", debugstr_w(di.pName));
994         RegCloseKey(hdrv);
995         SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
996         return FALSE;
997     }
998
999     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1000     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1001                    sizeof(DWORD));
1002
1003     RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1004                    (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1005     apd_copyfile(di.pDriverPath, &apd);
1006
1007     RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1008                    (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1009     apd_copyfile(di.pDataFile, &apd);
1010
1011     RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1012                    (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1013     apd_copyfile(di.pConfigFile, &apd);
1014
1015     /* settings for level 3 */
1016     if (di.pHelpFile)
1017         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1018                        (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1019     else
1020         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1021     apd_copyfile(di.pHelpFile, &apd);
1022
1023
1024     ptr = di.pDependentFiles;
1025     if (ptr)
1026         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1027                        multi_sz_lenW(di.pDependentFiles));
1028     else
1029         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1030     while ((ptr != NULL) && (ptr[0])) {
1031         if (apd_copyfile(ptr, &apd)) {
1032             ptr += lstrlenW(ptr) + 1;
1033         }
1034         else
1035         {
1036             WARN("Failed to copy %s\n", debugstr_w(ptr));
1037             ptr = NULL;
1038         }
1039     }
1040     /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1041     if (di.pMonitorName)
1042         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1043                        (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1044     else
1045         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1046
1047     if (di.pDefaultDataType)
1048         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1049                        (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1050     else
1051         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1052
1053     /* settings for level 4 */
1054     if (di.pszzPreviousNames)
1055         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1056                        multi_sz_lenW(di.pszzPreviousNames));
1057     else
1058         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1059
1060     if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1061
1062     RegCloseKey(hdrv);
1063     hui = driver_load(env, di.pConfigFile);
1064     pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1065     if (hui && pDrvDriverEvent) {
1066
1067         /* Support for DrvDriverEvent is optional */
1068         TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1069         /* MSDN: level for DRIVER_INFO is 1 to 3 */
1070         res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1071         TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1072     }
1073     FreeLibrary(hui);
1074
1075     TRACE("=> TRUE with %u\n", GetLastError());
1076     return TRUE;
1077
1078 }
1079
1080 /******************************************************************************
1081  * fpAddMonitor [exported through PRINTPROVIDOR]
1082  *
1083  * Install a Printmonitor
1084  *
1085  * PARAMS
1086  *  pName       [I] Servername or NULL (local Computer)
1087  *  Level       [I] Structure-Level (Must be 2)
1088  *  pMonitors   [I] PTR to MONITOR_INFO_2
1089  *
1090  * RETURNS
1091  *  Success: TRUE
1092  *  Failure: FALSE
1093  *
1094  * NOTES
1095  *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1096  *
1097  */
1098 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1099 {
1100     monitor_t * pm = NULL;
1101     LPMONITOR_INFO_2W mi2w;
1102     HKEY    hroot = NULL;
1103     HKEY    hentry = NULL;
1104     DWORD   disposition;
1105     BOOL    res = FALSE;
1106
1107     mi2w = (LPMONITOR_INFO_2W) pMonitors;
1108     TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1109             debugstr_w(mi2w ? mi2w->pName : NULL),
1110             debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1111             debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1112
1113     if (copy_servername_from_name(pName, NULL)) {
1114         FIXME("server %s not supported\n", debugstr_w(pName));
1115         SetLastError(ERROR_ACCESS_DENIED);
1116         return FALSE;
1117     }
1118
1119     if (!mi2w->pName || (! mi2w->pName[0])) {
1120         WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1121         SetLastError(ERROR_INVALID_PARAMETER);
1122         return FALSE;
1123     }
1124     if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1125         WARN("Environment %s requested (we support only %s)\n",
1126                 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1127         SetLastError(ERROR_INVALID_ENVIRONMENT);
1128         return FALSE;
1129     }
1130
1131     if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1132         WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1133         SetLastError(ERROR_INVALID_PARAMETER);
1134         return FALSE;
1135     }
1136
1137     /* Load and initialize the monitor. SetLastError() is called on failure */
1138     if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1139         return FALSE;
1140     }
1141     monitor_unload(pm);
1142
1143     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1144         ERR("unable to create key %s\n", debugstr_w(monitorsW));
1145         return FALSE;
1146     }
1147
1148     if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1149                         KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1150                         &disposition) == ERROR_SUCCESS) {
1151
1152         /* Some installers set options for the port before calling AddMonitor.
1153            We query the "Driver" entry to verify that the monitor is installed,
1154            before we return an error.
1155            When a user installs two print monitors at the same time with the
1156            same name, a race condition is possible but silently ignored. */
1157
1158         DWORD   namesize = 0;
1159
1160         if ((disposition == REG_OPENED_EXISTING_KEY) &&
1161             (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1162                               &namesize) == ERROR_SUCCESS)) {
1163             TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1164             /* 9x use ERROR_ALREADY_EXISTS */
1165             SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1166         }
1167         else
1168         {
1169             INT len;
1170             len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1171             res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1172                     (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1173         }
1174         RegCloseKey(hentry);
1175     }
1176
1177     RegCloseKey(hroot);
1178     return (res);
1179 }
1180
1181 /******************************************************************************
1182  * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1183  *
1184  * Install a Printer Driver with the Option to upgrade / downgrade the Files
1185  *
1186  * PARAMS
1187  *  pName           [I] Servername or NULL (local Computer)
1188  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
1189  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1190  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1191  *
1192  * RESULTS
1193  *  Success: TRUE
1194  *  Failure: FALSE
1195  *
1196  */
1197 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1198 {
1199     LONG lres;
1200
1201     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1202     lres = copy_servername_from_name(pName, NULL);
1203     if (lres) {
1204         FIXME("server %s not supported\n", debugstr_w(pName));
1205         SetLastError(ERROR_ACCESS_DENIED);
1206         return FALSE;
1207     }
1208
1209     if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1210         TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1211     }
1212
1213     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1214 }
1215 /******************************************************************
1216  * fpDeleteMonitor [exported through PRINTPROVIDOR]
1217  *
1218  * Delete a specific Printmonitor from a Printing-Environment
1219  *
1220  * PARAMS
1221  *  pName        [I] Servername or NULL (local Computer)
1222  *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1223  *  pMonitorName [I] Name of the Monitor, that should be deleted
1224  *
1225  * RETURNS
1226  *  Success: TRUE
1227  *  Failure: FALSE
1228  *
1229  * NOTES
1230  *  pEnvironment is ignored in Windows for the local Computer.
1231  *
1232  */
1233
1234 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1235 {
1236     HKEY    hroot = NULL;
1237     LONG    lres;
1238
1239     TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1240            debugstr_w(pMonitorName));
1241
1242     lres = copy_servername_from_name(pName, NULL);
1243     if (lres) {
1244         FIXME("server %s not supported\n", debugstr_w(pName));
1245         SetLastError(ERROR_INVALID_NAME);
1246         return FALSE;
1247     }
1248
1249     /*  pEnvironment is ignored in Windows for the local Computer */
1250     if (!pMonitorName || !pMonitorName[0]) {
1251         TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1252         SetLastError(ERROR_INVALID_PARAMETER);
1253         return FALSE;
1254     }
1255
1256     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1257         ERR("unable to create key %s\n", debugstr_w(monitorsW));
1258         return FALSE;
1259     }
1260
1261     if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1262         TRACE("%s deleted\n", debugstr_w(pMonitorName));
1263         RegCloseKey(hroot);
1264         return TRUE;
1265     }
1266
1267     TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1268     RegCloseKey(hroot);
1269
1270     /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1271     SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1272     return FALSE;
1273 }
1274
1275 /*****************************************************************************
1276  * fpEnumMonitors [exported through PRINTPROVIDOR]
1277  *
1278  * Enumerate available Port-Monitors
1279  *
1280  * PARAMS
1281  *  pName      [I] Servername or NULL (local Computer)
1282  *  Level      [I] Structure-Level (1:Win9x+NT or 2:NT only)
1283  *  pMonitors  [O] PTR to Buffer that receives the Result
1284  *  cbBuf      [I] Size of Buffer at pMonitors
1285  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1286  *  pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1287  *
1288  * RETURNS
1289  *  Success: TRUE
1290  *  Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1291  *
1292  * NOTES
1293  *  Windows reads the Registry once and cache the Results.
1294  *
1295  */
1296 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1297                                   LPDWORD pcbNeeded, LPDWORD pcReturned)
1298 {
1299     DWORD   numentries = 0;
1300     DWORD   needed = 0;
1301     LONG    lres;
1302     BOOL    res = FALSE;
1303
1304     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1305           cbBuf, pcbNeeded, pcReturned);
1306
1307     lres = copy_servername_from_name(pName, NULL);
1308     if (lres) {
1309         FIXME("server %s not supported\n", debugstr_w(pName));
1310         SetLastError(ERROR_INVALID_NAME);
1311         goto em_cleanup;
1312     }
1313
1314     if (!Level || (Level > 2)) {
1315         WARN("level (%d) is ignored in win9x\n", Level);
1316         SetLastError(ERROR_INVALID_LEVEL);
1317         return FALSE;
1318     }
1319
1320     /* Scan all Monitor-Keys */
1321     numentries = 0;
1322     needed = get_local_monitors(Level, NULL, 0, &numentries);
1323
1324     /* we calculated the needed buffersize. now do more error-checks */
1325     if (cbBuf < needed) {
1326         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1327         goto em_cleanup;
1328     }
1329
1330     /* fill the Buffer with the Monitor-Keys */
1331     needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1332     res = TRUE;
1333
1334 em_cleanup:
1335     if (pcbNeeded)  *pcbNeeded = needed;
1336     if (pcReturned) *pcReturned = numentries;
1337
1338     TRACE("returning %d with %d (%d byte for %d entries)\n",
1339             res, GetLastError(), needed, numentries);
1340
1341     return (res);
1342 }
1343
1344 /******************************************************************************
1345  * fpEnumPorts [exported through PRINTPROVIDOR]
1346  *
1347  * Enumerate available Ports
1348  *
1349  * PARAMS
1350  *  pName      [I] Servername or NULL (local Computer)
1351  *  Level      [I] Structure-Level (1 or 2)
1352  *  pPorts     [O] PTR to Buffer that receives the Result
1353  *  cbBuf      [I] Size of Buffer at pPorts
1354  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1355  *  pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1356  *
1357  * RETURNS
1358  *  Success: TRUE
1359  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1360  *
1361  */
1362 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1363                                LPDWORD pcbNeeded, LPDWORD pcReturned)
1364 {
1365     DWORD   needed = 0;
1366     DWORD   numentries = 0;
1367     LONG    lres;
1368     BOOL    res = FALSE;
1369
1370     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1371           cbBuf, pcbNeeded, pcReturned);
1372
1373     lres = copy_servername_from_name(pName, NULL);
1374     if (lres) {
1375         FIXME("server %s not supported\n", debugstr_w(pName));
1376         SetLastError(ERROR_INVALID_NAME);
1377         goto emP_cleanup;
1378     }
1379
1380     if (!Level || (Level > 2)) {
1381         SetLastError(ERROR_INVALID_LEVEL);
1382         goto emP_cleanup;
1383     }
1384
1385     if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1386         SetLastError(RPC_X_NULL_REF_POINTER);
1387         goto emP_cleanup;
1388     }
1389
1390     EnterCriticalSection(&monitor_handles_cs);
1391     monitor_loadall();
1392
1393     /* Scan all local Ports */
1394     numentries = 0;
1395     needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1396
1397     /* we calculated the needed buffersize. now do the error-checks */
1398     if (cbBuf < needed) {
1399         monitor_unloadall();
1400         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1401         goto emP_cleanup_cs;
1402     }
1403     else if (!pPorts || !pcReturned) {
1404         monitor_unloadall();
1405         SetLastError(RPC_X_NULL_REF_POINTER);
1406         goto emP_cleanup_cs;
1407     }
1408
1409     /* Fill the Buffer */
1410     needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1411     res = TRUE;
1412     monitor_unloadall();
1413
1414 emP_cleanup_cs:
1415     LeaveCriticalSection(&monitor_handles_cs);
1416
1417 emP_cleanup:
1418     if (pcbNeeded)  *pcbNeeded = needed;
1419     if (pcReturned) *pcReturned = (res) ? numentries : 0;
1420
1421     TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1422           (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1423
1424     return (res);
1425 }
1426
1427 /*****************************************************
1428  *  setup_provider [internal]
1429  */
1430 void setup_provider(void)
1431 {
1432     static const PRINTPROVIDOR backend = {
1433         NULL,   /* fpOpenPrinter */
1434         NULL,   /* fpSetJob */
1435         NULL,   /* fpGetJob */
1436         NULL,   /* fpEnumJobs */
1437         NULL,   /* fpAddPrinter */
1438         NULL,   /* fpDeletePrinter */
1439         NULL,   /* fpSetPrinter */
1440         NULL,   /* fpGetPrinter */
1441         NULL,   /* fpEnumPrinters */
1442         NULL,   /* fpAddPrinterDriver */
1443         NULL,   /* fpEnumPrinterDrivers */
1444         NULL,   /* fpGetPrinterDriver */
1445         fpGetPrinterDriverDirectory,
1446         NULL,   /* fpDeletePrinterDriver */
1447         NULL,   /* fpAddPrintProcessor */
1448         NULL,   /* fpEnumPrintProcessors */
1449         NULL,   /* fpGetPrintProcessorDirectory */
1450         NULL,   /* fpDeletePrintProcessor */
1451         NULL,   /* fpEnumPrintProcessorDatatypes */
1452         NULL,   /* fpStartDocPrinter */
1453         NULL,   /* fpStartPagePrinter */
1454         NULL,   /* fpWritePrinter */
1455         NULL,   /* fpEndPagePrinter */
1456         NULL,   /* fpAbortPrinter */
1457         NULL,   /* fpReadPrinter */
1458         NULL,   /* fpEndDocPrinter */
1459         NULL,   /* fpAddJob */
1460         NULL,   /* fpScheduleJob */
1461         NULL,   /* fpGetPrinterData */
1462         NULL,   /* fpSetPrinterData */
1463         NULL,   /* fpWaitForPrinterChange */
1464         NULL,   /* fpClosePrinter */
1465         NULL,   /* fpAddForm */
1466         NULL,   /* fpDeleteForm */
1467         NULL,   /* fpGetForm */
1468         NULL,   /* fpSetForm */
1469         NULL,   /* fpEnumForms */
1470         fpEnumMonitors,
1471         fpEnumPorts,
1472         NULL,   /* fpAddPort */
1473         NULL,   /* fpConfigurePort */
1474         NULL,   /* fpDeletePort */
1475         NULL,   /* fpCreatePrinterIC */
1476         NULL,   /* fpPlayGdiScriptOnPrinterIC */
1477         NULL,   /* fpDeletePrinterIC */
1478         NULL,   /* fpAddPrinterConnection */
1479         NULL,   /* fpDeletePrinterConnection */
1480         NULL,   /* fpPrinterMessageBox */
1481         fpAddMonitor,
1482         fpDeleteMonitor,
1483         NULL,   /* fpResetPrinter */
1484         NULL,   /* fpGetPrinterDriverEx */
1485         NULL,   /* fpFindFirstPrinterChangeNotification */
1486         NULL,   /* fpFindClosePrinterChangeNotification */
1487         NULL,   /* fpAddPortEx */
1488         NULL,   /* fpShutDown */
1489         NULL,   /* fpRefreshPrinterChangeNotification */
1490         NULL,   /* fpOpenPrinterEx */
1491         NULL,   /* fpAddPrinterEx */
1492         NULL,   /* fpSetPort */
1493         NULL,   /* fpEnumPrinterData */
1494         NULL,   /* fpDeletePrinterData */
1495         NULL,   /* fpClusterSplOpen */
1496         NULL,   /* fpClusterSplClose */
1497         NULL,   /* fpClusterSplIsAlive */
1498         NULL,   /* fpSetPrinterDataEx */
1499         NULL,   /* fpGetPrinterDataEx */
1500         NULL,   /* fpEnumPrinterDataEx */
1501         NULL,   /* fpEnumPrinterKey */
1502         NULL,   /* fpDeletePrinterDataEx */
1503         NULL,   /* fpDeletePrinterKey */
1504         NULL,   /* fpSeekPrinter */
1505         NULL,   /* fpDeletePrinterDriverEx */
1506         NULL,   /* fpAddPerMachineConnection */
1507         NULL,   /* fpDeletePerMachineConnection */
1508         NULL,   /* fpEnumPerMachineConnections */
1509         NULL,   /* fpXcvData */
1510         fpAddPrinterDriverEx,
1511         NULL,   /* fpSplReadPrinter */
1512         NULL,   /* fpDriverUnloadComplete */
1513         NULL,   /* fpGetSpoolFileInfo */
1514         NULL,   /* fpCommitSpoolData */
1515         NULL,   /* fpCloseSpoolFileHandle */
1516         NULL,   /* fpFlushPrinter */
1517         NULL,   /* fpSendRecvBidiData */
1518         NULL    /* fpAddDriverCatalog */
1519     };
1520     pprovider = &backend;
1521
1522 }
1523
1524 /*****************************************************
1525  * InitializePrintProvidor     (localspl.@)
1526  *
1527  * Initialize the Printprovider
1528  *
1529  * PARAMS
1530  *  pPrintProvidor    [I] Buffer to fill with a struct PRINTPROVIDOR
1531  *  cbPrintProvidor   [I] Size of Buffer in Bytes
1532  *  pFullRegistryPath [I] Registry-Path for the Printprovidor
1533  *
1534  * RETURNS
1535  *  Success: TRUE and pPrintProvidor filled
1536  *  Failure: FALSE
1537  *
1538  * NOTES
1539  *  The RegistryPath should be:
1540  *  "System\CurrentControlSet\Control\Print\Providers\<providername>",
1541  *  but this Parameter is ignored in "localspl.dll".
1542  *
1543  */
1544
1545 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
1546                                     DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
1547 {
1548
1549     TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
1550     memcpy(pPrintProvidor, pprovider,
1551           (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
1552
1553     return TRUE;
1554 }