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