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