atl80: Added AtlComModuleRegisterServer implementation (based on AtlModuleRegisterSer...
[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 spoolW[] = {'\\','s','p','o','o','l',0};
144 static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
145 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
146 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
147 static const WCHAR version0_subdirW[] = {'\\','0',0};
148 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
149 static const WCHAR version3_subdirW[] = {'\\','3',0};
150 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
151 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
152 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
153 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
154                                         'M','i','c','r','o','s','o','f','t','\\',
155                                         'W','i','n','d','o','w','s',' ','N','T','\\',
156                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157                                         'P','o','r','t','s',0};
158 static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
159 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
160 static const WCHAR x64_subdirW[] = {'x','6','4',0};
161 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
162 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
163 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
164 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
165
166
167 static const printenv_t env_ia64 =  {ia64_envnameW, ia64_subdirW, 3,
168                                      version3_regpathW, version3_subdirW};
169
170 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
171                                      version3_regpathW, version3_subdirW};
172
173 static const printenv_t env_x64 =   {x64_envnameW, x64_subdirW, 3,
174                                      version3_regpathW, version3_subdirW};
175
176 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
177                                      version0_regpathW, version0_subdirW};
178
179 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
180
181
182 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
183                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
184                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
185                                   0, sizeof(DRIVER_INFO_8W)};
186
187
188 /******************************************************************
189  * strdupW [internal]
190  *
191  * create a copy of a unicode-string
192  *
193  */
194 static LPWSTR strdupW(LPCWSTR p)
195 {
196     LPWSTR ret;
197     DWORD len;
198
199     if(!p) return NULL;
200     len = (lstrlenW(p) + 1) * sizeof(WCHAR);
201     ret = heap_alloc(len);
202     if (ret) memcpy(ret, p, len);
203     return ret;
204 }
205
206 /******************************************************************
207  *  apd_copyfile [internal]
208  *
209  * Copy a file from the driverdirectory to the versioned directory
210  *
211  * RETURNS
212  *  Success: TRUE
213  *  Failure: FALSE
214  *
215  */
216 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
217 {
218     WCHAR *srcname;
219     DWORD res;
220
221     apd->src[apd->srclen] = '\0';
222     apd->dst[apd->dstlen] = '\0';
223
224     if (!pathname || !pathname[0]) {
225         /* nothing to copy */
226         return TRUE;
227     }
228
229     if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
230         srcname = pathname;
231     else
232     {
233         srcname = apd->src;
234         strcatW( srcname, file_part );
235     }
236     strcatW( apd->dst, file_part );
237
238     TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
239
240     /* FIXME: handle APD_COPY_NEW_FILES */
241     res = CopyFileW(srcname, apd->dst, FALSE);
242     TRACE("got %u with %u\n", res, GetLastError());
243
244     return (apd->lazy) ? TRUE : res;
245 }
246
247 /******************************************************************
248  * copy_servername_from_name  (internal)
249  *
250  * for an external server, the serverpart from the name is copied.
251  *
252  * RETURNS
253  *  the length (in WCHAR) of the serverpart (0 for the local computer)
254  *  (-length), when the name is to long
255  *
256  */
257 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
258 {
259     LPCWSTR server;
260     LPWSTR  ptr;
261     WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
262     DWORD   len;
263     DWORD   serverlen;
264
265     if (target) *target = '\0';
266
267     if (name == NULL) return 0;
268     if ((name[0] != '\\') || (name[1] != '\\')) return 0;
269
270     server = &name[2];
271     /* skip over both backslash, find separator '\' */
272     ptr = strchrW(server, '\\');
273     serverlen = (ptr) ? ptr - server : lstrlenW(server);
274
275     /* servername is empty */
276     if (serverlen == 0) return 0;
277
278     TRACE("found %s\n", debugstr_wn(server, serverlen));
279
280     if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
281
282     if (target) {
283         memcpy(target, server, serverlen * sizeof(WCHAR));
284         target[serverlen] = '\0';
285     }
286
287     len = sizeof(buffer) / sizeof(buffer[0]);
288     if (GetComputerNameW(buffer, &len)) {
289         if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
290             /* The requested Servername is our computername */
291             return 0;
292         }
293     }
294     return serverlen;
295 }
296
297 /******************************************************************
298  * get_basename_from_name  (internal)
299  *
300  * skip over the serverpart from the full name
301  *
302  */
303 static LPCWSTR get_basename_from_name(LPCWSTR name)
304 {
305     if (name == NULL)  return NULL;
306     if ((name[0] == '\\') && (name[1] == '\\')) {
307         /* skip over the servername and search for the following '\'  */
308         name = strchrW(&name[2], '\\');
309         if ((name) && (name[1])) {
310             /* found a separator ('\') followed by a name:
311                skip over the separator and return the rest */
312             name++;
313         }
314         else
315         {
316             /* no basename present (we found only a servername) */
317             return NULL;
318         }
319     }
320     return name;
321 }
322
323 /******************************************************************
324  * monitor_unload [internal]
325  *
326  * release a printmonitor and unload it from memory, when needed
327  *
328  */
329 static void monitor_unload(monitor_t * pm)
330 {
331     if (pm == NULL) return;
332     TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
333
334     EnterCriticalSection(&monitor_handles_cs);
335
336     if (pm->refcount) pm->refcount--;
337
338     if (pm->refcount == 0) {
339         list_remove(&pm->entry);
340         FreeLibrary(pm->hdll);
341         heap_free(pm->name);
342         heap_free(pm->dllname);
343         heap_free(pm);
344     }
345     LeaveCriticalSection(&monitor_handles_cs);
346 }
347
348 /******************************************************************
349  * monitor_unloadall [internal]
350  *
351  * release all registered printmonitors and unload them from memory, when needed
352  *
353  */
354
355 static void monitor_unloadall(void)
356 {
357     monitor_t * pm;
358     monitor_t * next;
359
360     EnterCriticalSection(&monitor_handles_cs);
361     /* iterate through the list, with safety against removal */
362     LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
363     {
364         /* skip monitorui dlls */
365         if (pm->monitor) monitor_unload(pm);
366     }
367     LeaveCriticalSection(&monitor_handles_cs);
368 }
369
370 /******************************************************************
371  * monitor_load [internal]
372  *
373  * load a printmonitor, get the dllname from the registry, when needed
374  * initialize the monitor and dump found function-pointers
375  *
376  * On failure, SetLastError() is called and NULL is returned
377  */
378
379 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
380 {
381     LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
382     PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
383     LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
384     DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
385     DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
386
387     monitor_t * pm = NULL;
388     monitor_t * cursor;
389     LPWSTR  regroot = NULL;
390     LPWSTR  driver = dllname;
391
392     TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
393     /* Is the Monitor already loaded? */
394     EnterCriticalSection(&monitor_handles_cs);
395
396     if (name) {
397         LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
398         {
399             if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
400                 pm = cursor;
401                 break;
402             }
403         }
404     }
405
406     if (pm == NULL) {
407         pm = heap_alloc_zero(sizeof(monitor_t));
408         if (pm == NULL) goto cleanup;
409         list_add_tail(&monitor_handles, &pm->entry);
410     }
411     pm->refcount++;
412
413     if (pm->name == NULL) {
414         /* Load the monitor */
415         LPMONITOREX pmonitorEx;
416         DWORD   len;
417
418         if (name) {
419             len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
420             regroot = heap_alloc(len * sizeof(WCHAR));
421         }
422
423         if (regroot) {
424             lstrcpyW(regroot, monitorsW);
425             lstrcatW(regroot, name);
426             /* Get the Driver from the Registry */
427             if (driver == NULL) {
428                 HKEY    hroot;
429                 DWORD   namesize;
430                 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
431                     if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
432                                         &namesize) == ERROR_SUCCESS) {
433                         driver = heap_alloc(namesize);
434                         RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
435                     }
436                     RegCloseKey(hroot);
437                 }
438             }
439         }
440
441         pm->name = strdupW(name);
442         pm->dllname = strdupW(driver);
443
444         if ((name && (!regroot || !pm->name)) || !pm->dllname) {
445             monitor_unload(pm);
446             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
447             pm = NULL;
448             goto cleanup;
449         }
450
451         pm->hdll = LoadLibraryW(driver);
452         TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
453
454         if (pm->hdll == NULL) {
455             monitor_unload(pm);
456             SetLastError(ERROR_MOD_NOT_FOUND);
457             pm = NULL;
458             goto cleanup;
459         }
460
461         pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
462         pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
463         pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
464         pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
465         pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
466
467
468         TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
469         TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
470         TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
471         TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
472         TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
473
474         if (pInitializePrintMonitorUI  != NULL) {
475             pm->monitorUI = pInitializePrintMonitorUI();
476             TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
477             if (pm->monitorUI) {
478                 TRACE("0x%08x: dwMonitorSize (%d)\n",
479                         pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
480
481             }
482         }
483
484         if (pInitializePrintMonitor && regroot) {
485             pmonitorEx = pInitializePrintMonitor(regroot);
486             TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
487                     pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
488
489             if (pmonitorEx) {
490                 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
491                 pm->monitor = &(pmonitorEx->Monitor);
492             }
493         }
494
495         if (pm->monitor) {
496             TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
497
498         }
499
500         if (!pm->monitor && regroot) {
501             if (pInitializePrintMonitor2 != NULL) {
502                 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
503             }
504             if (pInitializeMonitorEx != NULL) {
505                 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
506             }
507             if (pInitializeMonitor != NULL) {
508                 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
509             }
510         }
511         if (!pm->monitor && !pm->monitorUI) {
512             monitor_unload(pm);
513             SetLastError(ERROR_PROC_NOT_FOUND);
514             pm = NULL;
515         }
516     }
517 cleanup:
518     if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
519         pm->refcount++;
520         pm_localport = pm;
521     }
522     LeaveCriticalSection(&monitor_handles_cs);
523     if (driver != dllname) heap_free(driver);
524     heap_free(regroot);
525     TRACE("=> %p\n", pm);
526     return pm;
527 }
528
529 /******************************************************************
530  * monitor_loadall [internal]
531  *
532  * Load all registered monitors
533  *
534  */
535 static DWORD monitor_loadall(void)
536 {
537     monitor_t * pm;
538     DWORD   registered = 0;
539     DWORD   loaded = 0;
540     HKEY    hmonitors;
541     WCHAR   buffer[MAX_PATH];
542     DWORD   id = 0;
543
544     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
545         RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
546                         NULL, NULL, NULL, NULL, NULL);
547
548         TRACE("%d monitors registered\n", registered);
549
550         while (id < registered) {
551             buffer[0] = '\0';
552             RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
553             pm = monitor_load(buffer, NULL);
554             if (pm) loaded++;
555             id++;
556         }
557         RegCloseKey(hmonitors);
558     }
559     TRACE("%d monitors loaded\n", loaded);
560     return loaded;
561 }
562
563 /******************************************************************
564  * monitor_loadui [internal]
565  *
566  * load the userinterface-dll for a given portmonitor
567  *
568  * On failure, NULL is returned
569  */
570 static monitor_t * monitor_loadui(monitor_t * pm)
571 {
572     monitor_t * pui = NULL;
573     WCHAR   buffer[MAX_PATH];
574     HANDLE  hXcv;
575     DWORD   len;
576     DWORD   res;
577
578     if (pm == NULL) return NULL;
579     TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
580
581     /* Try the Portmonitor first; works for many monitors */
582     if (pm->monitorUI) {
583         EnterCriticalSection(&monitor_handles_cs);
584         pm->refcount++;
585         LeaveCriticalSection(&monitor_handles_cs);
586         return pm;
587     }
588
589     /* query the userinterface-dllname from the Portmonitor */
590     if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
591         /* building (",XcvMonitor %s",pm->name) not needed yet */
592         res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
593         TRACE("got %u with %p\n", res, hXcv);
594         if (res) {
595             res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
596             TRACE("got %u with %s\n", res, debugstr_w(buffer));
597             if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
598             pm->monitor->pfnXcvClosePort(hXcv);
599         }
600     }
601     return pui;
602 }
603
604 /******************************************************************
605  * monitor_load_by_port [internal]
606  *
607  * load a printmonitor for a given port
608  *
609  * On failure, NULL is returned
610  */
611
612 static monitor_t * monitor_load_by_port(LPCWSTR portname)
613 {
614     HKEY    hroot;
615     HKEY    hport;
616     LPWSTR  buffer;
617     monitor_t * pm = NULL;
618     DWORD   registered = 0;
619     DWORD   id = 0;
620     DWORD   len;
621
622     TRACE("(%s)\n", debugstr_w(portname));
623
624     /* Try the Local Monitor first */
625     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
626         if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
627             /* found the portname */
628             RegCloseKey(hroot);
629             return monitor_load(localportW, NULL);
630         }
631         RegCloseKey(hroot);
632     }
633
634     len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
635     buffer = heap_alloc(len * sizeof(WCHAR));
636     if (buffer == NULL) return NULL;
637
638     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
639         EnterCriticalSection(&monitor_handles_cs);
640         RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
641
642         while ((pm == NULL) && (id < registered)) {
643             buffer[0] = '\0';
644             RegEnumKeyW(hroot, id, buffer, MAX_PATH);
645             TRACE("testing %s\n", debugstr_w(buffer));
646             len = lstrlenW(buffer);
647             lstrcatW(buffer, bs_ports_bsW);
648             lstrcatW(buffer, portname);
649             if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
650                 RegCloseKey(hport);
651                 buffer[len] = '\0';             /* use only the Monitor-Name */
652                 pm = monitor_load(buffer, NULL);
653             }
654             id++;
655         }
656         LeaveCriticalSection(&monitor_handles_cs);
657         RegCloseKey(hroot);
658     }
659     heap_free(buffer);
660     return pm;
661 }
662
663 /******************************************************************
664  * Return the number of bytes for an multi_sz string.
665  * The result includes all \0s
666  * (specifically the extra \0, that is needed as multi_sz terminator).
667  */
668 static int multi_sz_lenW(const WCHAR *str)
669 {
670     const WCHAR *ptr = str;
671     if (!str) return 0;
672     do
673     {
674         ptr += lstrlenW(ptr) + 1;
675     } while (*ptr);
676
677     return (ptr - str + 1) * sizeof(WCHAR);
678 }
679
680 /******************************************************************
681  * validate_envW [internal]
682  *
683  * validate the user-supplied printing-environment
684  *
685  * PARAMS
686  *  env  [I] PTR to Environment-String or NULL
687  *
688  * RETURNS
689  *  Success:  PTR to printenv_t
690  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
691  *
692  * NOTES
693  *  An empty string is handled the same way as NULL.
694  *
695  */
696
697 static const  printenv_t * validate_envW(LPCWSTR env)
698 {
699     const printenv_t *result = NULL;
700     unsigned int i;
701
702     TRACE("(%s)\n", debugstr_w(env));
703     if (env && env[0])
704     {
705         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
706         {
707             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
708             {
709                 result = all_printenv[i];
710                 break;
711             }
712         }
713         if (result == NULL) {
714             FIXME("unsupported Environment: %s\n", debugstr_w(env));
715             SetLastError(ERROR_INVALID_ENVIRONMENT);
716         }
717         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
718     }
719     else
720     {
721         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
722     }
723
724     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
725     return result;
726 }
727
728 /*****************************************************************************
729  * enumerate the local monitors (INTERNAL)
730  *
731  * returns the needed size (in bytes) for pMonitors
732  * and  *lpreturned is set to number of entries returned in pMonitors
733  *
734  * Language-Monitors are also installed in the same Registry-Location but
735  * they are filtered in Windows (not returned by EnumMonitors).
736  * We do no filtering to simplify our Code.
737  *
738  */
739 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
740 {
741     HKEY    hroot = NULL;
742     HKEY    hentry = NULL;
743     LPWSTR  ptr;
744     LPMONITOR_INFO_2W mi;
745     WCHAR   buffer[MAX_PATH];
746     WCHAR   dllname[MAX_PATH];
747     DWORD   dllsize;
748     DWORD   len;
749     DWORD   index = 0;
750     DWORD   needed = 0;
751     DWORD   numentries;
752     DWORD   entrysize;
753
754     entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
755
756     numentries = *lpreturned;       /* this is 0, when we scan the registry */
757     len = entrysize * numentries;
758     ptr = (LPWSTR) &pMonitors[len];
759
760     numentries = 0;
761     len = sizeof(buffer)/sizeof(buffer[0]);
762     buffer[0] = '\0';
763
764     /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
765     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
766         /* Scan all Monitor-Registry-Keys */
767         while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
768             TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
769             dllsize = sizeof(dllname);
770             dllname[0] = '\0';
771
772             /* The Monitor must have a Driver-DLL */
773             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
774                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
775                     /* We found a valid DLL for this Monitor. */
776                     TRACE("using Driver: %s\n", debugstr_w(dllname));
777                 }
778                 RegCloseKey(hentry);
779             }
780
781             /* Windows returns only Port-Monitors here, but to simplify our code,
782                we do no filtering for Language-Monitors */
783             if (dllname[0]) {
784                 numentries++;
785                 needed += entrysize;
786                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
787                 if (level > 1) {
788                     /* we install and return only monitors for "Windows NT x86" */
789                     needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
790                     needed += dllsize;
791                 }
792
793                 /* required size is calculated. Now fill the user-buffer */
794                 if (pMonitors && (cbBuf >= needed)){
795                     mi = (LPMONITOR_INFO_2W) pMonitors;
796                     pMonitors += entrysize;
797
798                     TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
799                     mi->pName = ptr;
800                     lstrcpyW(ptr, buffer);      /* Name of the Monitor */
801                     ptr += (len+1);               /* len is lstrlenW(monitorname) */
802                     if (level > 1) {
803                         mi->pEnvironment = ptr;
804                         lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
805                         ptr += (lstrlenW(x86_envnameW)+1);
806
807                         mi->pDLLName = ptr;
808                         lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
809                         ptr += (dllsize / sizeof(WCHAR));
810                     }
811                 }
812             }
813             index++;
814             len = sizeof(buffer)/sizeof(buffer[0]);
815             buffer[0] = '\0';
816         }
817         RegCloseKey(hroot);
818     }
819     *lpreturned = numentries;
820     TRACE("need %d byte for %d entries\n", needed, numentries);
821     return needed;
822 }
823
824 /*****************************************************************************
825  * enumerate the local print processors (INTERNAL)
826  *
827  * returns the needed size (in bytes) for pPPInfo
828  * and  *lpreturned is set to number of entries returned in pPPInfo
829  *
830  */
831 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
832 {
833     HKEY    hroot = NULL;
834     HKEY    hentry = NULL;
835     LPWSTR  ptr;
836     PPRINTPROCESSOR_INFO_1W ppi;
837     WCHAR   buffer[MAX_PATH];
838     WCHAR   dllname[MAX_PATH];
839     DWORD   dllsize;
840     DWORD   len;
841     DWORD   index = 0;
842     DWORD   needed = 0;
843     DWORD   numentries;
844
845     numentries = *lpreturned;       /* this is 0, when we scan the registry */
846     len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
847     ptr = (LPWSTR) &pPPInfo[len];
848
849     numentries = 0;
850     len = sizeof(buffer)/sizeof(buffer[0]);
851     buffer[0] = '\0';
852
853     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
854         /* add "winprint" first */
855         numentries++;
856         needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
857         if (pPPInfo && (cbBuf >= needed)){
858             ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
859             pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
860
861             TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
862             ppi->pName = ptr;
863             lstrcpyW(ptr, winprintW);      /* Name of the Print Processor */
864             ptr += sizeof(winprintW) / sizeof(WCHAR);
865         }
866
867         /* Scan all Printprocessor Keys */
868         while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
869             (lstrcmpiW(buffer, winprintW) != 0)) {
870             TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
871             dllsize = sizeof(dllname);
872             dllname[0] = '\0';
873
874             /* The Print Processor must have a Driver-DLL */
875             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
876                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
877                     /* We found a valid DLL for this Print Processor */
878                     TRACE("using Driver: %s\n", debugstr_w(dllname));
879                 }
880                 RegCloseKey(hentry);
881             }
882
883             if (dllname[0]) {
884                 numentries++;
885                 needed += sizeof(PRINTPROCESSOR_INFO_1W);
886                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(printprocessor name) */
887
888                 /* required size is calculated. Now fill the user-buffer */
889                 if (pPPInfo && (cbBuf >= needed)){
890                     ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
891                     pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
892
893                     TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
894                     ppi->pName = ptr;
895                     lstrcpyW(ptr, buffer);      /* Name of the Print Processor */
896                     ptr += (len+1);             /* len is lstrlenW(printprosessor name) */
897                 }
898             }
899             index++;
900             len = sizeof(buffer)/sizeof(buffer[0]);
901             buffer[0] = '\0';
902         }
903         RegCloseKey(hroot);
904     }
905     *lpreturned = numentries;
906     TRACE("need %d byte for %d entries\n", needed, numentries);
907     return needed;
908 }
909
910 /******************************************************************
911  * enumerate the local Ports from all loaded monitors (internal)
912  *
913  * returns the needed size (in bytes) for pPorts
914  * and  *lpreturned is set to number of entries returned in pPorts
915  *
916  */
917 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
918 {
919     monitor_t * pm;
920     LPWSTR      ptr;
921     LPPORT_INFO_2W cache;
922     LPPORT_INFO_2W out;
923     LPBYTE  pi_buffer = NULL;
924     DWORD   pi_allocated = 0;
925     DWORD   pi_needed;
926     DWORD   pi_index;
927     DWORD   pi_returned;
928     DWORD   res;
929     DWORD   outindex = 0;
930     DWORD   needed;
931     DWORD   numentries;
932     DWORD   entrysize;
933
934
935     TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
936     entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
937
938     numentries = *lpreturned;       /* this is 0, when we scan the registry */
939     needed = entrysize * numentries;
940     ptr = (LPWSTR) &pPorts[needed];
941
942     numentries = 0;
943     needed = 0;
944
945     LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
946     {
947         if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
948             pi_needed = 0;
949             pi_returned = 0;
950             res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
951             if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
952                 /* Do not use heap_realloc (we do not need the old data in the buffer) */
953                 heap_free(pi_buffer);
954                 pi_buffer = heap_alloc(pi_needed);
955                 pi_allocated = (pi_buffer) ? pi_needed : 0;
956                 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
957             }
958             TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
959                   debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
960
961             numentries += pi_returned;
962             needed += pi_needed;
963
964             /* fill the output-buffer (pPorts), if we have one */
965             if (pPorts && (cbBuf >= needed ) && pi_buffer) {
966                 pi_index = 0;
967                 while (pi_returned > pi_index) {
968                     cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
969                     out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
970                     out->pPortName = ptr;
971                     lstrcpyW(ptr, cache->pPortName);
972                     ptr += (lstrlenW(ptr)+1);
973                     if (level > 1) {
974                         out->pMonitorName = ptr;
975                         lstrcpyW(ptr,  cache->pMonitorName);
976                         ptr += (lstrlenW(ptr)+1);
977
978                         out->pDescription = ptr;
979                         lstrcpyW(ptr,  cache->pDescription);
980                         ptr += (lstrlenW(ptr)+1);
981                         out->fPortType = cache->fPortType;
982                         out->Reserved = cache->Reserved;
983                     }
984                     pi_index++;
985                     outindex++;
986                 }
987             }
988         }
989     }
990     /* the temporary portinfo-buffer is no longer needed */
991     heap_free(pi_buffer);
992
993     *lpreturned = numentries;
994     TRACE("need %d byte for %d entries\n", needed, numentries);
995     return needed;
996 }
997
998
999 /*****************************************************************************
1000  * open_driver_reg [internal]
1001  *
1002  * opens the registry for the printer drivers depending on the given input
1003  * variable pEnvironment
1004  *
1005  * RETURNS:
1006  *    Success: the opened hkey
1007  *    Failure: NULL
1008  */
1009 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1010 {
1011     HKEY  retval = NULL;
1012     LPWSTR buffer;
1013     const printenv_t * env;
1014
1015     TRACE("(%s)\n", debugstr_w(pEnvironment));
1016
1017     env = validate_envW(pEnvironment);
1018     if (!env) return NULL;
1019
1020     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1021                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1022
1023     if (buffer) {
1024         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1025         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1026         HeapFree(GetProcessHeap(), 0, buffer);
1027     }
1028     return retval;
1029 }
1030
1031 /*****************************************************************************
1032  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1033  *
1034  * Return the PATH for the Printer-Drivers
1035  *
1036  * PARAMS
1037  *   pName            [I] Servername (NT only) or NULL (local Computer)
1038  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
1039  *   Level            [I] Structure-Level (must be 1)
1040  *   pDriverDirectory [O] PTR to Buffer that receives the Result
1041  *   cbBuf            [I] Size of Buffer at pDriverDirectory
1042  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
1043  *                        required for pDriverDirectory
1044  *
1045  * RETURNS
1046  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
1047  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1048  *            if cbBuf is too small
1049  *
1050  *   Native Values returned in pDriverDirectory on Success:
1051  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
1052  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
1053  *|  win9x(Windows 4.0):  "%winsysdir%"
1054  *
1055  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
1056  *
1057  */
1058 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1059             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1060 {
1061     DWORD needed;
1062     const printenv_t * env;
1063     WCHAR * const dir = (WCHAR *)pDriverDirectory;
1064
1065     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1066           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1067
1068     if (pName != NULL && pName[0]) {
1069         FIXME("server %s not supported\n", debugstr_w(pName));
1070         SetLastError(ERROR_INVALID_PARAMETER);
1071         return FALSE;
1072     }
1073
1074     env = validate_envW(pEnvironment);
1075     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
1076
1077
1078     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1079     needed = GetSystemDirectoryW(NULL, 0);
1080     /* add the Size for the Subdirectories */
1081     needed += lstrlenW(spoolW);
1082     needed += lstrlenW(driversW);
1083     needed += lstrlenW(env->subdir);
1084     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
1085
1086     *pcbNeeded = needed;
1087
1088     if (needed > cbBuf) {
1089         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1090         return FALSE;
1091     }
1092
1093     if (dir == NULL) {
1094         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1095         SetLastError(ERROR_INVALID_USER_BUFFER);
1096         return FALSE;
1097     }
1098
1099     GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
1100     /* add the Subdirectories */
1101     lstrcatW( dir, spoolW );
1102     CreateDirectoryW( dir, NULL );
1103     lstrcatW( dir, driversW );
1104     CreateDirectoryW( dir, NULL );
1105     lstrcatW( dir, env->subdir );
1106     CreateDirectoryW( dir, NULL );
1107
1108     TRACE( "=> %s\n", debugstr_w( dir ) );
1109     return TRUE;
1110 }
1111
1112 /******************************************************************
1113  * driver_load [internal]
1114  *
1115  * load a driver user interface dll
1116  *
1117  * On failure, NULL is returned
1118  *
1119  */
1120
1121 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1122 {
1123     WCHAR fullname[MAX_PATH];
1124     HMODULE hui;
1125     DWORD len;
1126
1127     TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1128
1129     /* build the driverdir */
1130     len = sizeof(fullname) -
1131           (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1132
1133     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1134                                      (LPBYTE) fullname, len, &len)) {
1135         /* Should never Fail */
1136         SetLastError(ERROR_BUFFER_OVERFLOW);
1137         return NULL;
1138     }
1139
1140     lstrcatW(fullname, env->versionsubdir);
1141     lstrcatW(fullname, backslashW);
1142     lstrcatW(fullname, dllname);
1143
1144     hui = LoadLibraryW(fullname);
1145     TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1146
1147     return hui;
1148 }
1149
1150 /******************************************************************
1151  *  printer_free
1152  *  free the data pointer of an opened printer
1153  */
1154 static VOID printer_free(printer_t * printer)
1155 {
1156     if (printer->hXcv)
1157         printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1158
1159     monitor_unload(printer->pm);
1160
1161     heap_free(printer->printername);
1162     heap_free(printer->name);
1163     heap_free(printer);
1164 }
1165
1166 /******************************************************************
1167  *  printer_alloc_handle
1168  *  alloc a printer handle and remember the data pointer in the printer handle table
1169  *
1170  */
1171 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1172 {
1173     WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1174     printer_t *printer = NULL;
1175     LPCWSTR printername;
1176     HKEY    hkeyPrinters;
1177     HKEY    hkeyPrinter;
1178     DWORD   len;
1179
1180     if (copy_servername_from_name(name, servername)) {
1181         FIXME("server %s not supported\n", debugstr_w(servername));
1182         SetLastError(ERROR_INVALID_PRINTER_NAME);
1183         return NULL;
1184     }
1185
1186     printername = get_basename_from_name(name);
1187     if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1188
1189     /* an empty printername is invalid */
1190     if (printername && (!printername[0])) {
1191         SetLastError(ERROR_INVALID_PARAMETER);
1192         return NULL;
1193     }
1194
1195     printer = heap_alloc_zero(sizeof(printer_t));
1196     if (!printer) goto end;
1197
1198     /* clone the base name. This is NULL for the printserver */
1199     printer->printername = strdupW(printername);
1200
1201     /* clone the full name */
1202     printer->name = strdupW(name);
1203     if (name && (!printer->name)) {
1204         printer_free(printer);
1205         printer = NULL;
1206     }
1207     if (printername) {
1208         len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1209         if (strncmpW(printername, XcvMonitorW, len) == 0) {
1210             /* OpenPrinter(",XcvMonitor ", ...) detected */
1211             TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1212             printer->pm = monitor_load(&printername[len], NULL);
1213             if (printer->pm == NULL) {
1214                 printer_free(printer);
1215                 SetLastError(ERROR_UNKNOWN_PORT);
1216                 printer = NULL;
1217                 goto end;
1218             }
1219         }
1220         else
1221         {
1222             len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1223             if (strncmpW( printername, XcvPortW, len) == 0) {
1224                 /* OpenPrinter(",XcvPort ", ...) detected */
1225                 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1226                 printer->pm = monitor_load_by_port(&printername[len]);
1227                 if (printer->pm == NULL) {
1228                     printer_free(printer);
1229                     SetLastError(ERROR_UNKNOWN_PORT);
1230                     printer = NULL;
1231                     goto end;
1232                 }
1233             }
1234         }
1235
1236         if (printer->pm) {
1237             if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1238                 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1239                                                     pDefault ? pDefault->DesiredAccess : 0,
1240                                                     &printer->hXcv);
1241             }
1242             if (printer->hXcv == NULL) {
1243                 printer_free(printer);
1244                 SetLastError(ERROR_INVALID_PARAMETER);
1245                 printer = NULL;
1246                 goto end;
1247             }
1248         }
1249         else
1250         {
1251             /* Does the Printer exist? */
1252             if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1253                 ERR("Can't create Printers key\n");
1254                 printer_free(printer);
1255                 SetLastError(ERROR_INVALID_PRINTER_NAME);
1256                 printer = NULL;
1257                 goto end;
1258             }
1259             if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1260                 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1261                 RegCloseKey(hkeyPrinters);
1262                 printer_free(printer);
1263                 SetLastError(ERROR_INVALID_PRINTER_NAME);
1264                 printer = NULL;
1265                 goto end;
1266             }
1267             RegCloseKey(hkeyPrinter);
1268             RegCloseKey(hkeyPrinters);
1269         }
1270     }
1271     else
1272     {
1273         TRACE("using the local printserver\n");
1274     }
1275
1276 end:
1277
1278     TRACE("==> %p\n", printer);
1279     return (HANDLE)printer;
1280 }
1281
1282 static inline WCHAR *get_file_part( WCHAR *name )
1283 {
1284     WCHAR *ptr = strrchrW( name, '\\' );
1285     if (ptr) return ptr + 1;
1286     return name;
1287 }
1288
1289 /******************************************************************************
1290  *  myAddPrinterDriverEx [internal]
1291  *
1292  * Install a Printer Driver with the Option to upgrade / downgrade the Files
1293  * and a special mode with lazy error checking.
1294  *
1295  */
1296 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1297 {
1298     const printenv_t *env;
1299     apd_data_t apd;
1300     DRIVER_INFO_8W di;
1301     BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1302     HMODULE hui;
1303     WCHAR *file;
1304     HKEY    hroot;
1305     HKEY    hdrv;
1306     DWORD   disposition;
1307     DWORD   len;
1308     LONG    lres;
1309     BOOL    res;
1310
1311     /* we need to set all entries in the Registry, independent from the Level of
1312        DRIVER_INFO, that the caller supplied */
1313
1314     ZeroMemory(&di, sizeof(di));
1315     if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1316         memcpy(&di, pDriverInfo, di_sizeof[level]);
1317     }
1318
1319     /* dump the most used infos */
1320     TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1321     TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
1322     TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1323     TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1324     TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1325     TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1326     TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1327     /* dump only the first of the additional Files */
1328     TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1329
1330
1331     /* check environment */
1332     env = validate_envW(di.pEnvironment);
1333     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
1334
1335     /* fill the copy-data / get the driverdir */
1336     len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1337     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1338                                     (LPBYTE) apd.src, len, &len)) {
1339         /* Should never Fail */
1340         return FALSE;
1341     }
1342     memcpy(apd.dst, apd.src, len);
1343     lstrcatW(apd.src, backslashW);
1344     apd.srclen = lstrlenW(apd.src);
1345     lstrcatW(apd.dst, env->versionsubdir);
1346     lstrcatW(apd.dst, backslashW);
1347     apd.dstlen = lstrlenW(apd.dst);
1348     apd.copyflags = dwFileCopyFlags;
1349     apd.lazy = lazy;
1350     CreateDirectoryW(apd.src, NULL);
1351     CreateDirectoryW(apd.dst, NULL);
1352
1353     hroot = open_driver_reg(env->envname);
1354     if (!hroot) {
1355         ERR("Can't create Drivers key\n");
1356         return FALSE;
1357     }
1358
1359     /* Fill the Registry for the Driver */
1360     if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1361                                 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1362                                 &hdrv, &disposition)) != ERROR_SUCCESS) {
1363
1364         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1365         RegCloseKey(hroot);
1366         SetLastError(lres);
1367         return FALSE;
1368     }
1369     RegCloseKey(hroot);
1370
1371     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1372     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1373                    sizeof(DWORD));
1374
1375     file = get_file_part( di.pDriverPath );
1376     RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1377     apd_copyfile( di.pDriverPath, file, &apd );
1378
1379     file = get_file_part( di.pDataFile );
1380     RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1381     apd_copyfile( di.pDataFile, file, &apd );
1382
1383     file = get_file_part( di.pConfigFile );
1384     RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1385     apd_copyfile( di.pConfigFile, file, &apd );
1386
1387     /* settings for level 3 */
1388     if (di.pHelpFile)
1389     {
1390         file = get_file_part( di.pHelpFile );
1391         RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1392         apd_copyfile( di.pHelpFile, file, &apd );
1393     }
1394     else
1395         RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
1396
1397     if (di.pDependentFiles && *di.pDependentFiles)
1398     {
1399         WCHAR *reg, *reg_ptr, *in_ptr;
1400         reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1401
1402         for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += strlenW( in_ptr ) + 1)
1403         {
1404             file = get_file_part( in_ptr );
1405             len = strlenW( file ) + 1;
1406             memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1407             reg_ptr += len;
1408             apd_copyfile( in_ptr, file, &apd );
1409         }
1410         *reg_ptr = 0;
1411
1412         RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1413         HeapFree( GetProcessHeap(), 0, reg );
1414     }
1415     else
1416         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
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 }