po: Update French translation.
[wine] / dlls / localspl / provider.c
1 /*
2  * Implementation of the Local Printprovider
3  *
4  * Copyright 2006-2009 Detlef Riekenberg
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winspool.h"
31 #include "winuser.h"
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
34
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "localspl_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
41
42 /* ############################### */
43
44 static CRITICAL_SECTION monitor_handles_cs;
45 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
46 {
47     0, 0, &monitor_handles_cs,
48     { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
49       0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
50 };
51 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
52
53 /* ############################### */
54
55 typedef struct {
56     WCHAR   src[MAX_PATH+MAX_PATH];
57     WCHAR   dst[MAX_PATH+MAX_PATH];
58     DWORD   srclen;
59     DWORD   dstlen;
60     DWORD   copyflags;
61     BOOL    lazy;
62 } apd_data_t;
63
64 typedef struct {
65     struct list     entry;
66     LPWSTR          name;
67     LPWSTR          dllname;
68     PMONITORUI      monitorUI;
69     LPMONITOR       monitor;
70     HMODULE         hdll;
71     DWORD           refcount;
72     DWORD           dwMonitorSize;
73 } monitor_t;
74
75 typedef struct {
76     LPCWSTR  envname;
77     LPCWSTR  subdir;
78     DWORD    driverversion;
79     LPCWSTR  versionregpath;
80     LPCWSTR  versionsubdir;
81 } printenv_t;
82
83 typedef struct {
84     LPWSTR name;
85     LPWSTR printername;
86     monitor_t * pm;
87     HANDLE hXcv;
88 } printer_t;
89
90 /* ############################### */
91
92 static struct list monitor_handles = LIST_INIT( monitor_handles );
93 static monitor_t * pm_localport;
94
95 static const PRINTPROVIDOR * pprovider = NULL;
96
97 static const WCHAR backslashW[] = {'\\',0};
98 static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
99 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
100 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
101 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
102 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
103 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
104 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
105 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
106 static const WCHAR emptyW[] = {0};
107 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
108                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
109                                   'c','o','n','t','r','o','l','\\',
110                                   'P','r','i','n','t','\\',
111                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
112                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
113 static const WCHAR fmt_printprocessorsW[] = { '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                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
118                                   'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
119 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
120 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
121 static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
122 static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
123 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
124 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
125 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
126 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
127 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
128                                 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129                                 'C','o','n','t','r','o','l','\\',
130                                 'P','r','i','n','t','\\',
131                                 'M','o','n','i','t','o','r','s','\\',0};
132 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
133 static const WCHAR nameW[] = {'N','a','m','e',0};
134 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
135 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
136 static const WCHAR portW[] = {'P','o','r','t',0};
137 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
138 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
139                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
140                                   'C','o','n','t','r','o','l','\\',
141                                   'P','r','i','n','t','\\',
142                                   'P','r','i','n','t','e','r','s',0};
143 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
144 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
145 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
146 static const WCHAR version0_subdirW[] = {'\\','0',0};
147 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
148 static const WCHAR version3_subdirW[] = {'\\','3',0};
149 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
150 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
152 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
153                                         'M','i','c','r','o','s','o','f','t','\\',
154                                         'W','i','n','d','o','w','s',' ','N','T','\\',
155                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
156                                         'P','o','r','t','s',0};
157 static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
158 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
159 static const WCHAR x64_subdirW[] = {'x','6','4',0};
160 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
161 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
162 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
163 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
164
165
166 static const printenv_t env_ia64 =  {ia64_envnameW, ia64_subdirW, 3,
167                                      version3_regpathW, version3_subdirW};
168
169 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
170                                      version3_regpathW, version3_subdirW};
171
172 static const printenv_t env_x64 =   {x64_envnameW, x64_subdirW, 3,
173                                      version3_regpathW, version3_subdirW};
174
175 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
176                                      version0_regpathW, version0_subdirW};
177
178 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
179
180
181 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
182                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
183                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
184                                   0, sizeof(DRIVER_INFO_8W)};
185
186
187 /******************************************************************
188  * strdupW [internal]
189  *
190  * create a copy of a unicode-string
191  *
192  */
193 static LPWSTR strdupW(LPCWSTR p)
194 {
195     LPWSTR ret;
196     DWORD len;
197
198     if(!p) return NULL;
199     len = (lstrlenW(p) + 1) * sizeof(WCHAR);
200     ret = heap_alloc(len);
201     if (ret) memcpy(ret, p, len);
202     return ret;
203 }
204
205 /******************************************************************
206  *  apd_copyfile [internal]
207  *
208  * Copy a file from the driverdirectory to the versioned directory
209  *
210  * RETURNS
211  *  Success: TRUE
212  *  Failure: FALSE
213  *
214  */
215 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
216 {
217     WCHAR *srcname;
218     DWORD res;
219
220     apd->src[apd->srclen] = '\0';
221     apd->dst[apd->dstlen] = '\0';
222
223     if (!pathname || !pathname[0]) {
224         /* nothing to copy */
225         return TRUE;
226     }
227
228     if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
229         srcname = pathname;
230     else
231     {
232         srcname = apd->src;
233         strcatW( srcname, file_part );
234     }
235     strcatW( apd->dst, file_part );
236
237     TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
238
239     /* FIXME: handle APD_COPY_NEW_FILES */
240     res = CopyFileW(srcname, apd->dst, FALSE);
241     TRACE("got %u with %u\n", res, GetLastError());
242
243     return (apd->lazy) ? TRUE : res;
244 }
245
246 /******************************************************************
247  * copy_servername_from_name  (internal)
248  *
249  * for an external server, the serverpart from the name is copied.
250  *
251  * RETURNS
252  *  the length (in WCHAR) of the serverpart (0 for the local computer)
253  *  (-length), when the name is to long
254  *
255  */
256 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
257 {
258     LPCWSTR server;
259     LPWSTR  ptr;
260     WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
261     DWORD   len;
262     DWORD   serverlen;
263
264     if (target) *target = '\0';
265
266     if (name == NULL) return 0;
267     if ((name[0] != '\\') || (name[1] != '\\')) return 0;
268
269     server = &name[2];
270     /* skip over both backslash, find separator '\' */
271     ptr = strchrW(server, '\\');
272     serverlen = (ptr) ? ptr - server : lstrlenW(server);
273
274     /* servername is empty */
275     if (serverlen == 0) return 0;
276
277     TRACE("found %s\n", debugstr_wn(server, serverlen));
278
279     if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
280
281     if (target) {
282         memcpy(target, server, serverlen * sizeof(WCHAR));
283         target[serverlen] = '\0';
284     }
285
286     len = sizeof(buffer) / sizeof(buffer[0]);
287     if (GetComputerNameW(buffer, &len)) {
288         if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
289             /* The requested Servername is our computername */
290             return 0;
291         }
292     }
293     return serverlen;
294 }
295
296 /******************************************************************
297  * get_basename_from_name  (internal)
298  *
299  * skip over the serverpart from the full name
300  *
301  */
302 static LPCWSTR get_basename_from_name(LPCWSTR name)
303 {
304     if (name == NULL)  return NULL;
305     if ((name[0] == '\\') && (name[1] == '\\')) {
306         /* skip over the servername and search for the following '\'  */
307         name = strchrW(&name[2], '\\');
308         if ((name) && (name[1])) {
309             /* found a separator ('\') followed by a name:
310                skip over the separator and return the rest */
311             name++;
312         }
313         else
314         {
315             /* no basename present (we found only a servername) */
316             return NULL;
317         }
318     }
319     return name;
320 }
321
322 /******************************************************************
323  * monitor_unload [internal]
324  *
325  * release a printmonitor and unload it from memory, when needed
326  *
327  */
328 static void monitor_unload(monitor_t * pm)
329 {
330     if (pm == NULL) return;
331     TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
332
333     EnterCriticalSection(&monitor_handles_cs);
334
335     if (pm->refcount) pm->refcount--;
336
337     if (pm->refcount == 0) {
338         list_remove(&pm->entry);
339         FreeLibrary(pm->hdll);
340         heap_free(pm->name);
341         heap_free(pm->dllname);
342         heap_free(pm);
343     }
344     LeaveCriticalSection(&monitor_handles_cs);
345 }
346
347 /******************************************************************
348  * monitor_unloadall [internal]
349  *
350  * release all registered printmonitors and unload them from memory, when needed
351  *
352  */
353
354 static void monitor_unloadall(void)
355 {
356     monitor_t * pm;
357     monitor_t * next;
358
359     EnterCriticalSection(&monitor_handles_cs);
360     /* iterate through the list, with safety against removal */
361     LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
362     {
363         /* skip monitorui dlls */
364         if (pm->monitor) monitor_unload(pm);
365     }
366     LeaveCriticalSection(&monitor_handles_cs);
367 }
368
369 /******************************************************************
370  * monitor_load [internal]
371  *
372  * load a printmonitor, get the dllname from the registry, when needed
373  * initialize the monitor and dump found function-pointers
374  *
375  * On failure, SetLastError() is called and NULL is returned
376  */
377
378 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
379 {
380     LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
381     PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
382     LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
383     DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
384     DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
385
386     monitor_t * pm = NULL;
387     monitor_t * cursor;
388     LPWSTR  regroot = NULL;
389     LPWSTR  driver = dllname;
390
391     TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
392     /* Is the Monitor already loaded? */
393     EnterCriticalSection(&monitor_handles_cs);
394
395     if (name) {
396         LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
397         {
398             if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
399                 pm = cursor;
400                 break;
401             }
402         }
403     }
404
405     if (pm == NULL) {
406         pm = heap_alloc_zero(sizeof(monitor_t));
407         if (pm == NULL) goto cleanup;
408         list_add_tail(&monitor_handles, &pm->entry);
409     }
410     pm->refcount++;
411
412     if (pm->name == NULL) {
413         /* Load the monitor */
414         LPMONITOREX pmonitorEx;
415         DWORD   len;
416
417         if (name) {
418             len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
419             regroot = heap_alloc(len * sizeof(WCHAR));
420         }
421
422         if (regroot) {
423             lstrcpyW(regroot, monitorsW);
424             lstrcatW(regroot, name);
425             /* Get the Driver from the Registry */
426             if (driver == NULL) {
427                 HKEY    hroot;
428                 DWORD   namesize;
429                 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
430                     if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
431                                         &namesize) == ERROR_SUCCESS) {
432                         driver = heap_alloc(namesize);
433                         RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
434                     }
435                     RegCloseKey(hroot);
436                 }
437             }
438         }
439
440         pm->name = strdupW(name);
441         pm->dllname = strdupW(driver);
442
443         if ((name && (!regroot || !pm->name)) || !pm->dllname) {
444             monitor_unload(pm);
445             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
446             pm = NULL;
447             goto cleanup;
448         }
449
450         pm->hdll = LoadLibraryW(driver);
451         TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
452
453         if (pm->hdll == NULL) {
454             monitor_unload(pm);
455             SetLastError(ERROR_MOD_NOT_FOUND);
456             pm = NULL;
457             goto cleanup;
458         }
459
460         pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
461         pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
462         pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
463         pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
464         pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
465
466
467         TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
468         TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
469         TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
470         TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
471         TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
472
473         if (pInitializePrintMonitorUI  != NULL) {
474             pm->monitorUI = pInitializePrintMonitorUI();
475             TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
476             if (pm->monitorUI) {
477                 TRACE("0x%08x: dwMonitorSize (%d)\n",
478                         pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
479
480             }
481         }
482
483         if (pInitializePrintMonitor && regroot) {
484             pmonitorEx = pInitializePrintMonitor(regroot);
485             TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
486                     pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
487
488             if (pmonitorEx) {
489                 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
490                 pm->monitor = &(pmonitorEx->Monitor);
491             }
492         }
493
494         if (pm->monitor) {
495             TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
496
497         }
498
499         if (!pm->monitor && regroot) {
500             if (pInitializePrintMonitor2 != NULL) {
501                 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
502             }
503             if (pInitializeMonitorEx != NULL) {
504                 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
505             }
506             if (pInitializeMonitor != NULL) {
507                 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
508             }
509         }
510         if (!pm->monitor && !pm->monitorUI) {
511             monitor_unload(pm);
512             SetLastError(ERROR_PROC_NOT_FOUND);
513             pm = NULL;
514         }
515     }
516 cleanup:
517     if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
518         pm->refcount++;
519         pm_localport = pm;
520     }
521     LeaveCriticalSection(&monitor_handles_cs);
522     if (driver != dllname) heap_free(driver);
523     heap_free(regroot);
524     TRACE("=> %p\n", pm);
525     return pm;
526 }
527
528 /******************************************************************
529  * monitor_loadall [internal]
530  *
531  * Load all registered monitors
532  *
533  */
534 static DWORD monitor_loadall(void)
535 {
536     monitor_t * pm;
537     DWORD   registered = 0;
538     DWORD   loaded = 0;
539     HKEY    hmonitors;
540     WCHAR   buffer[MAX_PATH];
541     DWORD   id = 0;
542
543     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
544         RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
545                         NULL, NULL, NULL, NULL, NULL);
546
547         TRACE("%d monitors registered\n", registered);
548
549         while (id < registered) {
550             buffer[0] = '\0';
551             RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
552             pm = monitor_load(buffer, NULL);
553             if (pm) loaded++;
554             id++;
555         }
556         RegCloseKey(hmonitors);
557     }
558     TRACE("%d monitors loaded\n", loaded);
559     return loaded;
560 }
561
562 /******************************************************************
563  * monitor_loadui [internal]
564  *
565  * load the userinterface-dll for a given portmonitor
566  *
567  * On failure, NULL is returned
568  */
569 static monitor_t * monitor_loadui(monitor_t * pm)
570 {
571     monitor_t * pui = NULL;
572     WCHAR   buffer[MAX_PATH];
573     HANDLE  hXcv;
574     DWORD   len;
575     DWORD   res;
576
577     if (pm == NULL) return NULL;
578     TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
579
580     /* Try the Portmonitor first; works for many monitors */
581     if (pm->monitorUI) {
582         EnterCriticalSection(&monitor_handles_cs);
583         pm->refcount++;
584         LeaveCriticalSection(&monitor_handles_cs);
585         return pm;
586     }
587
588     /* query the userinterface-dllname from the Portmonitor */
589     if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
590         /* building (",XcvMonitor %s",pm->name) not needed yet */
591         res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
592         TRACE("got %u with %p\n", res, hXcv);
593         if (res) {
594             res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
595             TRACE("got %u with %s\n", res, debugstr_w(buffer));
596             if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
597             pm->monitor->pfnXcvClosePort(hXcv);
598         }
599     }
600     return pui;
601 }
602
603 /******************************************************************
604  * monitor_load_by_port [internal]
605  *
606  * load a printmonitor for a given port
607  *
608  * On failure, NULL is returned
609  */
610
611 static monitor_t * monitor_load_by_port(LPCWSTR portname)
612 {
613     HKEY    hroot;
614     HKEY    hport;
615     LPWSTR  buffer;
616     monitor_t * pm = NULL;
617     DWORD   registered = 0;
618     DWORD   id = 0;
619     DWORD   len;
620
621     TRACE("(%s)\n", debugstr_w(portname));
622
623     /* Try the Local Monitor first */
624     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
625         if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
626             /* found the portname */
627             RegCloseKey(hroot);
628             return monitor_load(localportW, NULL);
629         }
630         RegCloseKey(hroot);
631     }
632
633     len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
634     buffer = heap_alloc(len * sizeof(WCHAR));
635     if (buffer == NULL) return NULL;
636
637     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
638         EnterCriticalSection(&monitor_handles_cs);
639         RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
640
641         while ((pm == NULL) && (id < registered)) {
642             buffer[0] = '\0';
643             RegEnumKeyW(hroot, id, buffer, MAX_PATH);
644             TRACE("testing %s\n", debugstr_w(buffer));
645             len = lstrlenW(buffer);
646             lstrcatW(buffer, bs_ports_bsW);
647             lstrcatW(buffer, portname);
648             if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
649                 RegCloseKey(hport);
650                 buffer[len] = '\0';             /* use only the Monitor-Name */
651                 pm = monitor_load(buffer, NULL);
652             }
653             id++;
654         }
655         LeaveCriticalSection(&monitor_handles_cs);
656         RegCloseKey(hroot);
657     }
658     heap_free(buffer);
659     return pm;
660 }
661
662 /******************************************************************
663  * Return the number of bytes for an multi_sz string.
664  * The result includes all \0s
665  * (specifically the extra \0, that is needed as multi_sz terminator).
666  */
667 static int multi_sz_lenW(const WCHAR *str)
668 {
669     const WCHAR *ptr = str;
670     if (!str) return 0;
671     do
672     {
673         ptr += lstrlenW(ptr) + 1;
674     } while (*ptr);
675
676     return (ptr - str + 1) * sizeof(WCHAR);
677 }
678
679 /******************************************************************
680  * validate_envW [internal]
681  *
682  * validate the user-supplied printing-environment
683  *
684  * PARAMS
685  *  env  [I] PTR to Environment-String or NULL
686  *
687  * RETURNS
688  *  Success:  PTR to printenv_t
689  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
690  *
691  * NOTES
692  *  An empty string is handled the same way as NULL.
693  *
694  */
695
696 static const  printenv_t * validate_envW(LPCWSTR env)
697 {
698     const printenv_t *result = NULL;
699     unsigned int i;
700
701     TRACE("(%s)\n", debugstr_w(env));
702     if (env && env[0])
703     {
704         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
705         {
706             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
707             {
708                 result = all_printenv[i];
709                 break;
710             }
711         }
712         if (result == NULL) {
713             FIXME("unsupported Environment: %s\n", debugstr_w(env));
714             SetLastError(ERROR_INVALID_ENVIRONMENT);
715         }
716         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
717     }
718     else
719     {
720         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
721     }
722
723     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
724     return result;
725 }
726
727 /*****************************************************************************
728  * enumerate the local monitors (INTERNAL)
729  *
730  * returns the needed size (in bytes) for pMonitors
731  * and  *lpreturned is set to number of entries returned in pMonitors
732  *
733  * Language-Monitors are also installed in the same Registry-Location but
734  * they are filtered in Windows (not returned by EnumMonitors).
735  * We do no filtering to simplify our Code.
736  *
737  */
738 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
739 {
740     HKEY    hroot = NULL;
741     HKEY    hentry = NULL;
742     LPWSTR  ptr;
743     LPMONITOR_INFO_2W mi;
744     WCHAR   buffer[MAX_PATH];
745     WCHAR   dllname[MAX_PATH];
746     DWORD   dllsize;
747     DWORD   len;
748     DWORD   index = 0;
749     DWORD   needed = 0;
750     DWORD   numentries;
751     DWORD   entrysize;
752
753     entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
754
755     numentries = *lpreturned;       /* this is 0, when we scan the registry */
756     len = entrysize * numentries;
757     ptr = (LPWSTR) &pMonitors[len];
758
759     numentries = 0;
760     len = sizeof(buffer)/sizeof(buffer[0]);
761     buffer[0] = '\0';
762
763     /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
764     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
765         /* Scan all Monitor-Registry-Keys */
766         while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
767             TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
768             dllsize = sizeof(dllname);
769             dllname[0] = '\0';
770
771             /* The Monitor must have a Driver-DLL */
772             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
773                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
774                     /* We found a valid DLL for this Monitor. */
775                     TRACE("using Driver: %s\n", debugstr_w(dllname));
776                 }
777                 RegCloseKey(hentry);
778             }
779
780             /* Windows returns only Port-Monitors here, but to simplify our code,
781                we do no filtering for Language-Monitors */
782             if (dllname[0]) {
783                 numentries++;
784                 needed += entrysize;
785                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
786                 if (level > 1) {
787                     /* we install and return only monitors for "Windows NT x86" */
788                     needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
789                     needed += dllsize;
790                 }
791
792                 /* required size is calculated. Now fill the user-buffer */
793                 if (pMonitors && (cbBuf >= needed)){
794                     mi = (LPMONITOR_INFO_2W) pMonitors;
795                     pMonitors += entrysize;
796
797                     TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
798                     mi->pName = ptr;
799                     lstrcpyW(ptr, buffer);      /* Name of the Monitor */
800                     ptr += (len+1);               /* len is lstrlenW(monitorname) */
801                     if (level > 1) {
802                         mi->pEnvironment = ptr;
803                         lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
804                         ptr += (lstrlenW(x86_envnameW)+1);
805
806                         mi->pDLLName = ptr;
807                         lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
808                         ptr += (dllsize / sizeof(WCHAR));
809                     }
810                 }
811             }
812             index++;
813             len = sizeof(buffer)/sizeof(buffer[0]);
814             buffer[0] = '\0';
815         }
816         RegCloseKey(hroot);
817     }
818     *lpreturned = numentries;
819     TRACE("need %d byte for %d entries\n", needed, numentries);
820     return needed;
821 }
822
823 /*****************************************************************************
824  * enumerate the local print processors (INTERNAL)
825  *
826  * returns the needed size (in bytes) for pPPInfo
827  * and  *lpreturned is set to number of entries returned in pPPInfo
828  *
829  */
830 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
831 {
832     HKEY    hroot = NULL;
833     HKEY    hentry = NULL;
834     LPWSTR  ptr;
835     PPRINTPROCESSOR_INFO_1W ppi;
836     WCHAR   buffer[MAX_PATH];
837     WCHAR   dllname[MAX_PATH];
838     DWORD   dllsize;
839     DWORD   len;
840     DWORD   index = 0;
841     DWORD   needed = 0;
842     DWORD   numentries;
843
844     numentries = *lpreturned;       /* this is 0, when we scan the registry */
845     len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
846     ptr = (LPWSTR) &pPPInfo[len];
847
848     numentries = 0;
849     len = sizeof(buffer)/sizeof(buffer[0]);
850     buffer[0] = '\0';
851
852     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
853         /* add "winprint" first */
854         numentries++;
855         needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
856         if (pPPInfo && (cbBuf >= needed)){
857             ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
858             pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
859
860             TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
861             ppi->pName = ptr;
862             lstrcpyW(ptr, winprintW);      /* Name of the Print Processor */
863             ptr += sizeof(winprintW) / sizeof(WCHAR);
864         }
865
866         /* Scan all Printprocessor Keys */
867         while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
868             (lstrcmpiW(buffer, winprintW) != 0)) {
869             TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
870             dllsize = sizeof(dllname);
871             dllname[0] = '\0';
872
873             /* The Print Processor must have a Driver-DLL */
874             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
875                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
876                     /* We found a valid DLL for this Print Processor */
877                     TRACE("using Driver: %s\n", debugstr_w(dllname));
878                 }
879                 RegCloseKey(hentry);
880             }
881
882             if (dllname[0]) {
883                 numentries++;
884                 needed += sizeof(PRINTPROCESSOR_INFO_1W);
885                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(printprocessor name) */
886
887                 /* required size is calculated. Now fill the user-buffer */
888                 if (pPPInfo && (cbBuf >= needed)){
889                     ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
890                     pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
891
892                     TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
893                     ppi->pName = ptr;
894                     lstrcpyW(ptr, buffer);      /* Name of the Print Processor */
895                     ptr += (len+1);             /* len is lstrlenW(printprosessor name) */
896                 }
897             }
898             index++;
899             len = sizeof(buffer)/sizeof(buffer[0]);
900             buffer[0] = '\0';
901         }
902         RegCloseKey(hroot);
903     }
904     *lpreturned = numentries;
905     TRACE("need %d byte for %d entries\n", needed, numentries);
906     return needed;
907 }
908
909 /******************************************************************
910  * enumerate the local Ports from all loaded monitors (internal)
911  *
912  * returns the needed size (in bytes) for pPorts
913  * and  *lpreturned is set to number of entries returned in pPorts
914  *
915  */
916 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
917 {
918     monitor_t * pm;
919     LPWSTR      ptr;
920     LPPORT_INFO_2W cache;
921     LPPORT_INFO_2W out;
922     LPBYTE  pi_buffer = NULL;
923     DWORD   pi_allocated = 0;
924     DWORD   pi_needed;
925     DWORD   pi_index;
926     DWORD   pi_returned;
927     DWORD   res;
928     DWORD   outindex = 0;
929     DWORD   needed;
930     DWORD   numentries;
931     DWORD   entrysize;
932
933
934     TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
935     entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
936
937     numentries = *lpreturned;       /* this is 0, when we scan the registry */
938     needed = entrysize * numentries;
939     ptr = (LPWSTR) &pPorts[needed];
940
941     numentries = 0;
942     needed = 0;
943
944     LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
945     {
946         if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
947             pi_needed = 0;
948             pi_returned = 0;
949             res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
950             if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
951                 /* Do not use heap_realloc (we do not need the old data in the buffer) */
952                 heap_free(pi_buffer);
953                 pi_buffer = heap_alloc(pi_needed);
954                 pi_allocated = (pi_buffer) ? pi_needed : 0;
955                 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
956             }
957             TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
958                   debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
959
960             numentries += pi_returned;
961             needed += pi_needed;
962
963             /* fill the output-buffer (pPorts), if we have one */
964             if (pPorts && (cbBuf >= needed ) && pi_buffer) {
965                 pi_index = 0;
966                 while (pi_returned > pi_index) {
967                     cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
968                     out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
969                     out->pPortName = ptr;
970                     lstrcpyW(ptr, cache->pPortName);
971                     ptr += (lstrlenW(ptr)+1);
972                     if (level > 1) {
973                         out->pMonitorName = ptr;
974                         lstrcpyW(ptr,  cache->pMonitorName);
975                         ptr += (lstrlenW(ptr)+1);
976
977                         out->pDescription = ptr;
978                         lstrcpyW(ptr,  cache->pDescription);
979                         ptr += (lstrlenW(ptr)+1);
980                         out->fPortType = cache->fPortType;
981                         out->Reserved = cache->Reserved;
982                     }
983                     pi_index++;
984                     outindex++;
985                 }
986             }
987         }
988     }
989     /* the temporary portinfo-buffer is no longer needed */
990     heap_free(pi_buffer);
991
992     *lpreturned = numentries;
993     TRACE("need %d byte for %d entries\n", needed, numentries);
994     return needed;
995 }
996
997
998 /*****************************************************************************
999  * open_driver_reg [internal]
1000  *
1001  * opens the registry for the printer drivers depending on the given input
1002  * variable pEnvironment
1003  *
1004  * RETURNS:
1005  *    Success: the opened hkey
1006  *    Failure: NULL
1007  */
1008 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1009 {
1010     HKEY  retval = NULL;
1011     LPWSTR buffer;
1012     const printenv_t * env;
1013
1014     TRACE("(%s)\n", debugstr_w(pEnvironment));
1015
1016     env = validate_envW(pEnvironment);
1017     if (!env) return NULL;
1018
1019     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1020                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1021
1022     if (buffer) {
1023         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1024         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1025         HeapFree(GetProcessHeap(), 0, buffer);
1026     }
1027     return retval;
1028 }
1029
1030 /*****************************************************************************
1031  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1032  *
1033  * Return the PATH for the Printer-Drivers
1034  *
1035  * PARAMS
1036  *   pName            [I] Servername (NT only) or NULL (local Computer)
1037  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
1038  *   Level            [I] Structure-Level (must be 1)
1039  *   pDriverDirectory [O] PTR to Buffer that receives the Result
1040  *   cbBuf            [I] Size of Buffer at pDriverDirectory
1041  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
1042  *                        required for pDriverDirectory
1043  *
1044  * RETURNS
1045  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
1046  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1047  *            if cbBuf is too small
1048  *
1049  *   Native Values returned in pDriverDirectory on Success:
1050  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
1051  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
1052  *|  win9x(Windows 4.0):  "%winsysdir%"
1053  *
1054  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
1055  *
1056  */
1057 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1058             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1059 {
1060     DWORD needed;
1061     const printenv_t * env;
1062
1063     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1064           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1065
1066     if (pName != NULL && pName[0]) {
1067         FIXME("server %s not supported\n", debugstr_w(pName));
1068         SetLastError(ERROR_INVALID_PARAMETER);
1069         return FALSE;
1070     }
1071
1072     env = validate_envW(pEnvironment);
1073     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
1074
1075
1076     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1077     needed = GetSystemDirectoryW(NULL, 0);
1078     /* add the Size for the Subdirectories */
1079     needed += lstrlenW(spooldriversW);
1080     needed += lstrlenW(env->subdir);
1081     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
1082
1083     *pcbNeeded = needed;
1084
1085     if (needed > cbBuf) {
1086         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1087         return FALSE;
1088     }
1089
1090     if (pDriverDirectory == NULL) {
1091         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1092         SetLastError(ERROR_INVALID_USER_BUFFER);
1093         return FALSE;
1094     }
1095
1096     GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
1097     /* add the Subdirectories */
1098     lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
1099     lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
1100
1101     TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
1102     return TRUE;
1103 }
1104
1105 /******************************************************************
1106  * driver_load [internal]
1107  *
1108  * load a driver user interface dll
1109  *
1110  * On failure, NULL is returned
1111  *
1112  */
1113
1114 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1115 {
1116     WCHAR fullname[MAX_PATH];
1117     HMODULE hui;
1118     DWORD len;
1119
1120     TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1121
1122     /* build the driverdir */
1123     len = sizeof(fullname) -
1124           (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1125
1126     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1127                                      (LPBYTE) fullname, len, &len)) {
1128         /* Should never Fail */
1129         SetLastError(ERROR_BUFFER_OVERFLOW);
1130         return NULL;
1131     }
1132
1133     lstrcatW(fullname, env->versionsubdir);
1134     lstrcatW(fullname, backslashW);
1135     lstrcatW(fullname, dllname);
1136
1137     hui = LoadLibraryW(fullname);
1138     TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1139
1140     return hui;
1141 }
1142
1143 /******************************************************************
1144  *  printer_free
1145  *  free the data pointer of an opened printer
1146  */
1147 static VOID printer_free(printer_t * printer)
1148 {
1149     if (printer->hXcv)
1150         printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1151
1152     monitor_unload(printer->pm);
1153
1154     heap_free(printer->printername);
1155     heap_free(printer->name);
1156     heap_free(printer);
1157 }
1158
1159 /******************************************************************
1160  *  printer_alloc_handle
1161  *  alloc a printer handle and remember the data pointer in the printer handle table
1162  *
1163  */
1164 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1165 {
1166     WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1167     printer_t *printer = NULL;
1168     LPCWSTR printername;
1169     HKEY    hkeyPrinters;
1170     HKEY    hkeyPrinter;
1171     DWORD   len;
1172
1173     if (copy_servername_from_name(name, servername)) {
1174         FIXME("server %s not supported\n", debugstr_w(servername));
1175         SetLastError(ERROR_INVALID_PRINTER_NAME);
1176         return NULL;
1177     }
1178
1179     printername = get_basename_from_name(name);
1180     if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1181
1182     /* an empty printername is invalid */
1183     if (printername && (!printername[0])) {
1184         SetLastError(ERROR_INVALID_PARAMETER);
1185         return NULL;
1186     }
1187
1188     printer = heap_alloc_zero(sizeof(printer_t));
1189     if (!printer) goto end;
1190
1191     /* clone the base name. This is NULL for the printserver */
1192     printer->printername = strdupW(printername);
1193
1194     /* clone the full name */
1195     printer->name = strdupW(name);
1196     if (name && (!printer->name)) {
1197         printer_free(printer);
1198         printer = NULL;
1199     }
1200     if (printername) {
1201         len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1202         if (strncmpW(printername, XcvMonitorW, len) == 0) {
1203             /* OpenPrinter(",XcvMonitor ", ...) detected */
1204             TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1205             printer->pm = monitor_load(&printername[len], NULL);
1206             if (printer->pm == NULL) {
1207                 printer_free(printer);
1208                 SetLastError(ERROR_UNKNOWN_PORT);
1209                 printer = NULL;
1210                 goto end;
1211             }
1212         }
1213         else
1214         {
1215             len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1216             if (strncmpW( printername, XcvPortW, len) == 0) {
1217                 /* OpenPrinter(",XcvPort ", ...) detected */
1218                 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1219                 printer->pm = monitor_load_by_port(&printername[len]);
1220                 if (printer->pm == NULL) {
1221                     printer_free(printer);
1222                     SetLastError(ERROR_UNKNOWN_PORT);
1223                     printer = NULL;
1224                     goto end;
1225                 }
1226             }
1227         }
1228
1229         if (printer->pm) {
1230             if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1231                 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1232                                                     pDefault ? pDefault->DesiredAccess : 0,
1233                                                     &printer->hXcv);
1234             }
1235             if (printer->hXcv == NULL) {
1236                 printer_free(printer);
1237                 SetLastError(ERROR_INVALID_PARAMETER);
1238                 printer = NULL;
1239                 goto end;
1240             }
1241         }
1242         else
1243         {
1244             /* Does the Printer exist? */
1245             if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1246                 ERR("Can't create Printers key\n");
1247                 printer_free(printer);
1248                 SetLastError(ERROR_INVALID_PRINTER_NAME);
1249                 printer = NULL;
1250                 goto end;
1251             }
1252             if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1253                 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1254                 RegCloseKey(hkeyPrinters);
1255                 printer_free(printer);
1256                 SetLastError(ERROR_INVALID_PRINTER_NAME);
1257                 printer = NULL;
1258                 goto end;
1259             }
1260             RegCloseKey(hkeyPrinter);
1261             RegCloseKey(hkeyPrinters);
1262         }
1263     }
1264     else
1265     {
1266         TRACE("using the local printserver\n");
1267     }
1268
1269 end:
1270
1271     TRACE("==> %p\n", printer);
1272     return (HANDLE)printer;
1273 }
1274
1275 static inline WCHAR *get_file_part( WCHAR *name )
1276 {
1277     WCHAR *ptr = strrchrW( name, '\\' );
1278     if (ptr) return ptr + 1;
1279     return name;
1280 }
1281
1282 /******************************************************************************
1283  *  myAddPrinterDriverEx [internal]
1284  *
1285  * Install a Printer Driver with the Option to upgrade / downgrade the Files
1286  * and a special mode with lazy error checking.
1287  *
1288  */
1289 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1290 {
1291     const printenv_t *env;
1292     apd_data_t apd;
1293     DRIVER_INFO_8W di;
1294     BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1295     HMODULE hui;
1296     WCHAR *file;
1297     HKEY    hroot;
1298     HKEY    hdrv;
1299     DWORD   disposition;
1300     DWORD   len;
1301     LONG    lres;
1302     BOOL    res;
1303
1304     /* we need to set all entries in the Registry, independent from the Level of
1305        DRIVER_INFO, that the caller supplied */
1306
1307     ZeroMemory(&di, sizeof(di));
1308     if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1309         memcpy(&di, pDriverInfo, di_sizeof[level]);
1310     }
1311
1312     /* dump the most used infos */
1313     TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1314     TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
1315     TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1316     TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1317     TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1318     TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1319     TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1320     /* dump only the first of the additional Files */
1321     TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1322
1323
1324     /* check environment */
1325     env = validate_envW(di.pEnvironment);
1326     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
1327
1328     /* fill the copy-data / get the driverdir */
1329     len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1330     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1331                                     (LPBYTE) apd.src, len, &len)) {
1332         /* Should never Fail */
1333         return FALSE;
1334     }
1335     memcpy(apd.dst, apd.src, len);
1336     lstrcatW(apd.src, backslashW);
1337     apd.srclen = lstrlenW(apd.src);
1338     lstrcatW(apd.dst, env->versionsubdir);
1339     lstrcatW(apd.dst, backslashW);
1340     apd.dstlen = lstrlenW(apd.dst);
1341     apd.copyflags = dwFileCopyFlags;
1342     apd.lazy = lazy;
1343     CreateDirectoryW(apd.src, NULL);
1344     CreateDirectoryW(apd.dst, NULL);
1345
1346     hroot = open_driver_reg(env->envname);
1347     if (!hroot) {
1348         ERR("Can't create Drivers key\n");
1349         return FALSE;
1350     }
1351
1352     /* Fill the Registry for the Driver */
1353     if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1354                                 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1355                                 &hdrv, &disposition)) != ERROR_SUCCESS) {
1356
1357         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1358         RegCloseKey(hroot);
1359         SetLastError(lres);
1360         return FALSE;
1361     }
1362     RegCloseKey(hroot);
1363
1364     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1365     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1366                    sizeof(DWORD));
1367
1368     file = get_file_part( di.pDriverPath );
1369     RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1370     apd_copyfile( di.pDriverPath, file, &apd );
1371
1372     file = get_file_part( di.pDataFile );
1373     RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1374     apd_copyfile( di.pDataFile, file, &apd );
1375
1376     file = get_file_part( di.pConfigFile );
1377     RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1378     apd_copyfile( di.pConfigFile, file, &apd );
1379
1380     /* settings for level 3 */
1381     if (di.pHelpFile)
1382     {
1383         file = get_file_part( di.pHelpFile );
1384         RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1385         apd_copyfile( di.pHelpFile, file, &apd );
1386     }
1387     else
1388         RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
1389
1390     if (di.pDependentFiles && *di.pDependentFiles)
1391     {
1392         WCHAR *reg, *reg_ptr, *in_ptr;
1393         reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1394
1395         for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += strlenW( in_ptr ) + 1)
1396         {
1397             file = get_file_part( in_ptr );
1398             len = strlenW( file ) + 1;
1399             memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1400             reg_ptr += len;
1401             apd_copyfile( in_ptr, file, &apd );
1402         }
1403         *reg_ptr = 0;
1404
1405         RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1406         HeapFree( GetProcessHeap(), 0, reg );
1407     }
1408     else
1409         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1410
1411     /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1412     if (di.pMonitorName)
1413         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1414                        (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1415     else
1416         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1417
1418     if (di.pDefaultDataType)
1419         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1420                        (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1421     else
1422         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1423
1424     /* settings for level 4 */
1425     if (di.pszzPreviousNames)
1426         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1427                        multi_sz_lenW(di.pszzPreviousNames));
1428     else
1429         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1430
1431     if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1432
1433     RegCloseKey(hdrv);
1434     hui = driver_load(env, di.pConfigFile);
1435     pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1436     if (hui && pDrvDriverEvent) {
1437
1438         /* Support for DrvDriverEvent is optional */
1439         TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1440         /* MSDN: level for DRIVER_INFO is 1 to 3 */
1441         res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1442         TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1443     }
1444     FreeLibrary(hui);
1445
1446     TRACE("=> TRUE with %u\n", GetLastError());
1447     return TRUE;
1448
1449 }
1450
1451 /******************************************************************************
1452  * fpAddMonitor [exported through PRINTPROVIDOR]
1453  *
1454  * Install a Printmonitor
1455  *
1456  * PARAMS
1457  *  pName       [I] Servername or NULL (local Computer)
1458  *  Level       [I] Structure-Level (Must be 2)
1459  *  pMonitors   [I] PTR to MONITOR_INFO_2
1460  *
1461  * RETURNS
1462  *  Success: TRUE
1463  *  Failure: FALSE
1464  *
1465  * NOTES
1466  *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1467  *
1468  */
1469 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1470 {
1471     monitor_t * pm = NULL;
1472     LPMONITOR_INFO_2W mi2w;
1473     HKEY    hroot = NULL;
1474     HKEY    hentry = NULL;
1475     DWORD   disposition;
1476     BOOL    res = FALSE;
1477
1478     mi2w = (LPMONITOR_INFO_2W) pMonitors;
1479     TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1480             debugstr_w(mi2w ? mi2w->pName : NULL),
1481             debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1482             debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1483
1484     if (copy_servername_from_name(pName, NULL)) {
1485         FIXME("server %s not supported\n", debugstr_w(pName));
1486         SetLastError(ERROR_ACCESS_DENIED);
1487         return FALSE;
1488     }
1489
1490     if (!mi2w->pName || (! mi2w->pName[0])) {
1491         WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1492         SetLastError(ERROR_INVALID_PARAMETER);
1493         return FALSE;
1494     }
1495     if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1496         WARN("Environment %s requested (we support only %s)\n",
1497                 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1498         SetLastError(ERROR_INVALID_ENVIRONMENT);
1499         return FALSE;
1500     }
1501
1502     if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1503         WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1504         SetLastError(ERROR_INVALID_PARAMETER);
1505         return FALSE;
1506     }
1507
1508     /* Load and initialize the monitor. SetLastError() is called on failure */
1509     if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1510         return FALSE;
1511     }
1512     monitor_unload(pm);
1513
1514     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1515         ERR("unable to create key %s\n", debugstr_w(monitorsW));
1516         return FALSE;
1517     }
1518
1519     if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1520                         KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1521                         &disposition) == ERROR_SUCCESS) {
1522
1523         /* Some installers set options for the port before calling AddMonitor.
1524            We query the "Driver" entry to verify that the monitor is installed,
1525            before we return an error.
1526            When a user installs two print monitors at the same time with the
1527            same name, a race condition is possible but silently ignored. */
1528
1529         DWORD   namesize = 0;
1530
1531         if ((disposition == REG_OPENED_EXISTING_KEY) &&
1532             (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1533                               &namesize) == ERROR_SUCCESS)) {
1534             TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1535             /* 9x use ERROR_ALREADY_EXISTS */
1536             SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1537         }
1538         else
1539         {
1540             INT len;
1541             len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1542             res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1543                     (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1544         }
1545         RegCloseKey(hentry);
1546     }
1547
1548     RegCloseKey(hroot);
1549     return (res);
1550 }
1551
1552 /******************************************************************************
1553  * fpAddPort [exported through PRINTPROVIDOR]
1554  *
1555  * Add a Port for a specific Monitor
1556  *
1557  * PARAMS
1558  *  pName        [I] Servername or NULL (local Computer)
1559  *  hWnd         [I] Handle to parent Window for the Dialog-Box
1560  *  pMonitorName [I] Name of the Monitor that manage the Port
1561  *
1562  * RETURNS
1563  *  Success: TRUE
1564  *  Failure: FALSE
1565  *
1566  */
1567 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1568 {
1569     monitor_t * pm;
1570     monitor_t * pui;
1571     LONG        lres;
1572     DWORD       res;
1573
1574     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1575
1576     lres = copy_servername_from_name(pName, NULL);
1577     if (lres) {
1578         FIXME("server %s not supported\n", debugstr_w(pName));
1579         SetLastError(ERROR_INVALID_PARAMETER);
1580         return FALSE;
1581     }
1582
1583     /* an empty Monitorname is Invalid */
1584     if (!pMonitorName[0]) {
1585         SetLastError(ERROR_NOT_SUPPORTED);
1586         return FALSE;
1587     }
1588
1589     pm = monitor_load(pMonitorName, NULL);
1590     if (pm && pm->monitor && pm->monitor->pfnAddPort) {
1591         res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
1592         TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1593     }
1594     else
1595     {
1596         pui = monitor_loadui(pm);
1597         if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1598             res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1599             TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1600         }
1601         else
1602         {
1603             FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1604                     debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1605                     pui, debugstr_w(pui ? pui->dllname : NULL));
1606
1607             SetLastError(ERROR_NOT_SUPPORTED);
1608             res = FALSE;
1609         }
1610         monitor_unload(pui);
1611     }
1612     monitor_unload(pm);
1613
1614     TRACE("returning %d with %u\n", res, GetLastError());
1615     return res;
1616 }
1617
1618 /******************************************************************************
1619  * fpAddPortEx [exported through PRINTPROVIDOR]
1620  *
1621  * Add a Port for a specific Monitor, without presenting a user interface
1622  *
1623  * PARAMS
1624  *  pName         [I] Servername or NULL (local Computer)
1625  *  level         [I] Structure-Level (1 or 2) for pBuffer
1626  *  pBuffer       [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1627  *  pMonitorName  [I] Name of the Monitor that manage the Port
1628  *
1629  * RETURNS
1630  *  Success: TRUE
1631  *  Failure: FALSE
1632  *
1633  */
1634 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1635 {
1636     PORT_INFO_2W * pi2;
1637     monitor_t * pm;
1638     DWORD lres;
1639     DWORD res;
1640
1641     pi2 = (PORT_INFO_2W *) pBuffer;
1642
1643     TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1644             debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1645             debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1646             debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1647
1648     lres = copy_servername_from_name(pName, NULL);
1649     if (lres) {
1650         FIXME("server %s not supported\n", debugstr_w(pName));
1651         SetLastError(ERROR_INVALID_PARAMETER);
1652         return FALSE;
1653     }
1654
1655     if ((level < 1) || (level > 2)) {
1656         SetLastError(ERROR_INVALID_LEVEL);
1657         return FALSE;
1658     }
1659
1660     if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1661         SetLastError(ERROR_INVALID_PARAMETER);
1662         return FALSE;
1663     }
1664
1665     /* load the Monitor */
1666     pm = monitor_load(pMonitorName, NULL);
1667     if (pm && pm->monitor && pm->monitor->pfnAddPortEx) {
1668         res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
1669         TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1670     }
1671     else
1672     {
1673         FIXME("not implemented for %s (monitor %p: %s)\n",
1674             debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
1675             SetLastError(ERROR_INVALID_PARAMETER);
1676             res = FALSE;
1677     }
1678     monitor_unload(pm);
1679     return res;
1680 }
1681
1682 /******************************************************************************
1683  * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1684  *
1685  * Install a Printer Driver with the Option to upgrade / downgrade the Files
1686  *
1687  * PARAMS
1688  *  pName           [I] Servername or NULL (local Computer)
1689  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
1690  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1691  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1692  *
1693  * RESULTS
1694  *  Success: TRUE
1695  *  Failure: FALSE
1696  *
1697  */
1698 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1699 {
1700     LONG lres;
1701
1702     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1703     lres = copy_servername_from_name(pName, NULL);
1704     if (lres) {
1705         FIXME("server %s not supported\n", debugstr_w(pName));
1706         SetLastError(ERROR_ACCESS_DENIED);
1707         return FALSE;
1708     }
1709
1710     if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1711         TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1712     }
1713
1714     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1715 }
1716
1717 /******************************************************************************
1718  * fpClosePrinter [exported through PRINTPROVIDOR]
1719  *
1720  * Close a printer handle and free associated resources
1721  *
1722  * PARAMS
1723  *  hPrinter [I] Printerhandle to close
1724  *
1725  * RESULTS
1726  *  Success: TRUE
1727  *  Failure: FALSE
1728  *
1729  */
1730 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1731 {
1732     printer_t *printer = (printer_t *) hPrinter;
1733
1734     TRACE("(%p)\n", hPrinter);
1735
1736     if (printer) {
1737         printer_free(printer);
1738         return TRUE;
1739     }
1740     return FALSE;
1741 }
1742
1743 /******************************************************************************
1744  * fpConfigurePort [exported through PRINTPROVIDOR]
1745  *
1746  * Display the Configuration-Dialog for a specific Port
1747  *
1748  * PARAMS
1749  *  pName     [I] Servername or NULL (local Computer)
1750  *  hWnd      [I] Handle to parent Window for the Dialog-Box
1751  *  pPortName [I] Name of the Port, that should be configured
1752  *
1753  * RETURNS
1754  *  Success: TRUE
1755  *  Failure: FALSE
1756  *
1757  */
1758 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1759 {
1760     monitor_t * pm;
1761     monitor_t * pui;
1762     LONG        lres;
1763     DWORD       res;
1764
1765     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1766
1767     lres = copy_servername_from_name(pName, NULL);
1768     if (lres) {
1769         FIXME("server %s not supported\n", debugstr_w(pName));
1770         SetLastError(ERROR_INVALID_NAME);
1771         return FALSE;
1772     }
1773
1774     /* an empty Portname is Invalid, but can popup a Dialog */
1775     if (!pPortName[0]) {
1776         SetLastError(ERROR_NOT_SUPPORTED);
1777         return FALSE;
1778     }
1779
1780     pm = monitor_load_by_port(pPortName);
1781     if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
1782         TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1783                 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1784         res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
1785         TRACE("got %d with %u\n", res, GetLastError());
1786     }
1787     else
1788     {
1789         pui = monitor_loadui(pm);
1790         if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1791             TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1792                         debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1793             res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1794             TRACE("got %d with %u\n", res, GetLastError());
1795         }
1796         else
1797         {
1798             FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1799                     debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1800                     pui, debugstr_w(pui ? pui->dllname : NULL));
1801
1802             SetLastError(ERROR_NOT_SUPPORTED);
1803             res = FALSE;
1804         }
1805         monitor_unload(pui);
1806     }
1807     monitor_unload(pm);
1808
1809     TRACE("returning %d with %u\n", res, GetLastError());
1810     return res;
1811 }
1812
1813 /******************************************************************
1814  * fpDeleteMonitor [exported through PRINTPROVIDOR]
1815  *
1816  * Delete a specific Printmonitor from a Printing-Environment
1817  *
1818  * PARAMS
1819  *  pName        [I] Servername or NULL (local Computer)
1820  *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1821  *  pMonitorName [I] Name of the Monitor, that should be deleted
1822  *
1823  * RETURNS
1824  *  Success: TRUE
1825  *  Failure: FALSE
1826  *
1827  * NOTES
1828  *  pEnvironment is ignored in Windows for the local Computer.
1829  *
1830  */
1831
1832 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1833 {
1834     HKEY    hroot = NULL;
1835     LONG    lres;
1836
1837     TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1838            debugstr_w(pMonitorName));
1839
1840     lres = copy_servername_from_name(pName, NULL);
1841     if (lres) {
1842         FIXME("server %s not supported\n", debugstr_w(pName));
1843         SetLastError(ERROR_INVALID_NAME);
1844         return FALSE;
1845     }
1846
1847     /*  pEnvironment is ignored in Windows for the local Computer */
1848     if (!pMonitorName || !pMonitorName[0]) {
1849         TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1850         SetLastError(ERROR_INVALID_PARAMETER);
1851         return FALSE;
1852     }
1853
1854     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1855         ERR("unable to create key %s\n", debugstr_w(monitorsW));
1856         return FALSE;
1857     }
1858
1859     if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1860         TRACE("%s deleted\n", debugstr_w(pMonitorName));
1861         RegCloseKey(hroot);
1862         return TRUE;
1863     }
1864
1865     TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1866     RegCloseKey(hroot);
1867
1868     /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1869     SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1870     return FALSE;
1871 }
1872
1873 /*****************************************************************************
1874  * fpDeletePort [exported through PRINTPROVIDOR]
1875  *
1876  * Delete a specific Port
1877  *
1878  * PARAMS
1879  *  pName     [I] Servername or NULL (local Computer)
1880  *  hWnd      [I] Handle to parent Window for the Dialog-Box
1881  *  pPortName [I] Name of the Port, that should be deleted
1882  *
1883  * RETURNS
1884  *  Success: TRUE
1885  *  Failure: FALSE
1886  *
1887  */
1888 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1889 {
1890     monitor_t * pm;
1891     monitor_t * pui;
1892     LONG        lres;
1893     DWORD       res;
1894
1895     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1896
1897     lres = copy_servername_from_name(pName, NULL);
1898     if (lres) {
1899         FIXME("server %s not supported\n", debugstr_w(pName));
1900         SetLastError(ERROR_INVALID_NAME);
1901         return FALSE;
1902     }
1903
1904     /* an empty Portname is Invalid */
1905     if (!pPortName[0]) {
1906         SetLastError(ERROR_NOT_SUPPORTED);
1907         return FALSE;
1908     }
1909
1910     pm = monitor_load_by_port(pPortName);
1911     if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
1912         TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1913                 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1914         res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
1915         TRACE("got %d with %u\n", res, GetLastError());
1916     }
1917     else
1918     {
1919         pui = monitor_loadui(pm);
1920         if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
1921             TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1922                         debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1923             res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
1924             TRACE("got %d with %u\n", res, GetLastError());
1925         }
1926         else
1927         {
1928             FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1929                     debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1930                     pui, debugstr_w(pui ? pui->dllname : NULL));
1931
1932             SetLastError(ERROR_NOT_SUPPORTED);
1933             res = FALSE;
1934         }
1935         monitor_unload(pui);
1936     }
1937     monitor_unload(pm);
1938
1939     TRACE("returning %d with %u\n", res, GetLastError());
1940     return res;
1941 }
1942
1943 /*****************************************************************************
1944  * fpEnumMonitors [exported through PRINTPROVIDOR]
1945  *
1946  * Enumerate available Port-Monitors
1947  *
1948  * PARAMS
1949  *  pName      [I] Servername or NULL (local Computer)
1950  *  Level      [I] Structure-Level (1:Win9x+NT or 2:NT only)
1951  *  pMonitors  [O] PTR to Buffer that receives the Result
1952  *  cbBuf      [I] Size of Buffer at pMonitors
1953  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1954  *  pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1955  *
1956  * RETURNS
1957  *  Success: TRUE
1958  *  Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1959  *
1960  * NOTES
1961  *  Windows reads the Registry once and cache the Results.
1962  *
1963  */
1964 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1965                                   LPDWORD pcbNeeded, LPDWORD pcReturned)
1966 {
1967     DWORD   numentries = 0;
1968     DWORD   needed = 0;
1969     LONG    lres;
1970     BOOL    res = FALSE;
1971
1972     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1973           cbBuf, pcbNeeded, pcReturned);
1974
1975     lres = copy_servername_from_name(pName, NULL);
1976     if (lres) {
1977         FIXME("server %s not supported\n", debugstr_w(pName));
1978         SetLastError(ERROR_INVALID_NAME);
1979         goto em_cleanup;
1980     }
1981
1982     if (!Level || (Level > 2)) {
1983         WARN("level (%d) is ignored in win9x\n", Level);
1984         SetLastError(ERROR_INVALID_LEVEL);
1985         return FALSE;
1986     }
1987
1988     /* Scan all Monitor-Keys */
1989     numentries = 0;
1990     needed = get_local_monitors(Level, NULL, 0, &numentries);
1991
1992     /* we calculated the needed buffersize. now do more error-checks */
1993     if (cbBuf < needed) {
1994         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1995         goto em_cleanup;
1996     }
1997
1998     /* fill the Buffer with the Monitor-Keys */
1999     needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2000     res = TRUE;
2001
2002 em_cleanup:
2003     if (pcbNeeded)  *pcbNeeded = needed;
2004     if (pcReturned) *pcReturned = numentries;
2005
2006     TRACE("returning %d with %d (%d byte for %d entries)\n",
2007             res, GetLastError(), needed, numentries);
2008
2009     return (res);
2010 }
2011
2012 /******************************************************************************
2013  * fpEnumPorts [exported through PRINTPROVIDOR]
2014  *
2015  * Enumerate available Ports
2016  *
2017  * PARAMS
2018  *  pName      [I] Servername or NULL (local Computer)
2019  *  Level      [I] Structure-Level (1 or 2)
2020  *  pPorts     [O] PTR to Buffer that receives the Result
2021  *  cbBuf      [I] Size of Buffer at pPorts
2022  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2023  *  pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2024  *
2025  * RETURNS
2026  *  Success: TRUE
2027  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2028  *
2029  */
2030 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2031                                LPDWORD pcbNeeded, LPDWORD pcReturned)
2032 {
2033     DWORD   needed = 0;
2034     DWORD   numentries = 0;
2035     LONG    lres;
2036     BOOL    res = FALSE;
2037
2038     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2039           cbBuf, pcbNeeded, pcReturned);
2040
2041     lres = copy_servername_from_name(pName, NULL);
2042     if (lres) {
2043         FIXME("server %s not supported\n", debugstr_w(pName));
2044         SetLastError(ERROR_INVALID_NAME);
2045         goto emP_cleanup;
2046     }
2047
2048     if (!Level || (Level > 2)) {
2049         SetLastError(ERROR_INVALID_LEVEL);
2050         goto emP_cleanup;
2051     }
2052
2053     if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2054         SetLastError(RPC_X_NULL_REF_POINTER);
2055         goto emP_cleanup;
2056     }
2057
2058     EnterCriticalSection(&monitor_handles_cs);
2059     monitor_loadall();
2060
2061     /* Scan all local Ports */
2062     numentries = 0;
2063     needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2064
2065     /* we calculated the needed buffersize. now do the error-checks */
2066     if (cbBuf < needed) {
2067         monitor_unloadall();
2068         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2069         goto emP_cleanup_cs;
2070     }
2071     else if (!pPorts || !pcReturned) {
2072         monitor_unloadall();
2073         SetLastError(RPC_X_NULL_REF_POINTER);
2074         goto emP_cleanup_cs;
2075     }
2076
2077     /* Fill the Buffer */
2078     needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2079     res = TRUE;
2080     monitor_unloadall();
2081
2082 emP_cleanup_cs:
2083     LeaveCriticalSection(&monitor_handles_cs);
2084
2085 emP_cleanup:
2086     if (pcbNeeded)  *pcbNeeded = needed;
2087     if (pcReturned) *pcReturned = (res) ? numentries : 0;
2088
2089     TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2090           (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2091
2092     return (res);
2093 }
2094
2095 /*****************************************************************************
2096  * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2097  *
2098  * Enumerate available Print Processors
2099  *
2100  * PARAMS
2101  *  pName        [I] Servername or NULL (local Computer)
2102  *  pEnvironment [I] Printing-Environment or NULL (Default)
2103  *  Level        [I] Structure-Level (Only 1 is allowed)
2104  *  pPPInfo      [O] PTR to Buffer that receives the Result
2105  *  cbBuf        [I] Size of Buffer at pMonitors
2106  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2107  *  pcReturned   [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2108  *
2109  * RETURNS
2110  *  Success: TRUE
2111  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2112  *
2113  */
2114 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2115                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2116 {
2117     const printenv_t * env;
2118     LPWSTR  regpathW = NULL;
2119     DWORD   numentries = 0;
2120     DWORD   needed = 0;
2121     LONG    lres;
2122     BOOL    res = FALSE;
2123
2124     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2125                                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2126
2127     lres = copy_servername_from_name(pName, NULL);
2128     if (lres) {
2129         FIXME("server %s not supported\n", debugstr_w(pName));
2130         SetLastError(ERROR_INVALID_NAME);
2131         goto epp_cleanup;
2132     }
2133
2134     if (Level != 1) {
2135         SetLastError(ERROR_INVALID_LEVEL);
2136         goto epp_cleanup;
2137     }
2138
2139     env = validate_envW(pEnvironment);
2140     if (!env)
2141         goto epp_cleanup;   /* ERROR_INVALID_ENVIRONMENT */
2142
2143     regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
2144                             (lstrlenW(env->envname) * sizeof(WCHAR)));
2145
2146     if (!regpathW)
2147         goto epp_cleanup;
2148
2149     wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2150
2151     /* Scan all Printprocessor-Keys */
2152     numentries = 0;
2153     needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2154
2155     /* we calculated the needed buffersize. now do more error-checks */
2156     if (cbBuf < needed) {
2157         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2158         goto epp_cleanup;
2159     }
2160
2161     /* fill the Buffer with the Printprocessor Infos */
2162     needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2163     res = TRUE;
2164
2165 epp_cleanup:
2166     heap_free(regpathW);
2167     if (pcbNeeded)  *pcbNeeded = needed;
2168     if (pcReturned) *pcReturned = numentries;
2169
2170     TRACE("returning %d with %d (%d byte for %d entries)\n",
2171             res, GetLastError(), needed, numentries);
2172
2173     return (res);
2174 }
2175
2176 /******************************************************************************
2177  * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2178  *
2179  * Return the PATH for the Print-Processors
2180  *
2181  * PARAMS
2182  *  pName        [I] Servername or NULL (this computer)
2183  *  pEnvironment [I] Printing-Environment or NULL (Default)
2184  *  level        [I] Structure-Level (must be 1)
2185  *  pPPInfo      [O] PTR to Buffer that receives the Result
2186  *  cbBuf        [I] Size of Buffer at pPPInfo
2187  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2188  *
2189  * RETURNS
2190  *  Success: TRUE
2191  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2192  *
2193  *  Native Values returned in pPPInfo on Success for this computer:
2194  *| NT(Windows x64):    "%winsysdir%\\spool\\PRTPROCS\\x64"
2195  *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2196  *| NT(Windows 4.0):    "%winsysdir%\\spool\\PRTPROCS\\win40"
2197  *
2198  *  "%winsysdir%" is the Value from GetSystemDirectoryW()
2199  *
2200  */
2201 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2202                                                 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2203 {
2204     const printenv_t * env;
2205     DWORD needed;
2206     LONG  lres;
2207
2208     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2209                                         level, pPPInfo, cbBuf, pcbNeeded);
2210
2211     *pcbNeeded = 0;
2212     lres = copy_servername_from_name(pName, NULL);
2213     if (lres) {
2214         FIXME("server %s not supported\n", debugstr_w(pName));
2215         SetLastError(RPC_S_SERVER_UNAVAILABLE);
2216         return FALSE;
2217     }
2218
2219     env = validate_envW(pEnvironment);
2220     if (!env)
2221         return FALSE;   /* ERROR_INVALID_ENVIRONMENT */
2222
2223     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2224     needed = GetSystemDirectoryW(NULL, 0);
2225     /* add the Size for the Subdirectories */
2226     needed += lstrlenW(spoolprtprocsW);
2227     needed += lstrlenW(env->subdir);
2228     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
2229
2230     *pcbNeeded = needed;
2231
2232     if (needed > cbBuf) {
2233         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2234         return FALSE;
2235     }
2236
2237     GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2238     /* add the Subdirectories */
2239     lstrcatW((LPWSTR) pPPInfo, spoolprtprocsW);
2240     lstrcatW((LPWSTR) pPPInfo, env->subdir);
2241     TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2242     return TRUE;
2243 }
2244
2245 /******************************************************************************
2246  * fpOpenPrinter [exported through PRINTPROVIDOR]
2247  *
2248  * Open a Printer / Printserver or a Printer-Object
2249  *
2250  * PARAMS
2251  *  lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2252  *  pPrinter      [O] The resulting Handle is stored here
2253  *  pDefaults     [I] PTR to Default Printer Settings or NULL
2254  *
2255  * RETURNS
2256  *  Success: TRUE
2257  *  Failure: FALSE
2258  *
2259  * NOTES
2260  *  lpPrinterName is one of:
2261  *|  Printserver (NT only): "Servername" or NULL for the local Printserver
2262  *|  Printer: "PrinterName"
2263  *|  Printer-Object: "PrinterName,Job xxx"
2264  *|  XcvMonitor: "Servername,XcvMonitor MonitorName"
2265  *|  XcvPort: "Servername,XcvPort PortName"
2266  *
2267  *
2268  */
2269 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2270                                  LPPRINTER_DEFAULTSW pDefaults)
2271 {
2272
2273     TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2274
2275     *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2276
2277     return (*pPrinter != 0);
2278 }
2279
2280 /******************************************************************************
2281  * fpXcvData [exported through PRINTPROVIDOR]
2282  *
2283  * Execute commands in the Printmonitor DLL
2284  *
2285  * PARAMS
2286  *  hXcv            [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2287  *  pszDataName     [i] Name of the command to execute
2288  *  pInputData      [i] Buffer for extra Input Data (needed only for some commands)
2289  *  cbInputData     [i] Size in Bytes of Buffer at pInputData
2290  *  pOutputData     [o] Buffer to receive additional Data (needed only for some commands)
2291  *  cbOutputData    [i] Size in Bytes of Buffer at pOutputData
2292  *  pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2293  *  pdwStatus       [o] PTR to receive the win32 error code from the Printmonitor DLL
2294  *
2295  * RETURNS
2296  *  Success: TRUE
2297  *  Failure: FALSE
2298  *
2299  * NOTES
2300  *  Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2301  *  The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2302  *
2303  *  Minimal List of commands, that a Printmonitor DLL should support:
2304  *
2305  *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2306  *| "AddPort"   : Add a Port
2307  *| "DeletePort": Delete a Port
2308  *
2309  *  Many Printmonitors support additional commands. Examples for localspl.dll:
2310  *  "GetDefaultCommConfig", "SetDefaultCommConfig",
2311  *  "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2312  *
2313  */
2314 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2315                     DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2316                     PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2317 {
2318     printer_t *printer = (printer_t * ) hXcv;
2319
2320     TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2321           pInputData, cbInputData, pOutputData,
2322           cbOutputData, pcbOutputNeeded, pdwStatus);
2323
2324     if (!printer || (!printer->hXcv)) {
2325         SetLastError(ERROR_INVALID_HANDLE);
2326         return FALSE;
2327     }
2328
2329     if (!pcbOutputNeeded) {
2330         SetLastError(ERROR_INVALID_PARAMETER);
2331         return FALSE;
2332     }
2333
2334     if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2335         SetLastError(RPC_X_NULL_REF_POINTER);
2336         return FALSE;
2337     }
2338
2339     *pcbOutputNeeded = 0;
2340
2341     *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
2342             pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2343
2344     return TRUE;
2345 }
2346
2347 /*****************************************************
2348  *  setup_provider [internal]
2349  */
2350 void setup_provider(void)
2351 {
2352     static const PRINTPROVIDOR backend = {
2353         fpOpenPrinter,
2354         NULL,   /* fpSetJob */
2355         NULL,   /* fpGetJob */
2356         NULL,   /* fpEnumJobs */
2357         NULL,   /* fpAddPrinter */
2358         NULL,   /* fpDeletePrinter */
2359         NULL,   /* fpSetPrinter */
2360         NULL,   /* fpGetPrinter */
2361         NULL,   /* fpEnumPrinters */
2362         NULL,   /* fpAddPrinterDriver */
2363         NULL,   /* fpEnumPrinterDrivers */
2364         NULL,   /* fpGetPrinterDriver */
2365         fpGetPrinterDriverDirectory,
2366         NULL,   /* fpDeletePrinterDriver */
2367         NULL,   /* fpAddPrintProcessor */
2368         fpEnumPrintProcessors,
2369         fpGetPrintProcessorDirectory,
2370         NULL,   /* fpDeletePrintProcessor */
2371         NULL,   /* fpEnumPrintProcessorDatatypes */
2372         NULL,   /* fpStartDocPrinter */
2373         NULL,   /* fpStartPagePrinter */
2374         NULL,   /* fpWritePrinter */
2375         NULL,   /* fpEndPagePrinter */
2376         NULL,   /* fpAbortPrinter */
2377         NULL,   /* fpReadPrinter */
2378         NULL,   /* fpEndDocPrinter */
2379         NULL,   /* fpAddJob */
2380         NULL,   /* fpScheduleJob */
2381         NULL,   /* fpGetPrinterData */
2382         NULL,   /* fpSetPrinterData */
2383         NULL,   /* fpWaitForPrinterChange */
2384         fpClosePrinter,
2385         NULL,   /* fpAddForm */
2386         NULL,   /* fpDeleteForm */
2387         NULL,   /* fpGetForm */
2388         NULL,   /* fpSetForm */
2389         NULL,   /* fpEnumForms */
2390         fpEnumMonitors,
2391         fpEnumPorts,
2392         fpAddPort,
2393         fpConfigurePort,
2394         fpDeletePort,
2395         NULL,   /* fpCreatePrinterIC */
2396         NULL,   /* fpPlayGdiScriptOnPrinterIC */
2397         NULL,   /* fpDeletePrinterIC */
2398         NULL,   /* fpAddPrinterConnection */
2399         NULL,   /* fpDeletePrinterConnection */
2400         NULL,   /* fpPrinterMessageBox */
2401         fpAddMonitor,
2402         fpDeleteMonitor,
2403         NULL,   /* fpResetPrinter */
2404         NULL,   /* fpGetPrinterDriverEx */
2405         NULL,   /* fpFindFirstPrinterChangeNotification */
2406         NULL,   /* fpFindClosePrinterChangeNotification */
2407         fpAddPortEx,
2408         NULL,   /* fpShutDown */
2409         NULL,   /* fpRefreshPrinterChangeNotification */
2410         NULL,   /* fpOpenPrinterEx */
2411         NULL,   /* fpAddPrinterEx */
2412         NULL,   /* fpSetPort */
2413         NULL,   /* fpEnumPrinterData */
2414         NULL,   /* fpDeletePrinterData */
2415         NULL,   /* fpClusterSplOpen */
2416         NULL,   /* fpClusterSplClose */
2417         NULL,   /* fpClusterSplIsAlive */
2418         NULL,   /* fpSetPrinterDataEx */
2419         NULL,   /* fpGetPrinterDataEx */
2420         NULL,   /* fpEnumPrinterDataEx */
2421         NULL,   /* fpEnumPrinterKey */
2422         NULL,   /* fpDeletePrinterDataEx */
2423         NULL,   /* fpDeletePrinterKey */
2424         NULL,   /* fpSeekPrinter */
2425         NULL,   /* fpDeletePrinterDriverEx */
2426         NULL,   /* fpAddPerMachineConnection */
2427         NULL,   /* fpDeletePerMachineConnection */
2428         NULL,   /* fpEnumPerMachineConnections */
2429         fpXcvData,
2430         fpAddPrinterDriverEx,
2431         NULL,   /* fpSplReadPrinter */
2432         NULL,   /* fpDriverUnloadComplete */
2433         NULL,   /* fpGetSpoolFileInfo */
2434         NULL,   /* fpCommitSpoolData */
2435         NULL,   /* fpCloseSpoolFileHandle */
2436         NULL,   /* fpFlushPrinter */
2437         NULL,   /* fpSendRecvBidiData */
2438         NULL    /* fpAddDriverCatalog */
2439     };
2440     pprovider = &backend;
2441
2442 }
2443
2444 /*****************************************************
2445  * InitializePrintProvidor     (localspl.@)
2446  *
2447  * Initialize the Printprovider
2448  *
2449  * PARAMS
2450  *  pPrintProvidor    [I] Buffer to fill with a struct PRINTPROVIDOR
2451  *  cbPrintProvidor   [I] Size of Buffer in Bytes
2452  *  pFullRegistryPath [I] Registry-Path for the Printprovidor
2453  *
2454  * RETURNS
2455  *  Success: TRUE and pPrintProvidor filled
2456  *  Failure: FALSE
2457  *
2458  * NOTES
2459  *  The RegistryPath should be:
2460  *  "System\CurrentControlSet\Control\Print\Providers\<providername>",
2461  *  but this Parameter is ignored in "localspl.dll".
2462  *
2463  */
2464
2465 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2466                                     DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2467 {
2468
2469     TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2470     memcpy(pPrintProvidor, pprovider,
2471           (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2472
2473     return TRUE;
2474 }