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