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