mshtml: Implement IHTMLCurrentStyle_get_borderTopWidth.
[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 fmt_driversW[] = { 'S','y','s','t','e','m','\\',
107                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
108                                   'c','o','n','t','r','o','l','\\',
109                                   'P','r','i','n','t','\\',
110                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
111                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
112 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
113 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
114 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
115 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
116 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
117 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
118 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
119                                 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
120                                 'C','o','n','t','r','o','l','\\',
121                                 'P','r','i','n','t','\\',
122                                 'M','o','n','i','t','o','r','s','\\',0};
123 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
124 static const WCHAR nameW[] = {'N','a','m','e',0};
125 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
126 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
127 static const WCHAR portW[] = {'P','o','r','t',0};
128 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
129 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
130                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131                                   'C','o','n','t','r','o','l','\\',
132                                   'P','r','i','n','t','\\',
133                                   'P','r','i','n','t','e','r','s',0};
134 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
135 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
136 static const WCHAR version0_subdirW[] = {'\\','0',0};
137 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
138 static const WCHAR version3_subdirW[] = {'\\','3',0};
139 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
140 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
141 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
142 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
143                                         'M','i','c','r','o','s','o','f','t','\\',
144                                         'W','i','n','d','o','w','s',' ','N','T','\\',
145                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
146                                         'P','o','r','t','s',0};
147 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
148 static const WCHAR x64_subdirW[] = {'x','6','4',0};
149 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
150 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
151 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
152 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
153
154
155 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
156                                      version3_regpathW, version3_subdirW};
157
158 static const printenv_t env_x64 =   {x64_envnameW, x64_subdirW, 3,
159                                      version3_regpathW, version3_subdirW};
160
161 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
162                                      version0_regpathW, version0_subdirW};
163
164 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
165
166
167 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
168                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
169                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
170                                   0, sizeof(DRIVER_INFO_8W)};
171
172
173 /******************************************************************
174  * strdupW [internal]
175  *
176  * create a copy of a unicode-string
177  *
178  */
179 static LPWSTR strdupW(LPCWSTR p)
180 {
181     LPWSTR ret;
182     DWORD len;
183
184     if(!p) return NULL;
185     len = (lstrlenW(p) + 1) * sizeof(WCHAR);
186     ret = heap_alloc(len);
187     memcpy(ret, p, len);
188     return ret;
189 }
190
191 /******************************************************************
192  *  apd_copyfile [internal]
193  *
194  * Copy a file from the driverdirectory to the versioned directory
195  *
196  * RETURNS
197  *  Success: TRUE
198  *  Failure: FALSE
199  *
200  */
201 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
202 {
203     LPWSTR  ptr;
204     LPWSTR  srcname;
205     DWORD   res;
206
207     apd->src[apd->srclen] = '\0';
208     apd->dst[apd->dstlen] = '\0';
209
210     if (!filename || !filename[0]) {
211         /* nothing to copy */
212         return TRUE;
213     }
214
215     ptr = strrchrW(filename, '\\');
216     if (ptr) {
217         ptr++;
218     }
219     else
220     {
221         ptr = filename;
222     }
223
224     if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
225         /* we have an absolute Path */
226         srcname = filename;
227     }
228     else
229     {
230         srcname = apd->src;
231         lstrcatW(srcname, ptr);
232     }
233     lstrcatW(apd->dst, ptr);
234
235     TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
236
237     /* FIXME: handle APD_COPY_NEW_FILES */
238     res = CopyFileW(srcname, apd->dst, FALSE);
239     TRACE("got %u with %u\n", res, GetLastError());
240
241     return (apd->lazy) ? TRUE : res;
242 }
243
244 /******************************************************************
245  * copy_servername_from_name  (internal)
246  *
247  * for an external server, the serverpart from the name is copied.
248  *
249  * RETURNS
250  *  the length (in WCHAR) of the serverpart (0 for the local computer)
251  *  (-length), when the name is to long
252  *
253  */
254 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
255 {
256     LPCWSTR server;
257     LPWSTR  ptr;
258     WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
259     DWORD   len;
260     DWORD   serverlen;
261
262     if (target) *target = '\0';
263
264     if (name == NULL) return 0;
265     if ((name[0] != '\\') || (name[1] != '\\')) return 0;
266
267     server = &name[2];
268     /* skip over both backslash, find separator '\' */
269     ptr = strchrW(server, '\\');
270     serverlen = (ptr) ? ptr - server : lstrlenW(server);
271
272     /* servername is empty */
273     if (serverlen == 0) return 0;
274
275     TRACE("found %s\n", debugstr_wn(server, serverlen));
276
277     if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
278
279     if (target) {
280         memcpy(target, server, serverlen * sizeof(WCHAR));
281         target[serverlen] = '\0';
282     }
283
284     len = sizeof(buffer) / sizeof(buffer[0]);
285     if (GetComputerNameW(buffer, &len)) {
286         if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
287             /* The requested Servername is our computername */
288             return 0;
289         }
290     }
291     return serverlen;
292 }
293
294 /******************************************************************
295  * get_basename_from_name  (internal)
296  *
297  * skip over the serverpart from the full name
298  *
299  */
300 static LPCWSTR get_basename_from_name(LPCWSTR name)
301 {
302     if (name == NULL)  return NULL;
303     if ((name[0] == '\\') && (name[1] == '\\')) {
304         /* skip over the servername and search for the following '\'  */
305         name = strchrW(&name[2], '\\');
306         if ((name) && (name[1])) {
307             /* found a separator ('\') followed by a name:
308                skip over the separator and return the rest */
309             name++;
310         }
311         else
312         {
313             /* no basename present (we found only a servername) */
314             return NULL;
315         }
316     }
317     return name;
318 }
319
320 /******************************************************************
321  * monitor_unload [internal]
322  *
323  * release a printmonitor and unload it from memory, when needed
324  *
325  */
326 static void monitor_unload(monitor_t * pm)
327 {
328     if (pm == NULL) return;
329     TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
330
331     EnterCriticalSection(&monitor_handles_cs);
332
333     if (pm->refcount) pm->refcount--;
334
335     if (pm->refcount == 0) {
336         list_remove(&pm->entry);
337         FreeLibrary(pm->hdll);
338         heap_free(pm->name);
339         heap_free(pm->dllname);
340         heap_free(pm);
341     }
342     LeaveCriticalSection(&monitor_handles_cs);
343 }
344
345 /******************************************************************
346  * monitor_unloadall [internal]
347  *
348  * release all printmonitors and unload them from memory, when needed
349  *
350  */
351
352 static void monitor_unloadall(void)
353 {
354     monitor_t * pm;
355     monitor_t * next;
356
357     EnterCriticalSection(&monitor_handles_cs);
358     /* iterate through the list, with safety against removal */
359     LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
360     {
361         monitor_unload(pm);
362     }
363     LeaveCriticalSection(&monitor_handles_cs);
364 }
365
366 /******************************************************************
367  * monitor_load [internal]
368  *
369  * load a printmonitor, get the dllname from the registry, when needed
370  * initialize the monitor and dump found function-pointers
371  *
372  * On failure, SetLastError() is called and NULL is returned
373  */
374
375 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
376 {
377     LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
378     PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
379     LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
380     DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
381     DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
382
383     monitor_t * pm = NULL;
384     monitor_t * cursor;
385     LPWSTR  regroot = NULL;
386     LPWSTR  driver = dllname;
387
388     TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
389     /* Is the Monitor already loaded? */
390     EnterCriticalSection(&monitor_handles_cs);
391
392     if (name) {
393         LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
394         {
395             if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
396                 pm = cursor;
397                 break;
398             }
399         }
400     }
401
402     if (pm == NULL) {
403         pm = heap_alloc_zero(sizeof(monitor_t));
404         if (pm == NULL) goto cleanup;
405         list_add_tail(&monitor_handles, &pm->entry);
406     }
407     pm->refcount++;
408
409     if (pm->name == NULL) {
410         /* Load the monitor */
411         LPMONITOREX pmonitorEx;
412         DWORD   len;
413
414         if (name) {
415             len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
416             regroot = heap_alloc(len * sizeof(WCHAR));
417         }
418
419         if (regroot) {
420             lstrcpyW(regroot, monitorsW);
421             lstrcatW(regroot, name);
422             /* Get the Driver from the Registry */
423             if (driver == NULL) {
424                 HKEY    hroot;
425                 DWORD   namesize;
426                 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
427                     if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
428                                         &namesize) == ERROR_SUCCESS) {
429                         driver = heap_alloc(namesize);
430                         RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
431                     }
432                     RegCloseKey(hroot);
433                 }
434             }
435         }
436
437         pm->name = strdupW(name);
438         pm->dllname = strdupW(driver);
439
440         if ((name && (!regroot || !pm->name)) || !pm->dllname) {
441             monitor_unload(pm);
442             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
443             pm = NULL;
444             goto cleanup;
445         }
446
447         pm->hdll = LoadLibraryW(driver);
448         TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
449
450         if (pm->hdll == NULL) {
451             monitor_unload(pm);
452             SetLastError(ERROR_MOD_NOT_FOUND);
453             pm = NULL;
454             goto cleanup;
455         }
456
457         pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
458         pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
459         pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
460         pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
461         pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
462
463
464         TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
465         TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
466         TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
467         TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
468         TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
469
470         if (pInitializePrintMonitorUI  != NULL) {
471             pm->monitorUI = pInitializePrintMonitorUI();
472             TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
473             if (pm->monitorUI) {
474                 TRACE("0x%08x: dwMonitorSize (%d)\n",
475                         pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
476
477             }
478         }
479
480         if (pInitializePrintMonitor && regroot) {
481             pmonitorEx = pInitializePrintMonitor(regroot);
482             TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
483                     pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
484
485             if (pmonitorEx) {
486                 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
487                 pm->monitor = &(pmonitorEx->Monitor);
488             }
489         }
490
491         if (pm->monitor) {
492             TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
493
494         }
495
496         if (!pm->monitor && regroot) {
497             if (pInitializePrintMonitor2 != NULL) {
498                 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
499             }
500             if (pInitializeMonitorEx != NULL) {
501                 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
502             }
503             if (pInitializeMonitor != NULL) {
504                 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
505             }
506         }
507         if (!pm->monitor && !pm->monitorUI) {
508             monitor_unload(pm);
509             SetLastError(ERROR_PROC_NOT_FOUND);
510             pm = NULL;
511         }
512     }
513 cleanup:
514     if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
515         pm->refcount++;
516         pm_localport = pm;
517     }
518     LeaveCriticalSection(&monitor_handles_cs);
519     if (driver != dllname) heap_free(driver);
520     heap_free(regroot);
521     TRACE("=> %p\n", pm);
522     return pm;
523 }
524
525 /******************************************************************
526  * monitor_loadall [internal]
527  *
528  * Load all registered monitors
529  *
530  */
531 static DWORD monitor_loadall(void)
532 {
533     monitor_t * pm;
534     DWORD   registered = 0;
535     DWORD   loaded = 0;
536     HKEY    hmonitors;
537     WCHAR   buffer[MAX_PATH];
538     DWORD   id = 0;
539
540     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
541         RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
542                         NULL, NULL, NULL, NULL, NULL);
543
544         TRACE("%d monitors registered\n", registered);
545
546         while (id < registered) {
547             buffer[0] = '\0';
548             RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
549             pm = monitor_load(buffer, NULL);
550             if (pm) loaded++;
551             id++;
552         }
553         RegCloseKey(hmonitors);
554     }
555     TRACE("%d monitors loaded\n", loaded);
556     return loaded;
557 }
558
559 /******************************************************************
560  * monitor_load_by_port [internal]
561  *
562  * load a printmonitor for a given port
563  *
564  * On failure, NULL is returned
565  */
566
567 static monitor_t * monitor_load_by_port(LPCWSTR portname)
568 {
569     HKEY    hroot;
570     HKEY    hport;
571     LPWSTR  buffer;
572     monitor_t * pm = NULL;
573     DWORD   registered = 0;
574     DWORD   id = 0;
575     DWORD   len;
576
577     TRACE("(%s)\n", debugstr_w(portname));
578
579     /* Try the Local Monitor first */
580     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
581         if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
582             /* found the portname */
583             RegCloseKey(hroot);
584             return monitor_load(localportW, NULL);
585         }
586         RegCloseKey(hroot);
587     }
588
589     len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
590     buffer = heap_alloc(len * sizeof(WCHAR));
591     if (buffer == NULL) return NULL;
592
593     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
594         EnterCriticalSection(&monitor_handles_cs);
595         RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
596
597         while ((pm == NULL) && (id < registered)) {
598             buffer[0] = '\0';
599             RegEnumKeyW(hroot, id, buffer, MAX_PATH);
600             TRACE("testing %s\n", debugstr_w(buffer));
601             len = lstrlenW(buffer);
602             lstrcatW(buffer, bs_ports_bsW);
603             lstrcatW(buffer, portname);
604             if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
605                 RegCloseKey(hport);
606                 buffer[len] = '\0';             /* use only the Monitor-Name */
607                 pm = monitor_load(buffer, NULL);
608             }
609             id++;
610         }
611         LeaveCriticalSection(&monitor_handles_cs);
612         RegCloseKey(hroot);
613     }
614     heap_free(buffer);
615     return pm;
616 }
617
618 /******************************************************************
619  * Return the number of bytes for an multi_sz string.
620  * The result includes all \0s
621  * (specifically the extra \0, that is needed as multi_sz terminator).
622  */
623 static int multi_sz_lenW(const WCHAR *str)
624 {
625     const WCHAR *ptr = str;
626     if (!str) return 0;
627     do
628     {
629         ptr += lstrlenW(ptr) + 1;
630     } while (*ptr);
631
632     return (ptr - str + 1) * sizeof(WCHAR);
633 }
634
635 /******************************************************************
636  * validate_envW [internal]
637  *
638  * validate the user-supplied printing-environment
639  *
640  * PARAMS
641  *  env  [I] PTR to Environment-String or NULL
642  *
643  * RETURNS
644  *  Success:  PTR to printenv_t
645  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
646  *
647  * NOTES
648  *  An empty string is handled the same way as NULL.
649  *
650  */
651
652 static const  printenv_t * validate_envW(LPCWSTR env)
653 {
654     const printenv_t *result = NULL;
655     unsigned int i;
656
657     TRACE("(%s)\n", debugstr_w(env));
658     if (env && env[0])
659     {
660         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
661         {
662             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
663             {
664                 result = all_printenv[i];
665                 break;
666             }
667         }
668         if (result == NULL) {
669             FIXME("unsupported Environment: %s\n", debugstr_w(env));
670             SetLastError(ERROR_INVALID_ENVIRONMENT);
671         }
672         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
673     }
674     else
675     {
676         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
677     }
678
679     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
680     return result;
681 }
682
683 /*****************************************************************************
684  * enumerate the local monitors (INTERNAL)
685  *
686  * returns the needed size (in bytes) for pMonitors
687  * and  *lpreturned is set to number of entries returned in pMonitors
688  *
689  * Language-Monitors are also installed in the same Registry-Location but
690  * they are filtered in Windows (not returned by EnumMonitors).
691  * We do no filtering to simplify our Code.
692  *
693  */
694 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
695 {
696     HKEY    hroot = NULL;
697     HKEY    hentry = NULL;
698     LPWSTR  ptr;
699     LPMONITOR_INFO_2W mi;
700     WCHAR   buffer[MAX_PATH];
701     WCHAR   dllname[MAX_PATH];
702     DWORD   dllsize;
703     DWORD   len;
704     DWORD   index = 0;
705     DWORD   needed = 0;
706     DWORD   numentries;
707     DWORD   entrysize;
708
709     entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
710
711     numentries = *lpreturned;       /* this is 0, when we scan the registry */
712     len = entrysize * numentries;
713     ptr = (LPWSTR) &pMonitors[len];
714
715     numentries = 0;
716     len = sizeof(buffer)/sizeof(buffer[0]);
717     buffer[0] = '\0';
718
719     /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
720     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
721         /* Scan all Monitor-Registry-Keys */
722         while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
723             TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
724             dllsize = sizeof(dllname);
725             dllname[0] = '\0';
726
727             /* The Monitor must have a Driver-DLL */
728             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
729                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
730                     /* We found a valid DLL for this Monitor. */
731                     TRACE("using Driver: %s\n", debugstr_w(dllname));
732                 }
733                 RegCloseKey(hentry);
734             }
735
736             /* Windows returns only Port-Monitors here, but to simplify our code,
737                we do no filtering for Language-Monitors */
738             if (dllname[0]) {
739                 numentries++;
740                 needed += entrysize;
741                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
742                 if (level > 1) {
743                     /* we install and return only monitors for "Windows NT x86" */
744                     needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
745                     needed += dllsize;
746                 }
747
748                 /* required size is calculated. Now fill the user-buffer */
749                 if (pMonitors && (cbBuf >= needed)){
750                     mi = (LPMONITOR_INFO_2W) pMonitors;
751                     pMonitors += entrysize;
752
753                     TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
754                     mi->pName = ptr;
755                     lstrcpyW(ptr, buffer);      /* Name of the Monitor */
756                     ptr += (len+1);               /* len is lstrlenW(monitorname) */
757                     if (level > 1) {
758                         mi->pEnvironment = ptr;
759                         lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
760                         ptr += (lstrlenW(x86_envnameW)+1);
761
762                         mi->pDLLName = ptr;
763                         lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
764                         ptr += (dllsize / sizeof(WCHAR));
765                     }
766                 }
767             }
768             index++;
769             len = sizeof(buffer)/sizeof(buffer[0]);
770             buffer[0] = '\0';
771         }
772         RegCloseKey(hroot);
773     }
774     *lpreturned = numentries;
775     TRACE("need %d byte for %d entries\n", needed, numentries);
776     return needed;
777 }
778
779 /******************************************************************
780  * enumerate the local Ports from all loaded monitors (internal)
781  *
782  * returns the needed size (in bytes) for pPorts
783  * and  *lpreturned is set to number of entries returned in pPorts
784  *
785  */
786 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
787 {
788     monitor_t * pm;
789     LPWSTR      ptr;
790     LPPORT_INFO_2W cache;
791     LPPORT_INFO_2W out;
792     LPBYTE  pi_buffer = NULL;
793     DWORD   pi_allocated = 0;
794     DWORD   pi_needed;
795     DWORD   pi_index;
796     DWORD   pi_returned;
797     DWORD   res;
798     DWORD   outindex = 0;
799     DWORD   needed;
800     DWORD   numentries;
801     DWORD   entrysize;
802
803
804     TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
805     entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
806
807     numentries = *lpreturned;       /* this is 0, when we scan the registry */
808     needed = entrysize * numentries;
809     ptr = (LPWSTR) &pPorts[needed];
810
811     numentries = 0;
812     needed = 0;
813
814     LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
815     {
816         if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
817             pi_needed = 0;
818             pi_returned = 0;
819             res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
820             if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
821                 /* Do not use heap_realloc (we do not need the old data in the buffer) */
822                 heap_free(pi_buffer);
823                 pi_buffer = heap_alloc(pi_needed);
824                 pi_allocated = (pi_buffer) ? pi_needed : 0;
825                 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
826             }
827             TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
828                   debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
829
830             numentries += pi_returned;
831             needed += pi_needed;
832
833             /* fill the output-buffer (pPorts), if we have one */
834             if (pPorts && (cbBuf >= needed ) && pi_buffer) {
835                 pi_index = 0;
836                 while (pi_returned > pi_index) {
837                     cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
838                     out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
839                     out->pPortName = ptr;
840                     lstrcpyW(ptr, cache->pPortName);
841                     ptr += (lstrlenW(ptr)+1);
842                     if (level > 1) {
843                         out->pMonitorName = ptr;
844                         lstrcpyW(ptr,  cache->pMonitorName);
845                         ptr += (lstrlenW(ptr)+1);
846
847                         out->pDescription = ptr;
848                         lstrcpyW(ptr,  cache->pDescription);
849                         ptr += (lstrlenW(ptr)+1);
850                         out->fPortType = cache->fPortType;
851                         out->Reserved = cache->Reserved;
852                     }
853                     pi_index++;
854                     outindex++;
855                 }
856             }
857         }
858     }
859     /* the temporary portinfo-buffer is no longer needed */
860     heap_free(pi_buffer);
861
862     *lpreturned = numentries;
863     TRACE("need %d byte for %d entries\n", needed, numentries);
864     return needed;
865 }
866
867
868 /*****************************************************************************
869  * open_driver_reg [internal]
870  *
871  * opens the registry for the printer drivers depending on the given input
872  * variable pEnvironment
873  *
874  * RETURNS:
875  *    Success: the opened hkey
876  *    Failure: NULL
877  */
878 static HKEY open_driver_reg(LPCWSTR pEnvironment)
879 {
880     HKEY  retval = NULL;
881     LPWSTR buffer;
882     const printenv_t * env;
883
884     TRACE("(%s)\n", debugstr_w(pEnvironment));
885
886     env = validate_envW(pEnvironment);
887     if (!env) return NULL;
888
889     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
890                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
891
892     if (buffer) {
893         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
894         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
895         HeapFree(GetProcessHeap(), 0, buffer);
896     }
897     return retval;
898 }
899
900 /*****************************************************************************
901  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
902  *
903  * Return the PATH for the Printer-Drivers
904  *
905  * PARAMS
906  *   pName            [I] Servername (NT only) or NULL (local Computer)
907  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
908  *   Level            [I] Structure-Level (must be 1)
909  *   pDriverDirectory [O] PTR to Buffer that receives the Result
910  *   cbBuf            [I] Size of Buffer at pDriverDirectory
911  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
912  *                        required for pDriverDirectory
913  *
914  * RETURNS
915  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
916  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
917  *            if cbBuf is too small
918  *
919  *   Native Values returned in pDriverDirectory on Success:
920  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
921  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
922  *|  win9x(Windows 4.0):  "%winsysdir%"
923  *
924  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
925  *
926  */
927 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
928             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
929 {
930     DWORD needed;
931     const printenv_t * env;
932
933     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
934           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
935
936     if (pName != NULL && pName[0]) {
937         FIXME("server %s not supported\n", debugstr_w(pName));
938         SetLastError(ERROR_INVALID_PARAMETER);
939         return FALSE;
940     }
941
942     env = validate_envW(pEnvironment);
943     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
944
945
946     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
947     needed = GetSystemDirectoryW(NULL, 0);
948     /* add the Size for the Subdirectories */
949     needed += lstrlenW(spooldriversW);
950     needed += lstrlenW(env->subdir);
951     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
952
953     *pcbNeeded = needed;
954
955     if (needed > cbBuf) {
956         SetLastError(ERROR_INSUFFICIENT_BUFFER);
957         return FALSE;
958     }
959
960     if (pDriverDirectory == NULL) {
961         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
962         SetLastError(ERROR_INVALID_USER_BUFFER);
963         return FALSE;
964     }
965
966     GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
967     /* add the Subdirectories */
968     lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
969     lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
970
971     TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
972     return TRUE;
973 }
974
975 /******************************************************************
976  * driver_load [internal]
977  *
978  * load a driver user interface dll
979  *
980  * On failure, NULL is returned
981  *
982  */
983
984 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
985 {
986     WCHAR fullname[MAX_PATH];
987     HMODULE hui;
988     DWORD len;
989
990     TRACE("(%p, %s)\n", env, debugstr_w(dllname));
991
992     /* build the driverdir */
993     len = sizeof(fullname) -
994           (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
995
996     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
997                                      (LPBYTE) fullname, len, &len)) {
998         /* Should never Fail */
999         SetLastError(ERROR_BUFFER_OVERFLOW);
1000         return NULL;
1001     }
1002
1003     lstrcatW(fullname, env->versionsubdir);
1004     lstrcatW(fullname, backslashW);
1005     lstrcatW(fullname, dllname);
1006
1007     hui = LoadLibraryW(fullname);
1008     TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1009
1010     return hui;
1011 }
1012
1013 /******************************************************************
1014  *  printer_free
1015  *  free the data pointer of an opened printer
1016  */
1017 static VOID printer_free(printer_t * printer)
1018 {
1019     if (printer->hXcv)
1020         printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1021
1022     monitor_unload(printer->pm);
1023
1024     heap_free(printer->printername);
1025     heap_free(printer->name);
1026     heap_free(printer);
1027 }
1028
1029 /******************************************************************
1030  *  printer_alloc_handle
1031  *  alloc a printer handle and remember the data pointer in the printer handle table
1032  *
1033  */
1034 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1035 {
1036     WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1037     printer_t *printer = NULL;
1038     LPCWSTR printername;
1039     HKEY    hkeyPrinters;
1040     HKEY    hkeyPrinter;
1041     DWORD   len;
1042
1043     if (copy_servername_from_name(name, servername)) {
1044         FIXME("server %s not supported\n", debugstr_w(servername));
1045         SetLastError(ERROR_INVALID_PRINTER_NAME);
1046         return NULL;
1047     }
1048
1049     printername = get_basename_from_name(name);
1050     if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1051
1052     /* an empty printername is invalid */
1053     if (printername && (!printername[0])) {
1054         SetLastError(ERROR_INVALID_PARAMETER);
1055         return NULL;
1056     }
1057
1058     printer = heap_alloc_zero(sizeof(printer_t));
1059     if (!printer) goto end;
1060
1061     /* clone the base name. This is NULL for the printserver */
1062     printer->printername = strdupW(printername);
1063
1064     /* clone the full name */
1065     printer->name = strdupW(name);
1066     if (name && (!printer->name)) {
1067         printer_free(printer);
1068         printer = NULL;
1069     }
1070     if (printername) {
1071         len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1072         if (strncmpW(printername, XcvMonitorW, len) == 0) {
1073             /* OpenPrinter(",XcvMonitor ", ...) detected */
1074             TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1075             printer->pm = monitor_load(&printername[len], NULL);
1076             if (printer->pm == NULL) {
1077                 printer_free(printer);
1078                 SetLastError(ERROR_UNKNOWN_PORT);
1079                 printer = NULL;
1080                 goto end;
1081             }
1082         }
1083         else
1084         {
1085             len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1086             if (strncmpW( printername, XcvPortW, len) == 0) {
1087                 /* OpenPrinter(",XcvPort ", ...) detected */
1088                 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1089                 printer->pm = monitor_load_by_port(&printername[len]);
1090                 if (printer->pm == NULL) {
1091                     printer_free(printer);
1092                     SetLastError(ERROR_UNKNOWN_PORT);
1093                     printer = NULL;
1094                     goto end;
1095                 }
1096             }
1097         }
1098
1099         if (printer->pm) {
1100             if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1101                 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1102                                                     pDefault ? pDefault->DesiredAccess : 0,
1103                                                     &printer->hXcv);
1104             }
1105             if (printer->hXcv == NULL) {
1106                 printer_free(printer);
1107                 SetLastError(ERROR_INVALID_PARAMETER);
1108                 printer = NULL;
1109                 goto end;
1110             }
1111         }
1112         else
1113         {
1114             /* Does the Printer exist? */
1115             if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1116                 ERR("Can't create Printers key\n");
1117                 printer_free(printer);
1118                 SetLastError(ERROR_INVALID_PRINTER_NAME);
1119                 printer = NULL;
1120                 goto end;
1121             }
1122             if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1123                 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1124                 RegCloseKey(hkeyPrinters);
1125                 printer_free(printer);
1126                 SetLastError(ERROR_INVALID_PRINTER_NAME);
1127                 printer = NULL;
1128                 goto end;
1129             }
1130             RegCloseKey(hkeyPrinter);
1131             RegCloseKey(hkeyPrinters);
1132         }
1133     }
1134     else
1135     {
1136         TRACE("using the local printserver\n");
1137     }
1138
1139 end:
1140
1141     TRACE("==> %p\n", printer);
1142     return (HANDLE)printer;
1143 }
1144
1145
1146 /******************************************************************************
1147  *  myAddPrinterDriverEx [internal]
1148  *
1149  * Install a Printer Driver with the Option to upgrade / downgrade the Files
1150  * and a special mode with lazy error checking.
1151  *
1152  */
1153 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1154 {
1155     static const WCHAR emptyW[1];
1156     const printenv_t *env;
1157     apd_data_t apd;
1158     DRIVER_INFO_8W di;
1159     BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1160     HMODULE hui;
1161     LPWSTR  ptr;
1162     HKEY    hroot;
1163     HKEY    hdrv;
1164     DWORD   disposition;
1165     DWORD   len;
1166     LONG    lres;
1167     BOOL    res;
1168
1169     /* we need to set all entries in the Registry, independent from the Level of
1170        DRIVER_INFO, that the caller supplied */
1171
1172     ZeroMemory(&di, sizeof(di));
1173     if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1174         memcpy(&di, pDriverInfo, di_sizeof[level]);
1175     }
1176
1177     /* dump the most used infos */
1178     TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1179     TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
1180     TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1181     TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1182     TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1183     TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1184     TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1185     /* dump only the first of the additional Files */
1186     TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1187
1188
1189     /* check environment */
1190     env = validate_envW(di.pEnvironment);
1191     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
1192
1193     /* fill the copy-data / get the driverdir */
1194     len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1195     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1196                                     (LPBYTE) apd.src, len, &len)) {
1197         /* Should never Fail */
1198         return FALSE;
1199     }
1200     memcpy(apd.dst, apd.src, len);
1201     lstrcatW(apd.src, backslashW);
1202     apd.srclen = lstrlenW(apd.src);
1203     lstrcatW(apd.dst, env->versionsubdir);
1204     lstrcatW(apd.dst, backslashW);
1205     apd.dstlen = lstrlenW(apd.dst);
1206     apd.copyflags = dwFileCopyFlags;
1207     apd.lazy = lazy;
1208     CreateDirectoryW(apd.src, NULL);
1209     CreateDirectoryW(apd.dst, NULL);
1210
1211     hroot = open_driver_reg(env->envname);
1212     if (!hroot) {
1213         ERR("Can't create Drivers key\n");
1214         return FALSE;
1215     }
1216
1217     /* Fill the Registry for the Driver */
1218     if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1219                                 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1220                                 &hdrv, &disposition)) != ERROR_SUCCESS) {
1221
1222         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1223         RegCloseKey(hroot);
1224         SetLastError(lres);
1225         return FALSE;
1226     }
1227     RegCloseKey(hroot);
1228
1229     if (disposition == REG_OPENED_EXISTING_KEY) {
1230         TRACE("driver %s already installed\n", debugstr_w(di.pName));
1231         RegCloseKey(hdrv);
1232         SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1233         return FALSE;
1234     }
1235
1236     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1237     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1238                    sizeof(DWORD));
1239
1240     RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1241                    (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1242     apd_copyfile(di.pDriverPath, &apd);
1243
1244     RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1245                    (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1246     apd_copyfile(di.pDataFile, &apd);
1247
1248     RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1249                    (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1250     apd_copyfile(di.pConfigFile, &apd);
1251
1252     /* settings for level 3 */
1253     if (di.pHelpFile)
1254         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1255                        (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1256     else
1257         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1258     apd_copyfile(di.pHelpFile, &apd);
1259
1260
1261     ptr = di.pDependentFiles;
1262     if (ptr)
1263         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1264                        multi_sz_lenW(di.pDependentFiles));
1265     else
1266         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1267     while ((ptr != NULL) && (ptr[0])) {
1268         if (apd_copyfile(ptr, &apd)) {
1269             ptr += lstrlenW(ptr) + 1;
1270         }
1271         else
1272         {
1273             WARN("Failed to copy %s\n", debugstr_w(ptr));
1274             ptr = NULL;
1275         }
1276     }
1277     /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1278     if (di.pMonitorName)
1279         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1280                        (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1281     else
1282         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1283
1284     if (di.pDefaultDataType)
1285         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1286                        (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1287     else
1288         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1289
1290     /* settings for level 4 */
1291     if (di.pszzPreviousNames)
1292         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1293                        multi_sz_lenW(di.pszzPreviousNames));
1294     else
1295         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1296
1297     if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1298
1299     RegCloseKey(hdrv);
1300     hui = driver_load(env, di.pConfigFile);
1301     pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1302     if (hui && pDrvDriverEvent) {
1303
1304         /* Support for DrvDriverEvent is optional */
1305         TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1306         /* MSDN: level for DRIVER_INFO is 1 to 3 */
1307         res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1308         TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1309     }
1310     FreeLibrary(hui);
1311
1312     TRACE("=> TRUE with %u\n", GetLastError());
1313     return TRUE;
1314
1315 }
1316
1317 /******************************************************************************
1318  * fpAddMonitor [exported through PRINTPROVIDOR]
1319  *
1320  * Install a Printmonitor
1321  *
1322  * PARAMS
1323  *  pName       [I] Servername or NULL (local Computer)
1324  *  Level       [I] Structure-Level (Must be 2)
1325  *  pMonitors   [I] PTR to MONITOR_INFO_2
1326  *
1327  * RETURNS
1328  *  Success: TRUE
1329  *  Failure: FALSE
1330  *
1331  * NOTES
1332  *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1333  *
1334  */
1335 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1336 {
1337     monitor_t * pm = NULL;
1338     LPMONITOR_INFO_2W mi2w;
1339     HKEY    hroot = NULL;
1340     HKEY    hentry = NULL;
1341     DWORD   disposition;
1342     BOOL    res = FALSE;
1343
1344     mi2w = (LPMONITOR_INFO_2W) pMonitors;
1345     TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1346             debugstr_w(mi2w ? mi2w->pName : NULL),
1347             debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1348             debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1349
1350     if (copy_servername_from_name(pName, NULL)) {
1351         FIXME("server %s not supported\n", debugstr_w(pName));
1352         SetLastError(ERROR_ACCESS_DENIED);
1353         return FALSE;
1354     }
1355
1356     if (!mi2w->pName || (! mi2w->pName[0])) {
1357         WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1358         SetLastError(ERROR_INVALID_PARAMETER);
1359         return FALSE;
1360     }
1361     if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1362         WARN("Environment %s requested (we support only %s)\n",
1363                 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1364         SetLastError(ERROR_INVALID_ENVIRONMENT);
1365         return FALSE;
1366     }
1367
1368     if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1369         WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1370         SetLastError(ERROR_INVALID_PARAMETER);
1371         return FALSE;
1372     }
1373
1374     /* Load and initialize the monitor. SetLastError() is called on failure */
1375     if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1376         return FALSE;
1377     }
1378     monitor_unload(pm);
1379
1380     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1381         ERR("unable to create key %s\n", debugstr_w(monitorsW));
1382         return FALSE;
1383     }
1384
1385     if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1386                         KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1387                         &disposition) == ERROR_SUCCESS) {
1388
1389         /* Some installers set options for the port before calling AddMonitor.
1390            We query the "Driver" entry to verify that the monitor is installed,
1391            before we return an error.
1392            When a user installs two print monitors at the same time with the
1393            same name, a race condition is possible but silently ignored. */
1394
1395         DWORD   namesize = 0;
1396
1397         if ((disposition == REG_OPENED_EXISTING_KEY) &&
1398             (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1399                               &namesize) == ERROR_SUCCESS)) {
1400             TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1401             /* 9x use ERROR_ALREADY_EXISTS */
1402             SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1403         }
1404         else
1405         {
1406             INT len;
1407             len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1408             res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1409                     (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1410         }
1411         RegCloseKey(hentry);
1412     }
1413
1414     RegCloseKey(hroot);
1415     return (res);
1416 }
1417
1418 /******************************************************************************
1419  * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1420  *
1421  * Install a Printer Driver with the Option to upgrade / downgrade the Files
1422  *
1423  * PARAMS
1424  *  pName           [I] Servername or NULL (local Computer)
1425  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
1426  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1427  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1428  *
1429  * RESULTS
1430  *  Success: TRUE
1431  *  Failure: FALSE
1432  *
1433  */
1434 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1435 {
1436     LONG lres;
1437
1438     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1439     lres = copy_servername_from_name(pName, NULL);
1440     if (lres) {
1441         FIXME("server %s not supported\n", debugstr_w(pName));
1442         SetLastError(ERROR_ACCESS_DENIED);
1443         return FALSE;
1444     }
1445
1446     if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1447         TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1448     }
1449
1450     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1451 }
1452
1453 /******************************************************************************
1454  * fpClosePrinter [exported through PRINTPROVIDOR]
1455  *
1456  * Close a printer handle and free associated resources
1457  *
1458  * PARAMS
1459  *  hPrinter [I] Printerhandle to close
1460  *
1461  * RESULTS
1462  *  Success: TRUE
1463  *  Failure: FALSE
1464  *
1465  */
1466 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1467 {
1468     printer_t *printer = (printer_t *) hPrinter;
1469
1470     TRACE("(%p)\n", hPrinter);
1471
1472     if (printer) {
1473         printer_free(printer);
1474         return TRUE;
1475     }
1476     return FALSE;
1477 }
1478
1479
1480 /******************************************************************
1481  * fpDeleteMonitor [exported through PRINTPROVIDOR]
1482  *
1483  * Delete a specific Printmonitor from a Printing-Environment
1484  *
1485  * PARAMS
1486  *  pName        [I] Servername or NULL (local Computer)
1487  *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1488  *  pMonitorName [I] Name of the Monitor, that should be deleted
1489  *
1490  * RETURNS
1491  *  Success: TRUE
1492  *  Failure: FALSE
1493  *
1494  * NOTES
1495  *  pEnvironment is ignored in Windows for the local Computer.
1496  *
1497  */
1498
1499 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1500 {
1501     HKEY    hroot = NULL;
1502     LONG    lres;
1503
1504     TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1505            debugstr_w(pMonitorName));
1506
1507     lres = copy_servername_from_name(pName, NULL);
1508     if (lres) {
1509         FIXME("server %s not supported\n", debugstr_w(pName));
1510         SetLastError(ERROR_INVALID_NAME);
1511         return FALSE;
1512     }
1513
1514     /*  pEnvironment is ignored in Windows for the local Computer */
1515     if (!pMonitorName || !pMonitorName[0]) {
1516         TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1517         SetLastError(ERROR_INVALID_PARAMETER);
1518         return FALSE;
1519     }
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(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1527         TRACE("%s deleted\n", debugstr_w(pMonitorName));
1528         RegCloseKey(hroot);
1529         return TRUE;
1530     }
1531
1532     TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1533     RegCloseKey(hroot);
1534
1535     /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1536     SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1537     return FALSE;
1538 }
1539
1540 /*****************************************************************************
1541  * fpEnumMonitors [exported through PRINTPROVIDOR]
1542  *
1543  * Enumerate available Port-Monitors
1544  *
1545  * PARAMS
1546  *  pName      [I] Servername or NULL (local Computer)
1547  *  Level      [I] Structure-Level (1:Win9x+NT or 2:NT only)
1548  *  pMonitors  [O] PTR to Buffer that receives the Result
1549  *  cbBuf      [I] Size of Buffer at pMonitors
1550  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1551  *  pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1552  *
1553  * RETURNS
1554  *  Success: TRUE
1555  *  Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1556  *
1557  * NOTES
1558  *  Windows reads the Registry once and cache the Results.
1559  *
1560  */
1561 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1562                                   LPDWORD pcbNeeded, LPDWORD pcReturned)
1563 {
1564     DWORD   numentries = 0;
1565     DWORD   needed = 0;
1566     LONG    lres;
1567     BOOL    res = FALSE;
1568
1569     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1570           cbBuf, pcbNeeded, pcReturned);
1571
1572     lres = copy_servername_from_name(pName, NULL);
1573     if (lres) {
1574         FIXME("server %s not supported\n", debugstr_w(pName));
1575         SetLastError(ERROR_INVALID_NAME);
1576         goto em_cleanup;
1577     }
1578
1579     if (!Level || (Level > 2)) {
1580         WARN("level (%d) is ignored in win9x\n", Level);
1581         SetLastError(ERROR_INVALID_LEVEL);
1582         return FALSE;
1583     }
1584
1585     /* Scan all Monitor-Keys */
1586     numentries = 0;
1587     needed = get_local_monitors(Level, NULL, 0, &numentries);
1588
1589     /* we calculated the needed buffersize. now do more error-checks */
1590     if (cbBuf < needed) {
1591         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1592         goto em_cleanup;
1593     }
1594
1595     /* fill the Buffer with the Monitor-Keys */
1596     needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1597     res = TRUE;
1598
1599 em_cleanup:
1600     if (pcbNeeded)  *pcbNeeded = needed;
1601     if (pcReturned) *pcReturned = numentries;
1602
1603     TRACE("returning %d with %d (%d byte for %d entries)\n",
1604             res, GetLastError(), needed, numentries);
1605
1606     return (res);
1607 }
1608
1609 /******************************************************************************
1610  * fpEnumPorts [exported through PRINTPROVIDOR]
1611  *
1612  * Enumerate available Ports
1613  *
1614  * PARAMS
1615  *  pName      [I] Servername or NULL (local Computer)
1616  *  Level      [I] Structure-Level (1 or 2)
1617  *  pPorts     [O] PTR to Buffer that receives the Result
1618  *  cbBuf      [I] Size of Buffer at pPorts
1619  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1620  *  pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1621  *
1622  * RETURNS
1623  *  Success: TRUE
1624  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1625  *
1626  */
1627 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1628                                LPDWORD pcbNeeded, LPDWORD pcReturned)
1629 {
1630     DWORD   needed = 0;
1631     DWORD   numentries = 0;
1632     LONG    lres;
1633     BOOL    res = FALSE;
1634
1635     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1636           cbBuf, pcbNeeded, pcReturned);
1637
1638     lres = copy_servername_from_name(pName, NULL);
1639     if (lres) {
1640         FIXME("server %s not supported\n", debugstr_w(pName));
1641         SetLastError(ERROR_INVALID_NAME);
1642         goto emP_cleanup;
1643     }
1644
1645     if (!Level || (Level > 2)) {
1646         SetLastError(ERROR_INVALID_LEVEL);
1647         goto emP_cleanup;
1648     }
1649
1650     if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1651         SetLastError(RPC_X_NULL_REF_POINTER);
1652         goto emP_cleanup;
1653     }
1654
1655     EnterCriticalSection(&monitor_handles_cs);
1656     monitor_loadall();
1657
1658     /* Scan all local Ports */
1659     numentries = 0;
1660     needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1661
1662     /* we calculated the needed buffersize. now do the error-checks */
1663     if (cbBuf < needed) {
1664         monitor_unloadall();
1665         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1666         goto emP_cleanup_cs;
1667     }
1668     else if (!pPorts || !pcReturned) {
1669         monitor_unloadall();
1670         SetLastError(RPC_X_NULL_REF_POINTER);
1671         goto emP_cleanup_cs;
1672     }
1673
1674     /* Fill the Buffer */
1675     needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1676     res = TRUE;
1677     monitor_unloadall();
1678
1679 emP_cleanup_cs:
1680     LeaveCriticalSection(&monitor_handles_cs);
1681
1682 emP_cleanup:
1683     if (pcbNeeded)  *pcbNeeded = needed;
1684     if (pcReturned) *pcReturned = (res) ? numentries : 0;
1685
1686     TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1687           (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1688
1689     return (res);
1690 }
1691
1692 /******************************************************************************
1693  * fpOpenPrinter [exported through PRINTPROVIDOR]
1694  *
1695  * Open a Printer / Printserver or a Printer-Object
1696  *
1697  * PARAMS
1698  *  lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1699  *  pPrinter      [O] The resulting Handle is stored here
1700  *  pDefaults     [I] PTR to Default Printer Settings or NULL
1701  *
1702  * RETURNS
1703  *  Success: TRUE
1704  *  Failure: FALSE
1705  *
1706  * NOTES
1707  *  lpPrinterName is one of:
1708  *|  Printserver (NT only): "Servername" or NULL for the local Printserver
1709  *|  Printer: "PrinterName"
1710  *|  Printer-Object: "PrinterName,Job xxx"
1711  *|  XcvMonitor: "Servername,XcvMonitor MonitorName"
1712  *|  XcvPort: "Servername,XcvPort PortName"
1713  *
1714  *
1715  */
1716 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
1717                                  LPPRINTER_DEFAULTSW pDefaults)
1718 {
1719
1720     TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
1721
1722     *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
1723
1724     return (*pPrinter != 0);
1725 }
1726
1727 /******************************************************************************
1728  * fpXcvData [exported through PRINTPROVIDOR]
1729  *
1730  * Execute commands in the Printmonitor DLL
1731  *
1732  * PARAMS
1733  *  hXcv            [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
1734  *  pszDataName     [i] Name of the command to execute
1735  *  pInputData      [i] Buffer for extra Input Data (needed only for some commands)
1736  *  cbInputData     [i] Size in Bytes of Buffer at pInputData
1737  *  pOutputData     [o] Buffer to receive additional Data (needed only for some commands)
1738  *  cbOutputData    [i] Size in Bytes of Buffer at pOutputData
1739  *  pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
1740  *  pdwStatus       [o] PTR to receive the win32 error code from the Printmonitor DLL
1741  *
1742  * RETURNS
1743  *  Success: TRUE
1744  *  Failure: FALSE
1745  *
1746  * NOTES
1747  *  Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
1748  *  The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
1749  *
1750  *  Minimal List of commands, that a Printmonitor DLL should support:
1751  *
1752  *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
1753  *| "AddPort"   : Add a Port
1754  *| "DeletePort": Delete a Port
1755  *
1756  *  Many Printmonitors support additional commands. Examples for localspl.dll:
1757  *  "GetDefaultCommConfig", "SetDefaultCommConfig",
1758  *  "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
1759  *
1760  */
1761 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
1762                     DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
1763                     PDWORD pcbOutputNeeded, PDWORD pdwStatus)
1764 {
1765     printer_t *printer = (printer_t * ) hXcv;
1766
1767     TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
1768           pInputData, cbInputData, pOutputData,
1769           cbOutputData, pcbOutputNeeded, pdwStatus);
1770
1771     if (!printer || (!printer->hXcv)) {
1772         SetLastError(ERROR_INVALID_HANDLE);
1773         return FALSE;
1774     }
1775
1776     if (!pcbOutputNeeded) {
1777         SetLastError(ERROR_INVALID_PARAMETER);
1778         return FALSE;
1779     }
1780
1781     if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
1782         SetLastError(RPC_X_NULL_REF_POINTER);
1783         return FALSE;
1784     }
1785
1786     *pcbOutputNeeded = 0;
1787
1788     *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
1789             pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
1790
1791     return TRUE;
1792 }
1793
1794 /*****************************************************
1795  *  setup_provider [internal]
1796  */
1797 void setup_provider(void)
1798 {
1799     static const PRINTPROVIDOR backend = {
1800         fpOpenPrinter,
1801         NULL,   /* fpSetJob */
1802         NULL,   /* fpGetJob */
1803         NULL,   /* fpEnumJobs */
1804         NULL,   /* fpAddPrinter */
1805         NULL,   /* fpDeletePrinter */
1806         NULL,   /* fpSetPrinter */
1807         NULL,   /* fpGetPrinter */
1808         NULL,   /* fpEnumPrinters */
1809         NULL,   /* fpAddPrinterDriver */
1810         NULL,   /* fpEnumPrinterDrivers */
1811         NULL,   /* fpGetPrinterDriver */
1812         fpGetPrinterDriverDirectory,
1813         NULL,   /* fpDeletePrinterDriver */
1814         NULL,   /* fpAddPrintProcessor */
1815         NULL,   /* fpEnumPrintProcessors */
1816         NULL,   /* fpGetPrintProcessorDirectory */
1817         NULL,   /* fpDeletePrintProcessor */
1818         NULL,   /* fpEnumPrintProcessorDatatypes */
1819         NULL,   /* fpStartDocPrinter */
1820         NULL,   /* fpStartPagePrinter */
1821         NULL,   /* fpWritePrinter */
1822         NULL,   /* fpEndPagePrinter */
1823         NULL,   /* fpAbortPrinter */
1824         NULL,   /* fpReadPrinter */
1825         NULL,   /* fpEndDocPrinter */
1826         NULL,   /* fpAddJob */
1827         NULL,   /* fpScheduleJob */
1828         NULL,   /* fpGetPrinterData */
1829         NULL,   /* fpSetPrinterData */
1830         NULL,   /* fpWaitForPrinterChange */
1831         fpClosePrinter,
1832         NULL,   /* fpAddForm */
1833         NULL,   /* fpDeleteForm */
1834         NULL,   /* fpGetForm */
1835         NULL,   /* fpSetForm */
1836         NULL,   /* fpEnumForms */
1837         fpEnumMonitors,
1838         fpEnumPorts,
1839         NULL,   /* fpAddPort */
1840         NULL,   /* fpConfigurePort */
1841         NULL,   /* fpDeletePort */
1842         NULL,   /* fpCreatePrinterIC */
1843         NULL,   /* fpPlayGdiScriptOnPrinterIC */
1844         NULL,   /* fpDeletePrinterIC */
1845         NULL,   /* fpAddPrinterConnection */
1846         NULL,   /* fpDeletePrinterConnection */
1847         NULL,   /* fpPrinterMessageBox */
1848         fpAddMonitor,
1849         fpDeleteMonitor,
1850         NULL,   /* fpResetPrinter */
1851         NULL,   /* fpGetPrinterDriverEx */
1852         NULL,   /* fpFindFirstPrinterChangeNotification */
1853         NULL,   /* fpFindClosePrinterChangeNotification */
1854         NULL,   /* fpAddPortEx */
1855         NULL,   /* fpShutDown */
1856         NULL,   /* fpRefreshPrinterChangeNotification */
1857         NULL,   /* fpOpenPrinterEx */
1858         NULL,   /* fpAddPrinterEx */
1859         NULL,   /* fpSetPort */
1860         NULL,   /* fpEnumPrinterData */
1861         NULL,   /* fpDeletePrinterData */
1862         NULL,   /* fpClusterSplOpen */
1863         NULL,   /* fpClusterSplClose */
1864         NULL,   /* fpClusterSplIsAlive */
1865         NULL,   /* fpSetPrinterDataEx */
1866         NULL,   /* fpGetPrinterDataEx */
1867         NULL,   /* fpEnumPrinterDataEx */
1868         NULL,   /* fpEnumPrinterKey */
1869         NULL,   /* fpDeletePrinterDataEx */
1870         NULL,   /* fpDeletePrinterKey */
1871         NULL,   /* fpSeekPrinter */
1872         NULL,   /* fpDeletePrinterDriverEx */
1873         NULL,   /* fpAddPerMachineConnection */
1874         NULL,   /* fpDeletePerMachineConnection */
1875         NULL,   /* fpEnumPerMachineConnections */
1876         fpXcvData,
1877         fpAddPrinterDriverEx,
1878         NULL,   /* fpSplReadPrinter */
1879         NULL,   /* fpDriverUnloadComplete */
1880         NULL,   /* fpGetSpoolFileInfo */
1881         NULL,   /* fpCommitSpoolData */
1882         NULL,   /* fpCloseSpoolFileHandle */
1883         NULL,   /* fpFlushPrinter */
1884         NULL,   /* fpSendRecvBidiData */
1885         NULL    /* fpAddDriverCatalog */
1886     };
1887     pprovider = &backend;
1888
1889 }
1890
1891 /*****************************************************
1892  * InitializePrintProvidor     (localspl.@)
1893  *
1894  * Initialize the Printprovider
1895  *
1896  * PARAMS
1897  *  pPrintProvidor    [I] Buffer to fill with a struct PRINTPROVIDOR
1898  *  cbPrintProvidor   [I] Size of Buffer in Bytes
1899  *  pFullRegistryPath [I] Registry-Path for the Printprovidor
1900  *
1901  * RETURNS
1902  *  Success: TRUE and pPrintProvidor filled
1903  *  Failure: FALSE
1904  *
1905  * NOTES
1906  *  The RegistryPath should be:
1907  *  "System\CurrentControlSet\Control\Print\Providers\<providername>",
1908  *  but this Parameter is ignored in "localspl.dll".
1909  *
1910  */
1911
1912 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
1913                                     DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
1914 {
1915
1916     TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
1917     memcpy(pPrintProvidor, pprovider,
1918           (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
1919
1920     return TRUE;
1921 }