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