amstream: Simplify declaration of VTable members.
[wine] / dlls / spoolss / router.c
1 /*
2  * Routing for Spooler-Service helper DLL
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 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "winreg.h"
27
28 #include "wingdi.h"
29 #include "winspool.h"
30 #include "ddk/winsplp.h"
31 #include "spoolss.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(spoolss);
36
37 /* ################################ */
38
39 #define MAX_BACKEND 3
40
41 typedef struct {
42     /* PRINTPROVIDOR functions */
43     DWORD  (WINAPI *fpOpenPrinter)(LPWSTR, HANDLE *, LPPRINTER_DEFAULTSW);
44     DWORD  (WINAPI *fpSetJob)(HANDLE, DWORD, DWORD, LPBYTE, DWORD);
45     DWORD  (WINAPI *fpGetJob)(HANDLE, DWORD, DWORD, LPBYTE, DWORD, LPDWORD);
46     DWORD  (WINAPI *fpEnumJobs)(HANDLE, DWORD, DWORD, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
47     HANDLE (WINAPI *fpAddPrinter)(LPWSTR, DWORD, LPBYTE);
48     DWORD  (WINAPI *fpDeletePrinter)(HANDLE);
49     DWORD  (WINAPI *fpSetPrinter)(HANDLE, DWORD, LPBYTE, DWORD);
50     DWORD  (WINAPI *fpGetPrinter)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD);
51     DWORD  (WINAPI *fpEnumPrinters)(DWORD, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
52     DWORD  (WINAPI *fpAddPrinterDriver)(LPWSTR, DWORD, LPBYTE);
53     DWORD  (WINAPI *fpEnumPrinterDrivers)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
54     DWORD  (WINAPI *fpGetPrinterDriver)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
55     DWORD  (WINAPI *fpGetPrinterDriverDirectory)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
56     DWORD  (WINAPI *fpDeletePrinterDriver)(LPWSTR, LPWSTR, LPWSTR);
57     DWORD  (WINAPI *fpAddPrintProcessor)(LPWSTR, LPWSTR, LPWSTR, LPWSTR);
58     DWORD  (WINAPI *fpEnumPrintProcessors)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
59     DWORD  (WINAPI *fpGetPrintProcessorDirectory)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
60     DWORD  (WINAPI *fpDeletePrintProcessor)(LPWSTR, LPWSTR, LPWSTR);
61     DWORD  (WINAPI *fpEnumPrintProcessorDatatypes)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
62     DWORD  (WINAPI *fpStartDocPrinter)(HANDLE, DWORD, LPBYTE);
63     DWORD  (WINAPI *fpStartPagePrinter)(HANDLE);
64     DWORD  (WINAPI *fpWritePrinter)(HANDLE, LPVOID, DWORD, LPDWORD);
65     DWORD  (WINAPI *fpEndPagePrinter)(HANDLE);
66     DWORD  (WINAPI *fpAbortPrinter)(HANDLE);
67     DWORD  (WINAPI *fpReadPrinter)(HANDLE, LPVOID, DWORD, LPDWORD);
68     DWORD  (WINAPI *fpEndDocPrinter)(HANDLE);
69     DWORD  (WINAPI *fpAddJob)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD);
70     DWORD  (WINAPI *fpScheduleJob)(HANDLE, DWORD);
71     DWORD  (WINAPI *fpGetPrinterData)(HANDLE, LPWSTR, LPDWORD, LPBYTE, DWORD, LPDWORD);
72     DWORD  (WINAPI *fpSetPrinterData)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD);
73     DWORD  (WINAPI *fpWaitForPrinterChange)(HANDLE, DWORD);
74     DWORD  (WINAPI *fpClosePrinter)(HANDLE);
75     DWORD  (WINAPI *fpAddForm)(HANDLE, DWORD, LPBYTE);
76     DWORD  (WINAPI *fpDeleteForm)(HANDLE, LPWSTR);
77     DWORD  (WINAPI *fpGetForm)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
78     DWORD  (WINAPI *fpSetForm)(HANDLE, LPWSTR, DWORD, LPBYTE);
79     DWORD  (WINAPI *fpEnumForms)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
80     DWORD  (WINAPI *fpEnumMonitors)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
81     DWORD  (WINAPI *fpEnumPorts)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
82     DWORD  (WINAPI *fpAddPort)(LPWSTR, HWND, LPWSTR);
83     DWORD  (WINAPI *fpConfigurePort)(LPWSTR, HWND, LPWSTR);
84     DWORD  (WINAPI *fpDeletePort)(LPWSTR, HWND, LPWSTR);
85     HANDLE (WINAPI *fpCreatePrinterIC)(HANDLE, LPDEVMODEW);
86     DWORD  (WINAPI *fpPlayGdiScriptOnPrinterIC)(HANDLE, LPBYTE, DWORD, LPBYTE, DWORD, DWORD);
87     DWORD  (WINAPI *fpDeletePrinterIC)(HANDLE);
88     DWORD  (WINAPI *fpAddPrinterConnection)(LPWSTR);
89     DWORD  (WINAPI *fpDeletePrinterConnection)(LPWSTR);
90     DWORD  (WINAPI *fpPrinterMessageBox)(HANDLE, DWORD, HWND, LPWSTR, LPWSTR, DWORD);
91     DWORD  (WINAPI *fpAddMonitor)(LPWSTR, DWORD, LPBYTE);
92     DWORD  (WINAPI *fpDeleteMonitor)(LPWSTR, LPWSTR, LPWSTR);
93     DWORD  (WINAPI *fpResetPrinter)(HANDLE, LPPRINTER_DEFAULTSW);
94     DWORD  (WINAPI *fpGetPrinterDriverEx)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, DWORD, DWORD, PDWORD, PDWORD);
95     HANDLE (WINAPI *fpFindFirstPrinterChangeNotification)(HANDLE, DWORD, DWORD, LPVOID);
96     DWORD  (WINAPI *fpFindClosePrinterChangeNotification)(HANDLE);
97     DWORD  (WINAPI *fpAddPortEx)(HANDLE, LPWSTR, DWORD, LPBYTE, LPWSTR);
98     DWORD  (WINAPI *fpShutDown)(LPVOID);
99     DWORD  (WINAPI *fpRefreshPrinterChangeNotification)(HANDLE, DWORD, PVOID, PVOID);
100     DWORD  (WINAPI *fpOpenPrinterEx)(LPWSTR, LPHANDLE, LPPRINTER_DEFAULTSW, LPBYTE, DWORD);
101     HANDLE (WINAPI *fpAddPrinterEx)(LPWSTR, DWORD, LPBYTE, LPBYTE, DWORD);
102     DWORD  (WINAPI *fpSetPort)(LPWSTR, LPWSTR, DWORD, LPBYTE);
103     DWORD  (WINAPI *fpEnumPrinterData)(HANDLE, DWORD, LPWSTR, DWORD, LPDWORD, LPDWORD, LPBYTE, DWORD, LPDWORD);
104     DWORD  (WINAPI *fpDeletePrinterData)(HANDLE, LPWSTR);
105     DWORD  (WINAPI *fpClusterSplOpen)(LPCWSTR, LPCWSTR, PHANDLE, LPCWSTR, LPCWSTR);
106     DWORD  (WINAPI *fpClusterSplClose)(HANDLE);
107     DWORD  (WINAPI *fpClusterSplIsAlive)(HANDLE);
108     DWORD  (WINAPI *fpSetPrinterDataEx)(HANDLE, LPCWSTR, LPCWSTR, DWORD, LPBYTE, DWORD);
109     DWORD  (WINAPI *fpGetPrinterDataEx)(HANDLE, LPCWSTR, LPCWSTR, LPDWORD, LPBYTE, DWORD, LPDWORD);
110     DWORD  (WINAPI *fpEnumPrinterDataEx)(HANDLE, LPCWSTR, LPBYTE, DWORD, LPDWORD, LPDWORD);
111     DWORD  (WINAPI *fpEnumPrinterKey)(HANDLE, LPCWSTR, LPWSTR, DWORD, LPDWORD);
112     DWORD  (WINAPI *fpDeletePrinterDataEx)(HANDLE, LPCWSTR, LPCWSTR);
113     DWORD  (WINAPI *fpDeletePrinterKey)(HANDLE hPrinter, LPCWSTR pKeyName);
114     DWORD  (WINAPI *fpSeekPrinter)(HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD, BOOL);
115     DWORD  (WINAPI *fpDeletePrinterDriverEx)(LPWSTR, LPWSTR, LPWSTR, DWORD, DWORD);
116     DWORD  (WINAPI *fpAddPerMachineConnection)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
117     DWORD  (WINAPI *fpDeletePerMachineConnection)(LPCWSTR, LPCWSTR);
118     DWORD  (WINAPI *fpEnumPerMachineConnections)(LPCWSTR, LPBYTE, DWORD, LPDWORD, LPDWORD);
119     DWORD  (WINAPI *fpXcvData)(HANDLE, LPCWSTR, PBYTE, DWORD, PBYTE, DWORD, PDWORD, PDWORD);
120     DWORD  (WINAPI *fpAddPrinterDriverEx)(LPWSTR, DWORD, LPBYTE, DWORD);
121     DWORD  (WINAPI *fpSplReadPrinter)(HANDLE, LPBYTE *, DWORD);
122     DWORD  (WINAPI *fpDriverUnloadComplete)(LPWSTR);
123     DWORD  (WINAPI *fpGetSpoolFileInfo)(HANDLE, LPWSTR *, LPHANDLE, HANDLE, HANDLE);
124     DWORD  (WINAPI *fpCommitSpoolData)(HANDLE, DWORD);
125     DWORD  (WINAPI *fpCloseSpoolFileHandle)(HANDLE);
126     DWORD  (WINAPI *fpFlushPrinter)(HANDLE, LPBYTE, DWORD, LPDWORD, DWORD);
127     DWORD  (WINAPI *fpSendRecvBidiData)(HANDLE, LPCWSTR, LPBIDI_REQUEST_CONTAINER, LPBIDI_RESPONSE_CONTAINER *);
128     DWORD  (WINAPI *fpAddDriverCatalog)(HANDLE, DWORD, VOID *, DWORD);
129     /* Private Data */
130     HMODULE dll;
131     LPWSTR  dllname;
132     LPWSTR  name;
133     LPWSTR  regroot;
134     DWORD   index;
135 } backend_t;
136
137 /* ################################ */
138
139 static backend_t *backend[MAX_BACKEND];
140 static DWORD used_backends = 0;
141
142 static CRITICAL_SECTION backend_cs;
143 static CRITICAL_SECTION_DEBUG backend_cs_debug =
144 {
145     0, 0, &backend_cs,
146     { &backend_cs_debug.ProcessLocksList, &backend_cs_debug.ProcessLocksList },
147       0, 0, { (DWORD_PTR)(__FILE__ ": backend_cs") }
148 };
149 static CRITICAL_SECTION backend_cs = { &backend_cs_debug, -1, 0, 0, 0, 0 };
150
151 /* ################################ */
152
153 static WCHAR localsplW[] = {'l','o','c','a','l','s','p','l','.','d','l','l',0};
154
155 /******************************************************************
156  * strdupW [internal]
157  *
158  * create a copy of a unicode-string
159  *
160  */
161
162 static LPWSTR strdupW(LPCWSTR p)
163 {
164     LPWSTR ret;
165     DWORD len;
166
167     if(!p) return NULL;
168     len = (lstrlenW(p) + 1) * sizeof(WCHAR);
169     ret = heap_alloc(len);
170     memcpy(ret, p, len);
171     return ret;
172 }
173
174 /******************************************************************
175  * backend_unload_all [internal]
176  *
177  * unload all backends
178  */
179 void backend_unload_all(void)
180 {
181     EnterCriticalSection(&backend_cs);
182     while (used_backends > 0) {
183         used_backends--;
184         FreeLibrary(backend[used_backends]->dll);
185         heap_free(backend[used_backends]->dllname);
186         heap_free(backend[used_backends]->name);
187         heap_free(backend[used_backends]->regroot);
188         heap_free(backend[used_backends]);
189         backend[used_backends] = NULL;
190     }
191     LeaveCriticalSection(&backend_cs);
192 }
193
194 /******************************************************************************
195  * backend_load [internal]
196  *
197  * load and init a backend
198  *
199  * PARAMS
200  *  name   [I] Printprovider to use for the backend. NULL for the local print provider
201  *
202  * RETURNS
203  *  Success: PTR to the backend
204  *  Failure: NULL
205  *
206  */
207 static backend_t * backend_load(LPWSTR dllname, LPWSTR name, LPWSTR regroot)
208 {
209
210     BOOL (WINAPI *pInitializePrintProvidor)(LPPRINTPROVIDOR, DWORD, LPWSTR);
211     DWORD id;
212     DWORD res;
213
214     TRACE("(%s, %s, %s)\n", debugstr_w(dllname), debugstr_w(name), debugstr_w(regroot));
215
216     EnterCriticalSection(&backend_cs);
217     id = used_backends;
218
219     backend[id] = heap_alloc_zero(sizeof(backend_t));
220     if (!backend[id]) {
221         LeaveCriticalSection(&backend_cs);
222         return NULL;
223     }
224
225     backend[id]->dllname = strdupW(dllname);
226     backend[id]->name = strdupW(name);
227     backend[id]->regroot = strdupW(regroot);
228
229     backend[id]->dll = LoadLibraryW(dllname);
230     if (backend[id]->dll) {
231         pInitializePrintProvidor = (void *) GetProcAddress(backend[id]->dll, "InitializePrintProvidor");
232         if (pInitializePrintProvidor) {
233
234             /* native localspl does not clear unused entries */
235             res = pInitializePrintProvidor((PRINTPROVIDOR *) backend[id], sizeof(PRINTPROVIDOR), regroot);
236             if (res) {
237                 used_backends++;
238                 backend[id]->index = used_backends;
239                 LeaveCriticalSection(&backend_cs);
240                 TRACE("--> backend #%d: %p (%s)\n", id, backend[id], debugstr_w(dllname));
241                 return backend[id];
242             }
243         }
244         FreeLibrary(backend[id]->dll);
245     }
246     heap_free(backend[id]->dllname);
247     heap_free(backend[id]->name);
248     heap_free(backend[id]->regroot);
249     heap_free(backend[id]);
250     backend[id] = NULL;
251     LeaveCriticalSection(&backend_cs);
252     WARN("failed to init %s: %u\n", debugstr_w(dllname), GetLastError());
253     return NULL;
254 }
255
256 /******************************************************************************
257  * backend_load_all [internal]
258  *
259  * load and init all backends
260  *
261  * RETURNS
262  *  Success: TRUE
263  *  Failure: FALSE
264  *
265  */
266 BOOL backend_load_all(void)
267 {
268     static BOOL failed = FALSE;
269     backend_t * pb;
270
271     EnterCriticalSection(&backend_cs);
272
273     /* if we failed before, don't try again */
274     if (!failed && (used_backends == 0)) {
275         pb = backend_load(localsplW, NULL, NULL);
276
277         /* ToDo: parse the registry and load all other backends */
278
279         failed = (used_backends == 0);
280     }
281     LeaveCriticalSection(&backend_cs);
282     TRACE("-> %d\n", !failed);
283     return (!failed);
284 }
285
286 /******************************************************************************
287  * backend_first [internal]
288  *
289  * find the first usable backend
290  *
291  * RETURNS
292  *  Success: PTR to the backend
293  *  Failure: NULL
294  *
295  */
296 static backend_t * backend_first(LPWSTR name)
297 {
298
299     EnterCriticalSection(&backend_cs);
300     /* Load all backends, when not done yet */
301     if (used_backends || backend_load_all()) {
302
303         /* test for the local system first */
304         if (!name || !name[0]) {
305             LeaveCriticalSection(&backend_cs);
306             return backend[0];
307         }
308     }
309
310     FIXME("server %s not supported in %d backends\n", debugstr_w(name), used_backends);
311     LeaveCriticalSection(&backend_cs);
312     return NULL;
313 }
314
315 /******************************************************************
316  * AddMonitorW (spoolss.@)
317  *
318  * Install a Printmonitor
319  *
320  * PARAMS
321  *  pName       [I] Servername or NULL (local Computer)
322  *  Level       [I] Structure-Level (Must be 2)
323  *  pMonitors   [I] PTR to MONITOR_INFO_2
324  *
325  * RETURNS
326  *  Success: TRUE
327  *  Failure: FALSE
328  *
329  * NOTES
330  *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
331  *
332  */
333 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
334 {
335     backend_t * pb;
336     DWORD res = ROUTER_UNKNOWN;
337
338     TRACE("(%s, %d, %p)\n", debugstr_w(pName), Level, pMonitors);
339
340     if (Level != 2) {
341         SetLastError(ERROR_INVALID_LEVEL);
342         return FALSE;
343     }
344
345     pb = backend_first(pName);
346     if (pb && pb->fpAddMonitor)
347         res = pb->fpAddMonitor(pName, Level, pMonitors);
348     else
349     {
350         SetLastError(ERROR_PROC_NOT_FOUND);
351     }
352
353     TRACE("got %u with %u\n", res, GetLastError());
354     return (res == ROUTER_SUCCESS);
355 }
356
357 /******************************************************************
358  * AddPrinterDriverExW (spoolss.@)
359  *
360  * Install a Printer Driver with the Option to upgrade / downgrade the Files
361  *
362  * PARAMS
363  *  pName           [I] Servername or NULL (local Computer)
364  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
365  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
366  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
367  *
368  * RESULTS
369  *  Success: TRUE
370  *  Failure: FALSE
371  *
372  */
373 BOOL WINAPI AddPrinterDriverExW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
374 {
375     backend_t * pb;
376     DWORD res = ROUTER_UNKNOWN;
377
378     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
379
380     if (!pDriverInfo) {
381         SetLastError(ERROR_INVALID_PARAMETER);
382         return FALSE;
383     }
384
385     pb = backend_first(pName);
386     if (pb && pb->fpAddPrinterDriverEx)
387         res = pb->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
388     else
389     {
390         SetLastError(ERROR_PROC_NOT_FOUND);
391     }
392
393     TRACE("got %u with %u\n", res, GetLastError());
394     return (res == ROUTER_SUCCESS);
395 }
396
397 /******************************************************************
398  * DeleteMonitorW (spoolss.@)
399  *
400  * Delete a specific Printmonitor from a Printing-Environment
401  *
402  * PARAMS
403  *  pName        [I] Servername or NULL (local Computer)
404  *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
405  *  pMonitorName [I] Name of the Monitor, that should be deleted
406  *
407  * RETURNS
408  *  Success: TRUE
409  *  Failure: FALSE
410  *
411  */
412 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
413 {
414     backend_t * pb;
415     DWORD res = ROUTER_UNKNOWN;
416
417     TRACE("(%s, %s, %s)\n", debugstr_w(pName), debugstr_w(pEnvironment), debugstr_w(pMonitorName));
418
419     pb = backend_first(pName);
420     if (pb && pb->fpDeleteMonitor)
421         res = pb->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
422     else
423     {
424         SetLastError(ERROR_PROC_NOT_FOUND);
425     }
426
427     TRACE("got %u with %u\n", res, GetLastError());
428     return (res == ROUTER_SUCCESS);
429 }
430
431 /******************************************************************
432  * EnumMonitorsW (spoolss.@)
433  *
434  * Enumerate available Port-Monitors
435  *
436  * PARAMS
437  *  pName      [I] Servername or NULL (local Computer)
438  *  Level      [I] Structure-Level
439  *  pMonitors  [O] PTR to Buffer that receives the Result
440  *  cbBuf      [I] Size of Buffer at pMonitors
441  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
442  *  pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
443  *
444  * RETURNS
445  *  Success: TRUE
446  *  Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
447  *
448  */
449 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
450                           LPDWORD pcbNeeded, LPDWORD pcReturned)
451 {
452     backend_t * pb;
453     DWORD res = ROUTER_UNKNOWN;
454
455     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
456           cbBuf, pcbNeeded, pcReturned);
457
458     if (pcbNeeded) *pcbNeeded = 0;
459     if (pcReturned) *pcReturned = 0;
460
461     pb = backend_first(pName);
462     if (pb && pb->fpEnumMonitors)
463         res = pb->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
464     else
465     {
466         SetLastError(ERROR_PROC_NOT_FOUND);
467     }
468
469     TRACE("got %u with %u (%u byte for %u entries)\n\n", res, GetLastError(),
470             pcbNeeded ? *pcbNeeded : 0, pcReturned ? *pcReturned : 0);
471
472     return (res == ROUTER_SUCCESS);
473 }
474
475 /******************************************************************
476  * EnumPortsW (spoolss.@)
477  *
478  * Enumerate available Ports
479  *
480  * PARAMS
481  *  pName      [I] Servername or NULL (local Computer)
482  *  Level      [I] Structure-Level (1 or 2)
483  *  pPorts     [O] PTR to Buffer that receives the Result
484  *  cbBuf      [I] Size of Buffer at pPorts
485  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
486  *  pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
487  *
488  * RETURNS
489  *  Success: TRUE
490  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
491  *
492  */
493 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
494                        LPDWORD pcbNeeded, LPDWORD pcReturned)
495 {
496     backend_t * pb;
497     DWORD res = ROUTER_UNKNOWN;
498
499     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts, cbBuf,
500             pcbNeeded, pcReturned);
501
502     if (pcbNeeded) *pcbNeeded = 0;
503     if (pcReturned) *pcReturned = 0;
504
505     pb = backend_first(pName);
506     if (pb && pb->fpEnumPorts)
507         res = pb->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
508     else
509     {
510         SetLastError(ERROR_PROC_NOT_FOUND);
511     }
512
513     TRACE("got %u with %u (%u byte for %u entries)\n", res, GetLastError(),
514             pcbNeeded ? *pcbNeeded : 0, pcReturned ? *pcReturned : 0);
515
516     return (res == ROUTER_SUCCESS);
517 }
518
519 /******************************************************************
520  * GetPrinterDriverDirectoryW (spoolss.@)
521  *
522  * Return the PATH for the Printer-Drivers
523  *
524  * PARAMS
525  *   pName            [I] Servername or NULL (local Computer)
526  *   pEnvironment     [I] Printing-Environment or NULL (Default)
527  *   Level            [I] Structure-Level (must be 1)
528  *   pDriverDirectory [O] PTR to Buffer that receives the Result
529  *   cbBuf            [I] Size of Buffer at pDriverDirectory
530  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
531  *                        required for pDriverDirectory
532  *
533  * RETURNS
534  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
535  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
536  *   if cbBuf is too small
537  *
538  *   Native Values returned in pDriverDirectory on Success:
539  *|  NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
540  *|  NT(Windows x64):    "%winsysdir%\\spool\\DRIVERS\\x64"
541  *|  NT(Windows 4.0):    "%winsysdir%\\spool\\DRIVERS\\win40"
542  *|  win9x(Windows 4.0): "%winsysdir%"
543  *
544  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
545  *
546  */
547 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
548             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
549 {
550     backend_t * pb;
551     DWORD res = ROUTER_UNKNOWN;
552
553     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
554           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
555
556     if (pcbNeeded) *pcbNeeded = 0;
557
558     pb = backend_first(pName);
559     if (pb && pb->fpGetPrinterDriverDirectory)
560         res = pb->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
561                                               pDriverDirectory, cbBuf, pcbNeeded);
562     else
563     {
564         SetLastError(ERROR_PROC_NOT_FOUND);
565     }
566
567     TRACE("got %u with %u (%u byte)\n",
568             res, GetLastError(), pcbNeeded ? *pcbNeeded : 0);
569
570     return (res == ROUTER_SUCCESS);
571
572 }