Enable the functions AddPrinterW, WINSPOOL_GetPrinterDriver,
[wine] / dlls / winspool / info.c
1 /* 
2  * WINSPOOL functions
3  * 
4  * Copyright 1996 John Harvey
5  * Copyright 1998 Andreas Mohr
6  * Copyright 1999 Klaas van Gend
7  * Copyright 1999, 2000 Huw D M Davies
8  */
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <stddef.h>
14 #include "winspool.h"
15 #include "winbase.h"
16 #include "winerror.h"
17 #include "winreg.h"
18 #include "wine/windef16.h"
19 #include "wine/unicode.h"
20 #include "debugtools.h"
21 #include "heap.h"
22 #include "commctrl.h"
23 #include "winnls.h"
24
25 DEFAULT_DEBUG_CHANNEL(winspool);
26
27 typedef struct _OPENEDPRINTER
28 {
29     LPWSTR lpsPrinterName;
30     HANDLE hPrinter;
31 } OPENEDPRINTER, *LPOPENEDPRINTER;
32
33 /* The OpenedPrinter Table dynamic array */
34 static HDPA pOpenedPrinterDPA = NULL;
35
36 extern HDPA   (WINAPI* WINSPOOL_DPA_CreateEx) (INT, HANDLE);
37 extern LPVOID (WINAPI* WINSPOOL_DPA_GetPtr) (const HDPA, INT);
38 extern INT    (WINAPI* WINSPOOL_DPA_InsertPtr) (const HDPA, INT, LPVOID);
39
40 static char Printers[] =
41 "System\\CurrentControlSet\\control\\Print\\Printers\\";
42 static char Drivers[] =
43 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
44
45 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
46
47 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
48                                       'i','o','n',' ','F','i','l','e',0};
49 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
50 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
51 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
52                                    'M','o','d','e',0};
53 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
54                                    'i','l','e','s',0};
55 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
56 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
57 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
58 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
59 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
60 static WCHAR NameW[] = {'N','a','m','e',0};
61 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0}; 
62 static WCHAR PortW[] = {'P','o','r','t',0};
63 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
64                                    's','s','o','r',0};
65 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
66                                   'v','e','r',0};
67 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
68                                   'i','l','e',0};
69 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
70 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
71
72 /******************************************************************
73  *  WINSPOOL_GetOpenedPrinterEntry
74  *  Get the first place empty in the opened printer table
75  */
76 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinterEntry()
77 {
78     int i;
79     LPOPENEDPRINTER pOpenedPrinter;
80
81     /*
82      * Create the opened printers' handle dynamic array.
83      */
84     if (!pOpenedPrinterDPA)
85     {
86         pOpenedPrinterDPA = WINSPOOL_DPA_CreateEx(10, GetProcessHeap());
87         for (i = 0; i < 10; i++)
88         {
89             pOpenedPrinter = HeapAlloc(GetProcessHeap(),
90                                        HEAP_ZERO_MEMORY,
91                                        sizeof(OPENEDPRINTER));
92             pOpenedPrinter->hPrinter = -1;
93             WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
94         }
95     }
96
97     /*
98      * Search for a handle not yet allocated.
99      */
100     for (i = 0; i < pOpenedPrinterDPA->nItemCount; i++)
101     {
102         pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, i);
103
104         if (pOpenedPrinter->hPrinter == -1)
105         {
106             pOpenedPrinter->hPrinter = i + 1;
107             return pOpenedPrinter;
108         }
109     }
110
111     /*
112      * Didn't find one, insert new element in the array.
113      */
114     if (i == pOpenedPrinterDPA->nItemCount)
115     {
116         pOpenedPrinter = HeapAlloc(GetProcessHeap(),
117                                    HEAP_ZERO_MEMORY,
118                                    sizeof(OPENEDPRINTER));
119         pOpenedPrinter->hPrinter = i + 1;
120         WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
121         return pOpenedPrinter;
122     }
123
124     return NULL;
125 }
126
127 /******************************************************************
128  *  WINSPOOL_GetOpenedPrinter
129  *  Get the pointer to the opened printer referred by the handle
130  */
131 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinter(int printerHandle)
132 {
133     LPOPENEDPRINTER pOpenedPrinter;
134
135     if(!pOpenedPrinterDPA) return NULL;
136     if((printerHandle <=0) || 
137        (printerHandle > (pOpenedPrinterDPA->nItemCount - 1)))
138         return NULL;
139
140     pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1);
141
142     return pOpenedPrinter;
143 }
144
145 /***********************************************************
146  *      DEVMODEcpyAtoW
147  */
148 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
149 {
150     BOOL Formname;
151     ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
152     DWORD size;
153
154     Formname = (dmA->dmSize > off_formname);
155     size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
156     MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
157                         CCHDEVICENAME);
158     if(!Formname) {
159       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
160              dmA->dmSize - CCHDEVICENAME);
161     } else {
162       memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
163              off_formname - CCHDEVICENAME);
164       MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
165                           CCHFORMNAME);
166       memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
167              (off_formname + CCHFORMNAME));
168     }
169     dmW->dmSize = size;
170     memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
171            dmA->dmDriverExtra);
172     return dmW;
173 }
174
175 /***********************************************************
176  *      DEVMODEdupAtoW
177  * Creates a unicode copy of supplied devmode on heap
178  */
179 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
180 {
181     LPDEVMODEW dmW;
182     DWORD size;
183     BOOL Formname;
184     ptrdiff_t off_formname;
185
186     TRACE("\n");
187     if(!dmA) return NULL;
188
189     off_formname = (char *)dmA->dmFormName - (char *)dmA;
190     Formname = (dmA->dmSize > off_formname);
191     size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
192     dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
193     return DEVMODEcpyAtoW(dmW, dmA);
194 }
195
196 /***********************************************************
197  *      DEVMODEdupWtoA
198  * Creates an ascii copy of supplied devmode on heap
199  */
200 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
201 {
202     LPDEVMODEA dmA;
203     DWORD size;
204     BOOL Formname;
205     ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
206
207     if(!dmW) return NULL;
208     Formname = (dmW->dmSize > off_formname);
209     size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
210     dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
211     WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
212                         CCHDEVICENAME, NULL, NULL);
213     if(!Formname) {
214       memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
215              dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
216     } else {
217       memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
218              off_formname - CCHDEVICENAME * sizeof(WCHAR));
219       WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
220                           CCHFORMNAME, NULL, NULL);
221       memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
222              (off_formname + CCHFORMNAME * sizeof(WCHAR)));
223     }
224     dmA->dmSize = size;
225     memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
226            dmW->dmDriverExtra);
227     return dmA;
228 }
229
230 /***********************************************************
231  *             PRINTER_INFO_2AtoW
232  * Creates a unicode copy of PRINTER_INFO_2A on heap
233  */
234 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
235 {
236     LPPRINTER_INFO_2W piW;
237     if(!piA) return NULL;
238     piW = HeapAlloc(heap, 0, sizeof(*piW));
239     memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
240     piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
241     piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
242     piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
243     piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
244     piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
245     piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
246     piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
247     piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
248     piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
249     piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
250     piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
251     piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
252     return piW;
253 }
254
255 /***********************************************************
256  *       FREE_PRINTER_INFO_2W
257  * Free PRINTER_INFO_2W and all strings
258  */
259 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
260 {
261     if(!piW) return;
262
263     HeapFree(heap,0,piW->pServerName);
264     HeapFree(heap,0,piW->pPrinterName);
265     HeapFree(heap,0,piW->pShareName);
266     HeapFree(heap,0,piW->pPortName);
267     HeapFree(heap,0,piW->pDriverName);
268     HeapFree(heap,0,piW->pComment);
269     HeapFree(heap,0,piW->pLocation);
270     HeapFree(heap,0,piW->pDevMode);
271     HeapFree(heap,0,piW->pSepFile);
272     HeapFree(heap,0,piW->pPrintProcessor);
273     HeapFree(heap,0,piW->pDatatype);
274     HeapFree(heap,0,piW->pParameters);
275     HeapFree(heap,0,piW);
276     return;
277 }
278
279 /******************************************************************
280  *              DeviceCapabilitiesA    [WINSPOOL.150 & WINSPOOL.151]
281  *
282  */
283 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
284                                LPSTR pOutput, LPDEVMODEA lpdm)
285 {
286     INT ret;
287     ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
288
289     /* If DC_PAPERSIZE map POINT16s to POINTs */
290     if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
291         POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
292         INT i;
293         memcpy(tmp, pOutput, ret * sizeof(POINT16));
294         for(i = 0; i < ret; i++)
295             CONV_POINT16TO32(tmp + i, (POINT*)pOutput + i);
296         HeapFree( GetProcessHeap(), 0, tmp );
297     }
298     return ret;
299 }
300
301
302 /*****************************************************************************
303  *          DeviceCapabilitiesW        [WINSPOOL.152]
304  *
305  * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
306  *
307  */
308 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
309                                WORD fwCapability, LPWSTR pOutput,
310                                const DEVMODEW *pDevMode)
311 {
312     LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
313     LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
314     LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
315     INT ret;
316
317     if(pOutput && (fwCapability == DC_BINNAMES ||
318                    fwCapability == DC_FILEDEPENDENCIES ||
319                    fwCapability == DC_PAPERNAMES)) {
320       /* These need A -> W translation */
321         INT size = 0, i;
322         LPSTR pOutputA;
323         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
324                                   dmA);
325         if(ret == -1)
326             return ret;
327         switch(fwCapability) {
328         case DC_BINNAMES:
329             size = 24;
330             break;
331         case DC_PAPERNAMES:
332         case DC_FILEDEPENDENCIES:
333             size = 64;
334             break;
335         }
336         pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
337         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
338                                   dmA);
339         for(i = 0; i < ret; i++)
340             MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
341                                 pOutput + (i * size), size);
342         HeapFree(GetProcessHeap(), 0, pOutputA);
343     } else {
344         ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
345                                   (LPSTR)pOutput, dmA);
346     }
347     HeapFree(GetProcessHeap(),0,pPortA);
348     HeapFree(GetProcessHeap(),0,pDeviceA);
349     HeapFree(GetProcessHeap(),0,dmA);
350     return ret;
351 }
352
353 /******************************************************************
354  *              DocumentPropertiesA   [WINSPOOL.155]
355  *
356  */
357 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
358                                 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
359                                 LPDEVMODEA pDevModeInput,DWORD fMode )
360 {
361     LPOPENEDPRINTER lpOpenedPrinter;
362     LPSTR lpName = pDeviceName;
363     LONG ret;
364
365     TRACE("(%d,%d,%s,%p,%p,%ld)\n",
366         hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
367     );
368
369     if(!pDeviceName) {
370         LPWSTR lpNameW;
371         lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
372         if(!lpOpenedPrinter) {
373             SetLastError(ERROR_INVALID_HANDLE);
374             return -1;
375         }
376         lpNameW = lpOpenedPrinter->lpsPrinterName;
377         lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
378     }
379
380     ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
381                                   pDevModeInput, NULL, fMode);
382
383     if(!pDeviceName)
384         HeapFree(GetProcessHeap(),0,lpName);
385     return ret;
386 }
387
388
389 /*****************************************************************************
390  *          DocumentPropertiesW 
391  */
392 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
393                                 LPWSTR pDeviceName,
394                                 LPDEVMODEW pDevModeOutput,
395                                 LPDEVMODEW pDevModeInput, DWORD fMode)
396 {
397
398     LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
399     LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
400     LPDEVMODEA pDevModeOutputA = NULL;
401     LONG ret;
402
403     TRACE("(%d,%d,%s,%p,%p,%ld)\n",
404           hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
405           fMode);
406     if(pDevModeOutput) {
407         ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
408         if(ret < 0) return ret;
409         pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
410     }
411     ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
412                               pDevModeInputA, fMode);
413     if(pDevModeOutput) {
414         DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
415         HeapFree(GetProcessHeap(),0,pDevModeOutputA);
416     }
417     if(fMode == 0 && ret > 0)
418         ret += (CCHDEVICENAME + CCHFORMNAME);
419     HeapFree(GetProcessHeap(),0,pDevModeInputA);
420     HeapFree(GetProcessHeap(),0,pDeviceNameA);    
421     return ret;
422 }
423
424 /******************************************************************
425  *              OpenPrinterA        [WINSPOOL.196]
426  *
427  */
428 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
429                          LPPRINTER_DEFAULTSA pDefault)
430 {
431     LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
432     PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
433     BOOL ret;
434
435     if(pDefault) {
436         DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
437                                              pDefault->pDatatype);
438         DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
439                                            pDefault->pDevMode);
440         DefaultW.DesiredAccess = pDefault->DesiredAccess;
441         pDefaultW = &DefaultW;
442     }
443     ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
444     if(pDefault) {
445         HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
446         HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
447     }
448     HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
449     return ret;
450 }
451
452 /******************************************************************
453  *              OpenPrinterW        [WINSPOOL.197]
454  *
455  */
456 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
457                          LPPRINTER_DEFAULTSW pDefault)
458 {
459     LPOPENEDPRINTER lpOpenedPrinter;
460     HKEY hkeyPrinters, hkeyPrinter;
461
462     if (!lpPrinterName) {
463        WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
464        SetLastError(ERROR_INVALID_PARAMETER);
465        return FALSE;
466     }
467
468     TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
469           pDefault);
470
471     /* Check Printer exists */
472     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
473        ERROR_SUCCESS) {
474         ERR("Can't create Printers key\n");
475         SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
476         return FALSE;
477     }
478
479     if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
480        != ERROR_SUCCESS) {
481         WARN("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
482         RegCloseKey(hkeyPrinters);
483         SetLastError(ERROR_INVALID_PARAMETER);
484         return FALSE;
485     }
486     RegCloseKey(hkeyPrinter);
487     RegCloseKey(hkeyPrinters);
488
489     if(!phPrinter) /* This seems to be what win95 does anyway */
490         return TRUE;
491
492     /* Get a place in the opened printer buffer*/
493     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntry();
494     if(!lpOpenedPrinter) {
495         ERR("Can't allocate printer slot\n");
496         SetLastError(ERROR_OUTOFMEMORY);
497         return FALSE;
498     }
499
500     /* Get the name of the printer */
501     lpOpenedPrinter->lpsPrinterName = 
502       HEAP_strdupW( GetProcessHeap(), 0, lpPrinterName );
503
504     /* Get the unique handle of the printer*/
505     *phPrinter = lpOpenedPrinter->hPrinter;
506
507     if (pDefault != NULL)
508         FIXME("Not handling pDefault\n");
509
510     return TRUE;
511 }
512
513 /******************************************************************
514  *              AddMonitorA        [WINSPOOL.107]
515  *
516  */
517 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
518 {
519     FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
520     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
521     return FALSE;
522 }
523
524 /******************************************************************
525  *              DeletePrinterDriverA        [WINSPOOL.146]
526  *
527  */
528 BOOL WINAPI
529 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
530 {
531     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
532           debugstr_a(pDriverName));
533     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
534     return FALSE;
535 }
536
537
538 /******************************************************************
539  *              DeleteMonitorA        [WINSPOOL.135]
540  *
541  */
542 BOOL WINAPI
543 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
544 {
545     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
546           debugstr_a(pMonitorName));
547     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
548     return FALSE;
549 }
550
551
552 /******************************************************************
553  *              DeletePortA        [WINSPOOL.137]
554  *
555  */
556 BOOL WINAPI
557 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
558 {
559     FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
560           debugstr_a(pPortName));
561     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
562     return FALSE;
563 }
564
565 /******************************************************************************
566  *    SetPrinterW  [WINSPOOL.214]
567  */
568 BOOL WINAPI
569 SetPrinterW(
570   HANDLE  hPrinter,
571   DWORD     Level,
572   LPBYTE    pPrinter,
573   DWORD     Command) {
574
575     FIXME("():stub\n");
576     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
577     return FALSE;
578 }
579
580 /******************************************************************************
581  *    WritePrinter  [WINSPOOL.223]
582  */
583 BOOL WINAPI
584 WritePrinter( 
585   HANDLE  hPrinter,
586   LPVOID  pBuf,
587   DWORD   cbBuf,
588   LPDWORD pcWritten) {
589
590     FIXME("():stub\n");
591     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
592     return FALSE;
593 }
594
595 /*****************************************************************************
596  *          AddFormA  [WINSPOOL.103]
597  */
598 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
599 {
600     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
601     return 1;
602 }
603
604 /*****************************************************************************
605  *          AddFormW  [WINSPOOL.104]
606  */
607 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
608 {
609     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
610     return 1;
611 }
612
613 /*****************************************************************************
614  *          AddJobA  [WINSPOOL.105]
615  */
616 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
617                         DWORD cbBuf, LPDWORD pcbNeeded)
618 {
619     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
620           pcbNeeded);
621     return 1;
622 }
623
624 /*****************************************************************************
625  *          AddJobW  [WINSPOOL.106]
626  */
627 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
628                         LPDWORD pcbNeeded)
629 {
630     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
631           pcbNeeded);
632     return 1;
633 }
634
635 /*****************************************************************************
636  *          WINSPOOL_OpenDriverReg [internal]
637  *
638  * opens the registry for the printer drivers depending on the given input
639  * variable pEnvironment
640  *
641  * RETURNS:
642  *    the opened hkey on success
643  *    NULL on error 
644  */
645 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
646 {   HKEY  retval;
647     LPSTR lpKey, p = NULL;
648
649     TRACE("%s\n",
650           (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
651
652     if(pEnvironment)
653         p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
654                         pEnvironment;
655     else {
656         OSVERSIONINFOA ver;
657         ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
658
659         if(!GetVersionExA( &ver))
660             return NULL;
661
662         switch (ver.dwPlatformId) {
663              case VER_PLATFORM_WIN32s:
664                   return NULL;
665              case VER_PLATFORM_WIN32_NT:
666                   p = "Windows NT x86";
667                   break;
668              default: 
669                   p = "Windows 4.0";
670                   break;
671         }
672         TRACE("set environment to %s\n", p);
673     }
674
675     lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
676                        strlen(p) + strlen(Drivers));
677     (void) wsprintfA( lpKey, Drivers, p);
678
679     TRACE("%s\n", lpKey);
680
681     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &retval) !=
682        ERROR_SUCCESS)
683        retval = NULL;
684
685     if(pEnvironment && unicode)
686        HeapFree( GetProcessHeap(), 0, p);
687     HeapFree( GetProcessHeap(), 0, lpKey);
688
689     return retval;
690 }
691
692 /*****************************************************************************
693  *          AddPrinterW  [WINSPOOL.122]
694  */
695 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
696 {
697     PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
698     LPDEVMODEA dmA;
699     LPDEVMODEW dmW;
700     HANDLE retval;
701     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
702     LONG size;
703
704     TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
705     
706     if(pName != NULL) {
707         FIXME("pName = %s - unsupported\n", debugstr_w(pName));
708         SetLastError(ERROR_INVALID_PARAMETER);
709         return 0;
710     }
711     if(Level != 2) {
712         WARN("Level = %ld\n", Level);
713         SetLastError(ERROR_INVALID_LEVEL);
714         return 0;
715     }
716     if(!pPrinter) {
717         SetLastError(ERROR_INVALID_PARAMETER);
718         return 0;
719     }
720     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
721        ERROR_SUCCESS) {
722         ERR("Can't create Printers key\n");
723         return 0;
724     }
725     if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
726        ERROR_SUCCESS) {
727         SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
728         RegCloseKey(hkeyPrinter);
729         RegCloseKey(hkeyPrinters);
730         return 0;
731     }
732     hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
733     if(!hkeyDrivers) {
734         ERR("Can't create Drivers key\n");
735         RegCloseKey(hkeyPrinters);
736         return 0;
737     }
738     if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) != 
739        ERROR_SUCCESS) {
740         WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
741         RegCloseKey(hkeyPrinters);
742         RegCloseKey(hkeyDrivers);
743         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
744         return 0;
745     }
746     RegCloseKey(hkeyDriver);
747     RegCloseKey(hkeyDrivers);
748
749     if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) {  /* FIXME */
750         WARN("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
751         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
752         RegCloseKey(hkeyPrinters);
753         return 0;
754     }
755
756     /* See if we can load the driver.  We may need the devmode structure anyway
757      */
758     size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
759     if(size < 0) {
760         WARN("DocumentProperties fails\n");
761         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
762         return 0;
763     }
764     if(pi->pDevMode) {
765         dmW = pi->pDevMode;
766     } else {
767         dmW = HeapAlloc(GetProcessHeap(), 0, size);
768         DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
769     }
770
771     if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
772        ERROR_SUCCESS) {
773         WARN("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
774         SetLastError(ERROR_INVALID_PRINTER_NAME);
775         RegCloseKey(hkeyPrinters);
776         if(!pi->pDevMode)
777             HeapFree(GetProcessHeap(), 0, dmW);
778         return 0;
779     }
780     RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
781                    (LPBYTE)&pi->Attributes, sizeof(DWORD));
782     RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
783                    0);
784
785     /* Write DEVMODEA not DEVMODEW into reg.  This is what win9x does
786        and we support these drivers.  NT writes DEVMODEW so somehow
787        we'll need to distinguish between these when we support NT
788        drivers */
789     dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
790     RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
791                    dmA->dmSize + dmA->dmDriverExtra);
792     HeapFree(GetProcessHeap(), 0, dmA);
793     if(!pi->pDevMode)
794         HeapFree(GetProcessHeap(), 0, dmW);
795     RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
796                    0);
797     RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
798                    0);
799     RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
800     RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
801                    (LPBYTE)pi->pParameters, 0);
802     RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
803     RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
804                    (LPBYTE)pi->pPrintProcessor, 0);
805     RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
806                    (LPBYTE)pi->pDriverName, 0);
807     RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
808                    (LPBYTE)&pi->Priority, sizeof(DWORD));
809     RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
810                    (LPBYTE)pi->pSepFile, 0);
811     RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
812                    0);
813     RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
814                    (LPBYTE)&pi->StartTime, sizeof(DWORD));
815     RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
816                    (LPBYTE)&pi->Status, sizeof(DWORD));
817     RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
818                    (LPBYTE)&pi->UntilTime, sizeof(DWORD));
819
820     RegCloseKey(hkeyPrinter);
821     RegCloseKey(hkeyPrinters);
822     if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
823         ERR("OpenPrinter failing\n");
824         return 0;
825     }
826     return retval;
827 }
828
829 /*****************************************************************************
830  *          AddPrinterA  [WINSPOOL.117]
831  */
832 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
833 {
834     WCHAR *pNameW;
835     PRINTER_INFO_2W *piW;
836     PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
837     HANDLE ret;
838
839     TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
840     if(Level != 2) {
841         WARN("Level = %ld\n", Level);
842         SetLastError(ERROR_INVALID_LEVEL);
843         return 0;
844     }
845     pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
846     piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
847
848     ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
849
850     FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
851     HeapFree(GetProcessHeap(),0,pNameW);
852     return ret;
853 }
854
855
856 /*****************************************************************************
857  *          ClosePrinter  [WINSPOOL.126]
858  */
859 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
860 {
861     LPOPENEDPRINTER lpOpenedPrinter;
862
863     TRACE("Handle %d\n", hPrinter);
864
865     if (!pOpenedPrinterDPA)
866         return FALSE;
867
868     if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1)))
869     {
870         lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
871         HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
872         lpOpenedPrinter->lpsPrinterName = NULL;
873         lpOpenedPrinter->hPrinter = -1;
874
875         return TRUE;
876     }
877     return FALSE;
878 }
879
880 /*****************************************************************************
881  *          DeleteFormA  [WINSPOOL.133]
882  */
883 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
884 {
885     FIXME("(%d,%s): stub\n", hPrinter, pFormName);
886     return 1;
887 }
888
889 /*****************************************************************************
890  *          DeleteFormW  [WINSPOOL.134]
891  */
892 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
893 {
894     FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
895     return 1;
896 }
897
898 /*****************************************************************************
899  *          DeletePrinter  [WINSPOOL.143]
900  */
901 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
902 {
903     LPWSTR lpNameW;
904     HKEY hkeyPrinters;
905
906     LPOPENEDPRINTER lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
907     if(!lpOpenedPrinter) {
908         SetLastError(ERROR_INVALID_HANDLE);
909         return FALSE;
910     }
911     lpNameW = lpOpenedPrinter->lpsPrinterName;
912     if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
913        ERROR_SUCCESS) {
914         ERR("Can't open Printers key\n");
915         return 0;
916     }
917
918     /* This should use a recursive delete see Q142491 or SHDeleteKey */
919     if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
920         SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
921         RegCloseKey(hkeyPrinters);
922         return 0;
923     }    
924
925     ClosePrinter(hPrinter);
926     return TRUE;
927 }
928
929 /*****************************************************************************
930  *          SetPrinterA  [WINSPOOL.211]
931  */
932 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
933                            DWORD Command)
934 {
935     FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
936     return FALSE;
937 }
938
939 /*****************************************************************************
940  *          SetJobA  [WINSPOOL.209]
941  */
942 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
943                        LPBYTE pJob, DWORD Command)
944 {
945     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
946          Command);
947     return FALSE;
948 }
949
950 /*****************************************************************************
951  *          SetJobW  [WINSPOOL.210]
952  */
953 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
954                        LPBYTE pJob, DWORD Command)
955 {
956     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
957          Command);
958     return FALSE;
959 }
960
961 /*****************************************************************************
962  *          GetFormA  [WINSPOOL.181]
963  */
964 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
965                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
966 {
967     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
968          Level,pForm,cbBuf,pcbNeeded); 
969     return FALSE;
970 }
971
972 /*****************************************************************************
973  *          GetFormW  [WINSPOOL.182]
974  */
975 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
976                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
977 {
978     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
979           debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
980     return FALSE;
981 }
982
983 /*****************************************************************************
984  *          SetFormA  [WINSPOOL.207]
985  */
986 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
987                         LPBYTE pForm)
988 {
989     FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
990     return FALSE;
991 }
992
993 /*****************************************************************************
994  *          SetFormW  [WINSPOOL.208]
995  */
996 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
997                         LPBYTE pForm)
998 {
999     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1000     return FALSE;
1001 }
1002
1003 /*****************************************************************************
1004  *          ReadPrinter  [WINSPOOL.202]
1005  */
1006 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1007                            LPDWORD pNoBytesRead)
1008 {
1009     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1010     return FALSE;
1011 }
1012
1013 /*****************************************************************************
1014  *          ResetPrinterA  [WINSPOOL.203]
1015  */
1016 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1017 {
1018     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1019     return FALSE;
1020 }
1021
1022 /*****************************************************************************
1023  *          ResetPrinterW  [WINSPOOL.204]
1024  */
1025 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1026 {
1027     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1028     return FALSE;
1029 }
1030
1031 /*****************************************************************************
1032  *    WINSPOOL_GetDWORDFromReg
1033  *
1034  * Return DWORD associated with ValueName from hkey.
1035  */ 
1036 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1037 {
1038     DWORD sz = sizeof(DWORD), type, value = 0;
1039     LONG ret;
1040
1041     ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1042
1043     if(ret != ERROR_SUCCESS) {
1044         WARN("Got ret = %ld on name %s\n", ret, ValueName);
1045         return 0;
1046     }
1047     if(type != REG_DWORD) {
1048         ERR("Got type %ld\n", type);
1049         return 0;
1050     }
1051     return value;
1052 }
1053
1054 /*****************************************************************************
1055  *    WINSPOOL_GetStringFromReg
1056  *
1057  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1058  * String is stored either as unicode or ascii.
1059  * Bit of a hack here to get the ValueName if we want ascii.
1060  */ 
1061 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1062                                       DWORD buflen, DWORD *needed,
1063                                       BOOL unicode)
1064 {
1065     DWORD sz = buflen, type;
1066     LONG ret;
1067
1068     if(unicode)
1069         ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1070     else {
1071         LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1072         ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1073         HeapFree(GetProcessHeap(),0,ValueNameA);
1074     }
1075     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1076         WARN("Got ret = %ld\n", ret);
1077         *needed = 0;
1078         return FALSE;
1079     }
1080     *needed = sz;
1081     return TRUE;
1082 }
1083
1084 /*****************************************************************************
1085  *    WINSPOOL_GetDevModeFromReg
1086  *
1087  * Get ValueName from hkey storing result in ptr.  buflen is space left in ptr
1088  * DevMode is stored either as unicode or ascii.
1089  */ 
1090 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1091                                        LPBYTE ptr,
1092                                        DWORD buflen, DWORD *needed,
1093                                        BOOL unicode)
1094 {
1095     DWORD sz = buflen, type;
1096     LONG ret;
1097
1098     if (ptr) memset(ptr, 0, sizeof(DEVMODEA));
1099     ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1100     if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1101     if (sz < sizeof(DEVMODEA))
1102     {
1103         ERR("corrupted registry for %s\n", debugstr_w(ValueName));
1104         sz = sizeof(DEVMODEA);
1105     }
1106     /* ensures that dmSize is not erratically bogus if registry is invalid */
1107     if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1108         ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1109     if(unicode) {
1110         sz += (CCHDEVICENAME + CCHFORMNAME);
1111         if(buflen >= sz) {
1112             DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1113             memcpy(ptr, dmW, sz);
1114             HeapFree(GetProcessHeap(),0,dmW);
1115         }
1116     }
1117     *needed = sz;
1118     return TRUE;
1119 }
1120
1121 /*********************************************************************
1122  *    WINSPOOL_GetPrinter_2
1123  *
1124  * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1125  * The strings are either stored as unicode or ascii.
1126  */
1127 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1128                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1129                                   BOOL unicode)
1130 {
1131     DWORD size, left = cbBuf;
1132     BOOL space = (cbBuf > 0);
1133     LPBYTE ptr = buf;
1134
1135     *pcbNeeded = 0;
1136
1137     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1138                                  unicode)) {
1139         if(space && size <= left) {
1140             pi2->pPrinterName = (LPWSTR)ptr;
1141             ptr += size;
1142             left -= size;
1143         } else
1144             space = FALSE;
1145         *pcbNeeded += size;
1146     }
1147     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1148                                  unicode)) {
1149         if(space && size <= left) {
1150             pi2->pShareName = (LPWSTR)ptr;
1151             ptr += size;
1152             left -= size;
1153         } else
1154             space = FALSE;
1155         *pcbNeeded += size;
1156     }
1157     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1158                                  unicode)) {
1159         if(space && size <= left) {
1160             pi2->pPortName = (LPWSTR)ptr;
1161             ptr += size;
1162             left -= size;
1163         } else
1164             space = FALSE;
1165         *pcbNeeded += size;
1166     }
1167     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1168                                  &size, unicode)) {
1169         if(space && size <= left) {
1170             pi2->pDriverName = (LPWSTR)ptr;
1171             ptr += size;
1172             left -= size;
1173         } else
1174             space = FALSE;
1175         *pcbNeeded += size;
1176     }
1177     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1178                                  unicode)) {
1179         if(space && size <= left) {
1180             pi2->pComment = (LPWSTR)ptr;
1181             ptr += size;
1182             left -= size;
1183         } else
1184             space = FALSE;
1185         *pcbNeeded += size;
1186     }
1187     if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1188                                  unicode)) {
1189         if(space && size <= left) {
1190             pi2->pLocation = (LPWSTR)ptr;
1191             ptr += size;
1192             left -= size;
1193         } else
1194             space = FALSE;
1195         *pcbNeeded += size;
1196     }
1197     if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1198                                   &size, unicode)) {
1199         if(space && size <= left) {
1200             pi2->pDevMode = (LPDEVMODEW)ptr;
1201             ptr += size;
1202             left -= size;
1203         } else
1204             space = FALSE;
1205         *pcbNeeded += size;
1206     }
1207     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1208                                  &size, unicode)) {
1209         if(space && size <= left) {
1210             pi2->pSepFile = (LPWSTR)ptr;
1211             ptr += size;
1212             left -= size;
1213         } else
1214             space = FALSE;
1215         *pcbNeeded += size;
1216     }
1217     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1218                                  &size, unicode)) {
1219         if(space && size <= left) {
1220             pi2->pPrintProcessor = (LPWSTR)ptr;
1221             ptr += size;
1222             left -= size;
1223         } else
1224             space = FALSE;
1225         *pcbNeeded += size;
1226     }
1227     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1228                                  &size, unicode)) {
1229         if(space && size <= left) {
1230             pi2->pDatatype = (LPWSTR)ptr;
1231             ptr += size;
1232             left -= size;
1233         } else
1234             space = FALSE;
1235         *pcbNeeded += size;
1236     }
1237     if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1238                                  &size, unicode)) {
1239         if(space && size <= left) {
1240             pi2->pParameters = (LPWSTR)ptr;
1241             ptr += size;
1242             left -= size;
1243         } else
1244             space = FALSE;
1245         *pcbNeeded += size;
1246     }
1247     if(pi2) {
1248         pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes"); 
1249         pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1250         pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1251                                                         "Default Priority");
1252         pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1253         pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1254     }
1255
1256     if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1257         memset(pi2, 0, sizeof(*pi2));
1258
1259     return space;
1260 }
1261
1262 /*********************************************************************
1263  *    WINSPOOL_GetPrinter_4
1264  *
1265  * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1266  */
1267 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1268                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1269                                   BOOL unicode)
1270 {
1271     DWORD size, left = cbBuf;
1272     BOOL space = (cbBuf > 0);
1273     LPBYTE ptr = buf;
1274
1275     *pcbNeeded = 0;
1276
1277     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1278                                  unicode)) {
1279         if(space && size <= left) {
1280             pi4->pPrinterName = (LPWSTR)ptr;
1281             ptr += size;
1282             left -= size;
1283         } else
1284             space = FALSE;
1285         *pcbNeeded += size;
1286     }
1287     if(pi4) {
1288         pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes"); 
1289     }
1290
1291     if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1292         memset(pi4, 0, sizeof(*pi4));
1293
1294     return space;
1295 }
1296
1297 /*********************************************************************
1298  *    WINSPOOL_GetPrinter_5
1299  *
1300  * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1301  */
1302 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1303                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1304                                   BOOL unicode)
1305 {
1306     DWORD size, left = cbBuf;
1307     BOOL space = (cbBuf > 0);
1308     LPBYTE ptr = buf;
1309
1310     *pcbNeeded = 0;
1311
1312     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1313                                  unicode)) {
1314         if(space && size <= left) {
1315             pi5->pPrinterName = (LPWSTR)ptr;
1316             ptr += size;
1317             left -= size;
1318         } else
1319             space = FALSE;
1320         *pcbNeeded += size;
1321     }
1322     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1323                                  unicode)) {
1324         if(space && size <= left) {
1325             pi5->pPortName = (LPWSTR)ptr;
1326             ptr += size;
1327             left -= size;
1328         } else
1329             space = FALSE;
1330         *pcbNeeded += size;
1331     }
1332     if(pi5) {
1333         pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes"); 
1334         pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1335                                                                 "dnsTimeout"); 
1336         pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1337                                                                  "txTimeout"); 
1338     }
1339
1340     if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1341         memset(pi5, 0, sizeof(*pi5));
1342
1343     return space;
1344 }
1345
1346 /*****************************************************************************
1347  *          WINSPOOL_GetPrinter
1348  *
1349  *    Implementation of GetPrinterA|W.  Relies on PRINTER_INFO_*W being
1350  *    essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1351  *    just a collection of pointers to strings.
1352  */
1353 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1354                                 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1355 {
1356     OPENEDPRINTER *lpOpenedPrinter;
1357     DWORD size, needed = 0;
1358     LPBYTE ptr = NULL;
1359     HKEY hkeyPrinter, hkeyPrinters;
1360     BOOL ret;
1361
1362     TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1363
1364     lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1365     if(!lpOpenedPrinter) {
1366         SetLastError(ERROR_INVALID_HANDLE);
1367         return FALSE;
1368     }
1369     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1370        ERROR_SUCCESS) {
1371         ERR("Can't create Printers key\n");
1372         return FALSE;
1373     }
1374     if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1375        != ERROR_SUCCESS) {
1376         ERR("Can't find opened printer %s in registry\n",
1377             debugstr_w(lpOpenedPrinter->lpsPrinterName));
1378         RegCloseKey(hkeyPrinters);
1379         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1380         return FALSE;
1381     }
1382
1383     switch(Level) {
1384     case 2:
1385       {
1386         PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1387
1388         size = sizeof(PRINTER_INFO_2W);
1389         if(size <= cbBuf) {
1390             ptr = pPrinter + size;
1391             cbBuf -= size;
1392             memset(pPrinter, 0, size);
1393         } else {
1394             pi2 = NULL;
1395             cbBuf = 0;
1396         }
1397         ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1398                                     unicode);
1399         needed += size;
1400         break;
1401       }
1402       
1403     case 4:
1404       {
1405         PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1406         
1407         size = sizeof(PRINTER_INFO_4W);
1408         if(size <= cbBuf) {
1409             ptr = pPrinter + size;
1410             cbBuf -= size;
1411             memset(pPrinter, 0, size);
1412         } else {
1413             pi4 = NULL;
1414             cbBuf = 0;
1415         }
1416         ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1417                                     unicode);
1418         needed += size;
1419         break;
1420       }
1421
1422
1423     case 5:
1424       {
1425         PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1426
1427         size = sizeof(PRINTER_INFO_5W);
1428         if(size <= cbBuf) {
1429             ptr = pPrinter + size;
1430             cbBuf -= size;
1431             memset(pPrinter, 0, size);
1432         } else {
1433             pi5 = NULL;
1434             cbBuf = 0;
1435         }
1436
1437         ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1438                                     unicode);
1439         needed += size;
1440         break;
1441       }
1442
1443     default:
1444         FIXME("Unimplemented level %ld\n", Level);
1445         SetLastError(ERROR_INVALID_LEVEL);
1446         RegCloseKey(hkeyPrinters);
1447         RegCloseKey(hkeyPrinter);
1448         return FALSE;
1449     }
1450
1451     RegCloseKey(hkeyPrinter);
1452     RegCloseKey(hkeyPrinters);
1453
1454     TRACE("returing %d needed = %ld\n", ret, needed);
1455     if(pcbNeeded) *pcbNeeded = needed;
1456     if(!ret)
1457         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1458     return ret;
1459 }
1460
1461 /*****************************************************************************
1462  *          GetPrinterW  [WINSPOOL.194]
1463  */
1464 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1465                         DWORD cbBuf, LPDWORD pcbNeeded)
1466 {
1467     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1468                                TRUE);
1469 }
1470
1471 /*****************************************************************************
1472  *          GetPrinterA  [WINSPOOL.187]
1473  */
1474 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1475                     DWORD cbBuf, LPDWORD pcbNeeded)
1476 {
1477     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1478                                FALSE);
1479 }
1480
1481 /*****************************************************************************
1482  *          WINSPOOL_EnumPrinters
1483  *
1484  *    Implementation of EnumPrintersA|W
1485  */
1486 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1487                                   DWORD dwLevel, LPBYTE lpbPrinters,
1488                                   DWORD cbBuf, LPDWORD lpdwNeeded,
1489                                   LPDWORD lpdwReturned, BOOL unicode)
1490
1491 {
1492     HKEY hkeyPrinters, hkeyPrinter;
1493     WCHAR PrinterName[255];
1494     DWORD needed = 0, number = 0;
1495     DWORD used, i, left;
1496     PBYTE pi, buf;
1497
1498     if(lpbPrinters)
1499         memset(lpbPrinters, 0, cbBuf);
1500     if(lpdwReturned)
1501         *lpdwReturned = 0;
1502
1503     if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1504         FIXME("dwType = %08lx\n", dwType);
1505         SetLastError(ERROR_INVALID_FLAGS);
1506         return FALSE;
1507     }
1508
1509     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1510        ERROR_SUCCESS) {
1511         ERR("Can't create Printers key\n");
1512         return FALSE;
1513     }
1514   
1515     if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1516                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1517         RegCloseKey(hkeyPrinters);
1518         ERR("Can't query Printers key\n");
1519         return FALSE;
1520     }
1521     TRACE("Found %ld printers\n", number);
1522
1523     switch(dwLevel) {
1524     case 1:
1525         RegCloseKey(hkeyPrinters);
1526         if (lpdwReturned)
1527             *lpdwReturned = number;
1528         return TRUE;
1529
1530     case 2:
1531         used = number * sizeof(PRINTER_INFO_2W);
1532         break;
1533     case 4:
1534         used = number * sizeof(PRINTER_INFO_4W);
1535         break;
1536     case 5:
1537         used = number * sizeof(PRINTER_INFO_5W);
1538         break;
1539
1540     default:
1541         SetLastError(ERROR_INVALID_LEVEL);
1542         RegCloseKey(hkeyPrinters);
1543         return FALSE;
1544     }
1545     pi = (used <= cbBuf) ? lpbPrinters : NULL;
1546
1547     for(i = 0; i < number; i++) {
1548         if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) != 
1549            ERROR_SUCCESS) {
1550             ERR("Can't enum key number %ld\n", i);
1551             RegCloseKey(hkeyPrinters);
1552             return FALSE;
1553         }
1554         TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1555         if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1556            ERROR_SUCCESS) {
1557             ERR("Can't open key %s\n", debugstr_w(PrinterName));
1558             RegCloseKey(hkeyPrinters);
1559             return FALSE;
1560         }
1561
1562         if(cbBuf > used) {
1563             buf = lpbPrinters + used;
1564             left = cbBuf - used;
1565         } else {
1566             buf = NULL;
1567             left = 0;
1568         }
1569
1570         switch(dwLevel) {
1571         case 2:
1572             WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1573                                   left, &needed, unicode);
1574             used += needed;
1575             if(pi) pi += sizeof(PRINTER_INFO_2W);
1576             break;
1577         case 4:
1578             WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1579                                   left, &needed, unicode);
1580             used += needed;
1581             if(pi) pi += sizeof(PRINTER_INFO_4W);
1582             break;
1583         case 5:
1584             WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1585                                   left, &needed, unicode);
1586             used += needed;
1587             if(pi) pi += sizeof(PRINTER_INFO_5W);
1588             break;
1589         default:
1590             ERR("Shouldn't be here!\n");
1591             RegCloseKey(hkeyPrinter);
1592             RegCloseKey(hkeyPrinters);
1593             return FALSE;
1594         }
1595         RegCloseKey(hkeyPrinter);
1596     }
1597     RegCloseKey(hkeyPrinters);
1598
1599     if(lpdwNeeded)
1600         *lpdwNeeded = used;
1601
1602     if(used > cbBuf) {
1603         if(lpbPrinters)
1604             memset(lpbPrinters, 0, cbBuf);
1605         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1606         return FALSE;
1607     }
1608     if(lpdwReturned)
1609         *lpdwReturned = number;  
1610     SetLastError(ERROR_SUCCESS);
1611     return TRUE;
1612 }
1613
1614
1615 /******************************************************************
1616  *              EnumPrintersW        [WINSPOOL.175]
1617  *
1618  *    Enumerates the available printers, print servers and print
1619  *    providers, depending on the specified flags, name and level.
1620  *
1621  * RETURNS:
1622  *
1623  *    If level is set to 1:
1624  *      Not implemented yet! 
1625  *      Returns TRUE with an empty list.
1626  *
1627  *    If level is set to 2:
1628  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1629  *      Returns an array of PRINTER_INFO_2 data structures in the 
1630  *      lpbPrinters buffer. Note that according to MSDN also an 
1631  *      OpenPrinter should be performed on every remote printer.
1632  *
1633  *    If level is set to 4 (officially WinNT only):
1634  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1635  *      Fast: Only the registry is queried to retrieve printer names,
1636  *      no connection to the driver is made.
1637  *      Returns an array of PRINTER_INFO_4 data structures in the 
1638  *      lpbPrinters buffer.
1639  *
1640  *    If level is set to 5 (officially WinNT4/Win9x only):
1641  *      Fast: Only the registry is queried to retrieve printer names,
1642  *      no connection to the driver is made.
1643  *      Returns an array of PRINTER_INFO_5 data structures in the 
1644  *      lpbPrinters buffer.
1645  *
1646  *    If level set to 3 or 6+:
1647  *          returns zero (faillure!)
1648  *      
1649  *    Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
1650  *    for information.
1651  *
1652  * BUGS:
1653  *    - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1654  *    - Only levels 2, 4 and 5 are implemented at the moment.
1655  *    - 16-bit printer drivers are not enumerated.
1656  *    - Returned amount of bytes used/needed does not match the real Windoze 
1657  *      implementation (as in this implementation, all strings are part 
1658  *      of the buffer, whereas Win32 keeps them somewhere else)
1659  *    - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1660  *
1661  * NOTE:
1662  *    - In a regular Wine installation, no registry settings for printers
1663  *      exist, which makes this function return an empty list.
1664  */
1665 BOOL  WINAPI EnumPrintersW(
1666                 DWORD dwType,        /* Types of print objects to enumerate */
1667                 LPWSTR lpszName,     /* name of objects to enumerate */
1668                 DWORD dwLevel,       /* type of printer info structure */
1669                 LPBYTE lpbPrinters,  /* buffer which receives info */
1670                 DWORD cbBuf,         /* max size of buffer in bytes */
1671                 LPDWORD lpdwNeeded,  /* pointer to var: # bytes used/needed */
1672                 LPDWORD lpdwReturned /* number of entries returned */
1673                 )
1674 {
1675     return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1676                                  lpdwNeeded, lpdwReturned, TRUE);
1677 }
1678
1679 /******************************************************************
1680  *              EnumPrintersA        [WINSPOOL.174]
1681  *
1682  */
1683 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1684                           DWORD dwLevel, LPBYTE lpbPrinters,
1685                           DWORD cbBuf, LPDWORD lpdwNeeded,
1686                           LPDWORD lpdwReturned)
1687 {
1688     BOOL ret;
1689     LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1690
1691     ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1692                                 lpdwNeeded, lpdwReturned, FALSE);
1693     HeapFree(GetProcessHeap(),0,lpszNameW);
1694     return ret;
1695 }
1696
1697 /*****************************************************************************
1698  *          WINSPOOL_GetDriverInfoFromReg [internal]
1699  *
1700  *    Enters the information from the registry into the DRIVER_INFO struct
1701  *
1702  * RETURNS
1703  *    zero if the printer driver does not exist in the registry
1704  *    (only if Level > 1) otherwise nonzero
1705  */
1706 static BOOL WINSPOOL_GetDriverInfoFromReg(
1707                             HKEY    hkeyDrivers,
1708                             LPWSTR  DriverName,
1709                             LPWSTR  pEnvironment,
1710                             DWORD   Level,
1711                             LPBYTE  ptr,            /* DRIVER_INFO */
1712                             LPBYTE  pDriverStrings, /* strings buffer */
1713                             DWORD   cbBuf,          /* size of string buffer */
1714                             LPDWORD pcbNeeded,      /* space needed for str. */
1715                             BOOL    unicode)        /* type of strings */
1716 {   DWORD  dw, size, type;
1717     HKEY   hkeyDriver;
1718     LPBYTE strPtr = pDriverStrings;
1719
1720     TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1721           debugstr_w(DriverName), debugstr_w(pEnvironment),
1722           Level, ptr, pDriverStrings, cbBuf, unicode);
1723
1724     if(unicode) {
1725         *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1726             if (*pcbNeeded <= cbBuf)
1727                strcpyW((LPWSTR)strPtr, DriverName);
1728     } else {
1729         *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1730                                           NULL, NULL);
1731         if(*pcbNeeded <= cbBuf)
1732             WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1733                                 NULL, NULL);
1734     }
1735     if(Level == 1) {
1736        if(ptr)
1737           ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1738        return TRUE;
1739     } else {
1740        if(ptr)
1741           ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
1742        strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1743     }
1744
1745     if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
1746         ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1747         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1748         return FALSE;
1749     }
1750
1751     size = sizeof(dw);
1752     if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
1753         ERROR_SUCCESS)
1754          WARN("Can't get Version\n");
1755     else if(ptr)
1756          ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
1757
1758     if(!pEnvironment)
1759         pEnvironment = DefaultEnvironmentW;
1760     if(unicode)
1761         size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1762     else
1763         size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1764                                    NULL, NULL);
1765     *pcbNeeded += size;
1766     if(*pcbNeeded <= cbBuf) {
1767         if(unicode)
1768             strcpyW((LPWSTR)strPtr, pEnvironment);
1769         else
1770             WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
1771                                 NULL, NULL);
1772         if(ptr)
1773             ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
1774         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1775     }
1776
1777     if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
1778                                  unicode)) {
1779         *pcbNeeded += size;
1780         if(*pcbNeeded <= cbBuf)
1781             WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, cbBuf, &size,
1782                                       unicode);
1783         if(ptr)
1784             ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
1785         strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1786     }
1787
1788     if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
1789                                  unicode)) {
1790         *pcbNeeded += size;
1791         if(*pcbNeeded <= cbBuf)
1792             WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, cbBuf,
1793                                       &size, unicode);
1794         if(ptr)
1795             ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
1796         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1797     }
1798
1799     if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1800                                  cbBuf, &size, unicode)) {
1801         *pcbNeeded += size;
1802         if(*pcbNeeded <= cbBuf)
1803             WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1804                                       cbBuf, &size, unicode);
1805         if(ptr)
1806             ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
1807         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1808     }
1809
1810     if(Level == 2 ) {
1811         RegCloseKey(hkeyDriver);
1812         return TRUE;
1813     }
1814
1815     if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
1816                                  unicode)) {
1817         *pcbNeeded += size;
1818         if(*pcbNeeded <= cbBuf)
1819             WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
1820                                       cbBuf, &size, unicode);
1821         if(ptr)
1822             ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
1823         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1824     }
1825
1826     if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
1827                              &size, unicode)) {
1828         *pcbNeeded += size;
1829         if(*pcbNeeded <= cbBuf)
1830             WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
1831                                       cbBuf, &size, unicode);
1832         if(ptr)
1833             ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
1834         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1835     }
1836
1837     if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
1838                                  unicode)) {
1839         *pcbNeeded += size;
1840         if(*pcbNeeded <= cbBuf)
1841             WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1842                                       cbBuf, &size, unicode);
1843         if(ptr)
1844             ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
1845         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1846     }
1847
1848     if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
1849                                  unicode)) {
1850         *pcbNeeded += size;
1851         if(*pcbNeeded <= cbBuf)
1852             WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1853                                       cbBuf, &size, unicode);
1854         if(ptr)
1855             ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
1856         strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1857     }
1858
1859     RegCloseKey(hkeyDriver);
1860     return TRUE;
1861 }
1862
1863 /*****************************************************************************
1864  *          WINSPOOL_GetPrinterDriver
1865  */
1866 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1867                                       DWORD Level, LPBYTE pDriverInfo,
1868                                       DWORD cbBuf, LPDWORD pcbNeeded,
1869                                       BOOL unicode)
1870 {
1871     OPENEDPRINTER *lpOpenedPrinter;
1872     WCHAR DriverName[100];
1873     DWORD ret, type, size, needed = 0;
1874     LPBYTE ptr = NULL;
1875     HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
1876     
1877     TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1878           Level,pDriverInfo,cbBuf, pcbNeeded);
1879
1880     ZeroMemory(pDriverInfo, cbBuf);
1881
1882     lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1883     if(!lpOpenedPrinter) {
1884         SetLastError(ERROR_INVALID_HANDLE);
1885         return FALSE;
1886     }
1887     if(Level < 1 || Level > 3) {
1888         SetLastError(ERROR_INVALID_LEVEL);
1889         return FALSE;
1890     }
1891     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1892        ERROR_SUCCESS) {
1893         ERR("Can't create Printers key\n");
1894         return FALSE;
1895     }
1896     if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1897        != ERROR_SUCCESS) {
1898         ERR("Can't find opened printer %s in registry\n",
1899             debugstr_w(lpOpenedPrinter->lpsPrinterName));
1900         RegCloseKey(hkeyPrinters);
1901         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1902         return FALSE;
1903     }
1904     size = sizeof(DriverName);
1905     ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1906                            (LPBYTE)DriverName, &size);
1907     RegCloseKey(hkeyPrinter);
1908     RegCloseKey(hkeyPrinters);
1909     if(ret != ERROR_SUCCESS) {
1910         ERR("Can't get DriverName for printer %s\n",
1911             debugstr_w(lpOpenedPrinter->lpsPrinterName));
1912         return FALSE;
1913     }
1914
1915     hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
1916     if(!hkeyDrivers) {
1917         ERR("Can't create Drivers key\n");
1918         return FALSE;
1919     }
1920
1921     switch(Level) {
1922     case 1:
1923         size = sizeof(DRIVER_INFO_1W);
1924         break;
1925     case 2:
1926         size = sizeof(DRIVER_INFO_2W);
1927         break;
1928     case 3:
1929         size = sizeof(DRIVER_INFO_3W);
1930         break;
1931     default:
1932         ERR("Invalid level\n");
1933         return FALSE;
1934     }
1935
1936     if(size <= cbBuf)
1937         ptr = pDriverInfo + size;
1938
1939     if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
1940                          pEnvironment, Level, pDriverInfo,
1941                          (cbBuf < size) ? NULL : ptr,
1942                          (cbBuf < size) ? 0 : cbBuf - size,
1943                          &needed, unicode)) {
1944             RegCloseKey(hkeyDrivers);
1945             return FALSE;
1946     }
1947
1948     RegCloseKey(hkeyDrivers);
1949
1950     if(pcbNeeded) *pcbNeeded = needed;
1951     if(cbBuf >= needed) return TRUE;
1952     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1953     return FALSE;
1954 }
1955
1956 /*****************************************************************************
1957  *          GetPrinterDriverA  [WINSPOOL.190]
1958  */
1959 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1960                               DWORD Level, LPBYTE pDriverInfo,
1961                               DWORD cbBuf, LPDWORD pcbNeeded)
1962 {
1963     BOOL ret;
1964     LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
1965     ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
1966                                     cbBuf, pcbNeeded, FALSE);
1967     HeapFree(GetProcessHeap(),0,pEnvW);
1968     return ret;
1969 }
1970 /*****************************************************************************
1971  *          GetPrinterDriverW  [WINSPOOL.193]
1972  */
1973 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1974                                   DWORD Level, LPBYTE pDriverInfo, 
1975                                   DWORD cbBuf, LPDWORD pcbNeeded)
1976 {
1977     return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
1978                                      pDriverInfo, cbBuf, pcbNeeded, TRUE);
1979 }
1980
1981 /*****************************************************************************
1982  *       GetPrinterDriverDirectoryA  [WINSPOOL.191]
1983  */
1984 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1985                                        DWORD Level, LPBYTE pDriverDirectory,
1986                                        DWORD cbBuf, LPDWORD pcbNeeded)
1987 {
1988     DWORD needed;
1989
1990     TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1991           pDriverDirectory, cbBuf, pcbNeeded);
1992     if(pName != NULL) {
1993         FIXME("pName = `%s' - unsupported\n", pName);
1994         SetLastError(ERROR_INVALID_PARAMETER);
1995         return FALSE;
1996     }
1997     if(pEnvironment != NULL) {
1998         FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1999         SetLastError(ERROR_INVALID_ENVIRONMENT);
2000         return FALSE;
2001     }
2002     if(Level != 1)  /* win95 ignores this so we just carry on */
2003         WARN("Level = %ld - assuming 1\n", Level);
2004     
2005     /* FIXME should read from registry */
2006     needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2007     needed++;
2008     if(pcbNeeded)
2009         *pcbNeeded = needed;
2010     if(needed > cbBuf) {
2011         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2012         return FALSE;
2013     }
2014     return TRUE;
2015 }
2016
2017
2018 /*****************************************************************************
2019  *       GetPrinterDriverDirectoryW  [WINSPOOL.192]
2020  */
2021 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2022                                        DWORD Level, LPBYTE pDriverDirectory,
2023                                        DWORD cbBuf, LPDWORD pcbNeeded)
2024 {
2025     LPSTR pNameA = NULL, pEnvironmentA = NULL;
2026     BOOL ret;
2027
2028     if(pName)
2029         pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2030     if(pEnvironment)
2031         pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2032     ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2033                                       pDriverDirectory, cbBuf, pcbNeeded );
2034     if(pNameA)
2035         HeapFree( GetProcessHeap(), 0, pNameA );
2036     if(pEnvironmentA)
2037         HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2038
2039     return ret;
2040 }
2041
2042 /*****************************************************************************
2043  *          AddPrinterDriverA  [WINSPOOL.120]
2044  */
2045 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2046 {
2047     DRIVER_INFO_3A di3;
2048     HKEY hkeyDrivers, hkeyName;
2049
2050     TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2051
2052     if(level != 2 && level != 3) {
2053         SetLastError(ERROR_INVALID_LEVEL);
2054         return FALSE;
2055     }
2056     if(pName != NULL) {
2057         FIXME("pName= `%s' - unsupported\n", pName);
2058         SetLastError(ERROR_INVALID_PARAMETER);
2059         return FALSE;
2060     }
2061     if(!pDriverInfo) {
2062         WARN("pDriverInfo == NULL");
2063         SetLastError(ERROR_INVALID_PARAMETER);
2064         return FALSE;
2065     }
2066     
2067     if(level == 3)
2068         di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2069     else {
2070         memset(&di3, 0, sizeof(di3));
2071         *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2072     }
2073
2074     if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2075        !di3.pDataFile) {
2076         SetLastError(ERROR_INVALID_PARAMETER);
2077         return FALSE;
2078     }
2079     if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2080     if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2081     if(!di3.pHelpFile) di3.pHelpFile = "";
2082     if(!di3.pMonitorName) di3.pMonitorName = "";
2083
2084     hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2085
2086     if(!hkeyDrivers) {
2087         ERR("Can't create Drivers key\n");
2088         return FALSE;
2089     }
2090
2091     if(level == 2) { /* apparently can't overwrite with level2 */
2092         if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2093             RegCloseKey(hkeyName);
2094             RegCloseKey(hkeyDrivers);
2095             WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2096             SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2097             return FALSE;
2098         }
2099     }
2100     if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2101         RegCloseKey(hkeyDrivers);
2102         ERR("Can't create Name key\n");
2103         return FALSE;
2104     }
2105     RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2106                    0);
2107     RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2108     RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2109     RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion, 
2110                    sizeof(DWORD));
2111     RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2112     RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2113                    di3.pDependentFiles, 0);
2114     RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2115     RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2116     RegCloseKey(hkeyName);
2117     RegCloseKey(hkeyDrivers);
2118
2119     return TRUE;
2120 }
2121 /*****************************************************************************
2122  *          AddPrinterDriverW  [WINSPOOL.121]
2123  */
2124 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level, 
2125                                    LPBYTE pDriverInfo)
2126 {
2127     FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2128           level,pDriverInfo);
2129     return FALSE;
2130 }
2131
2132
2133 /*****************************************************************************
2134  *          PrinterProperties  [WINSPOOL.201]
2135  *
2136  *     Displays a dialog to set the properties of the printer.
2137  *
2138  * RETURNS 
2139  *     nonzero on succes or zero on faillure
2140  *
2141  * BUGS
2142  *         implemented as stub only
2143  */
2144 BOOL WINAPI PrinterProperties(HWND hWnd,      /* handle to parent window */
2145                               HANDLE hPrinter /* handle to printer object */
2146 ){
2147     FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2148     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2149     return FALSE;
2150 }
2151
2152 /*****************************************************************************
2153  *          EnumJobsA [WINSPOOL.162]
2154  *
2155  */
2156 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2157                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2158                       LPDWORD pcReturned)
2159 {
2160     FIXME("stub\n");
2161     if(pcbNeeded) *pcbNeeded = 0;
2162     if(pcReturned) *pcReturned = 0;
2163     return TRUE;
2164 }
2165
2166
2167 /*****************************************************************************
2168  *          EnumJobsW [WINSPOOL.163]
2169  *
2170  */
2171 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2172                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2173                       LPDWORD pcReturned)
2174 {
2175     FIXME("stub\n");
2176     if(pcbNeeded) *pcbNeeded = 0;
2177     if(pcReturned) *pcReturned = 0;
2178     return TRUE;
2179 }
2180
2181 /*****************************************************************************
2182  *          WINSPOOL_EnumPrinterDrivers [internal]
2183  *
2184  *    Delivers information about all installed printer drivers installed on
2185  *    localhost or a given server
2186  *
2187  * RETURNS
2188  *    nonzero on succes or zero on failure, if the buffer for the returned
2189  *    information is too small the function will return an error
2190  *
2191  * BUGS
2192  *    - only implemented for localhost, foreign hosts will return an error
2193  */
2194 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2195                                         DWORD Level, LPBYTE pDriverInfo,
2196                                         DWORD cbBuf, LPDWORD pcbNeeded,
2197                                         LPDWORD pcReturned, BOOL unicode)
2198
2199 {   HKEY  hkeyDrivers;
2200     DWORD i, needed, number = 0, size = 0;
2201     WCHAR DriverNameW[255];
2202     PBYTE ptr;
2203
2204     TRACE("%s,%s,%ld,%p,%ld,%d\n",
2205           debugstr_w(pName), debugstr_w(pEnvironment),
2206           Level, pDriverInfo, cbBuf, unicode);
2207
2208     /* check for local drivers */
2209     if(pName) {
2210         ERR("remote drivers unsupported! Current remote host is %s\n",
2211              debugstr_w(pName));
2212         return FALSE;
2213     }
2214
2215     /* check input parameter */
2216     if((Level < 1) || (Level > 3)) {
2217         ERR("unsupported level %ld \n", Level);
2218         return FALSE;
2219     }
2220
2221     /* initialize return values */
2222     if(pDriverInfo)
2223         memset( pDriverInfo, 0, cbBuf);
2224     *pcbNeeded  = 0;
2225     *pcReturned = 0;
2226
2227     hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2228     if(!hkeyDrivers) {
2229         ERR("Can't open Drivers key\n");
2230         return FALSE;
2231     }
2232
2233     if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2234                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2235         RegCloseKey(hkeyDrivers);
2236         ERR("Can't query Drivers key\n");
2237         return FALSE;
2238     }
2239     TRACE("Found %ld Drivers\n", number);
2240
2241     /* get size of single struct
2242      * unicode and ascii structure have the same size
2243      */
2244     switch (Level) {
2245         case 1:
2246             size = sizeof(DRIVER_INFO_1A);
2247             break;
2248         case 2:
2249             size = sizeof(DRIVER_INFO_2A);
2250             break;
2251         case 3:
2252             size = sizeof(DRIVER_INFO_3A);
2253             break;
2254     }
2255
2256     /* calculate required buffer size */
2257     *pcbNeeded = size * number;
2258
2259     for( i = 0,  ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2260          i < number;
2261          i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2262         if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2263                        != ERROR_SUCCESS) {
2264             ERR("Can't enum key number %ld\n", i);
2265             RegCloseKey(hkeyDrivers);
2266             return FALSE;
2267         }
2268         if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2269                          pEnvironment, Level, ptr,
2270                          (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2271                          (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2272                          &needed, unicode)) {
2273             RegCloseKey(hkeyDrivers);
2274             return FALSE;
2275         }
2276         (*pcbNeeded) += needed;
2277     }
2278
2279     RegCloseKey(hkeyDrivers);
2280
2281     if(cbBuf < *pcbNeeded){
2282         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2283         return FALSE;
2284     }
2285
2286     return TRUE;
2287 }
2288
2289 /*****************************************************************************
2290  *          EnumPrinterDriversW  [WINSPOOL.173]
2291  *
2292  *    see function EnumPrinterDrivers for RETURNS, BUGS
2293  */
2294 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2295                                 LPBYTE pDriverInfo, DWORD cbBuf,
2296                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
2297 {
2298     return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2299                                        cbBuf, pcbNeeded, pcReturned, TRUE);
2300 }
2301
2302 /*****************************************************************************
2303  *          EnumPrinterDriversA  [WINSPOOL.172]
2304  *
2305  *    see function EnumPrinterDrivers for RETURNS, BUGS
2306  */
2307 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2308                                 LPBYTE pDriverInfo, DWORD cbBuf,
2309                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
2310 {   BOOL ret;
2311     WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2312
2313     if(pName)
2314         pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2315     if(pEnvironment)
2316         pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2317
2318     ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2319                                       cbBuf, pcbNeeded, pcReturned, FALSE);
2320     if(pNameW)
2321         HeapFree(GetProcessHeap(), 0, pNameW);
2322     if(pEnvironmentW)
2323         HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2324
2325     return ret;
2326 }