Merged DeviceCapabilities and DeviceCapabilitiesA.
[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 "debugtools.h"
19 #include "heap.h"
20 #include "commctrl.h"
21 #include "winnls.h"
22
23 DEFAULT_DEBUG_CHANNEL(winspool)
24
25 CRITICAL_SECTION PRINT32_RegistryBlocker;
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 pDeivce,LPCSTR pPort, WORD cap,
284                                LPSTR pOutput, LPDEVMODEA lpdm)
285 {
286     INT ret;
287     ret = GDI_CallDeviceCapabilities16(pDeivce, 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     ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1042     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1043         WARN("Got ret = %ld\n", ret);
1044         *needed = 0;
1045         return FALSE;
1046     }
1047     if(unicode) {
1048         sz += (CCHDEVICENAME + CCHFORMNAME);
1049         if(buflen >= sz) {
1050             DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1051             memcpy(ptr, dmW, sz);
1052             HeapFree(GetProcessHeap(),0,dmW);
1053         }
1054     }
1055     *needed = sz;
1056     return TRUE;
1057 }
1058
1059 /*********************************************************************
1060  *    WINSPOOL_GetPrinter_2
1061  *
1062  * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1063  * The strings are either stored as unicode or ascii.
1064  */
1065 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1066                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1067                                   BOOL unicode)
1068 {
1069     DWORD size, left = cbBuf;
1070     BOOL space = (cbBuf > 0);
1071     LPBYTE ptr = buf;
1072
1073     *pcbNeeded = 0;
1074
1075     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1076                                  unicode)) {
1077         if(space && size <= left) {
1078             pi2->pPrinterName = (LPWSTR)ptr;
1079             ptr += size;
1080             left -= size;
1081         } else
1082             space = FALSE;
1083         *pcbNeeded += size;
1084     }
1085     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1086                                  unicode)) {
1087         if(space && size <= left) {
1088             pi2->pShareName = (LPWSTR)ptr;
1089             ptr += size;
1090             left -= size;
1091         } else
1092             space = FALSE;
1093         *pcbNeeded += size;
1094     }
1095     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1096                                  unicode)) {
1097         if(space && size <= left) {
1098             pi2->pPortName = (LPWSTR)ptr;
1099             ptr += size;
1100             left -= size;
1101         } else
1102             space = FALSE;
1103         *pcbNeeded += size;
1104     }
1105     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1106                                  &size, unicode)) {
1107         if(space && size <= left) {
1108             pi2->pDriverName = (LPWSTR)ptr;
1109             ptr += size;
1110             left -= size;
1111         } else
1112             space = FALSE;
1113         *pcbNeeded += size;
1114     }
1115     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1116                                  unicode)) {
1117         if(space && size <= left) {
1118             pi2->pComment = (LPWSTR)ptr;
1119             ptr += size;
1120             left -= size;
1121         } else
1122             space = FALSE;
1123         *pcbNeeded += size;
1124     }
1125     if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1126                                  unicode)) {
1127         if(space && size <= left) {
1128             pi2->pLocation = (LPWSTR)ptr;
1129             ptr += size;
1130             left -= size;
1131         } else
1132             space = FALSE;
1133         *pcbNeeded += size;
1134     }
1135     if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1136                                   &size, unicode)) {
1137         if(space && size <= left) {
1138             pi2->pDevMode = (LPDEVMODEW)ptr;
1139             ptr += size;
1140             left -= size;
1141         } else
1142             space = FALSE;
1143         *pcbNeeded += size;
1144     }
1145     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1146                                  &size, unicode)) {
1147         if(space && size <= left) {
1148             pi2->pSepFile = (LPWSTR)ptr;
1149             ptr += size;
1150             left -= size;
1151         } else
1152             space = FALSE;
1153         *pcbNeeded += size;
1154     }
1155     if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1156                                  &size, unicode)) {
1157         if(space && size <= left) {
1158             pi2->pPrintProcessor = (LPWSTR)ptr;
1159             ptr += size;
1160             left -= size;
1161         } else
1162             space = FALSE;
1163         *pcbNeeded += size;
1164     }
1165     if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1166                                  &size, unicode)) {
1167         if(space && size <= left) {
1168             pi2->pDatatype = (LPWSTR)ptr;
1169             ptr += size;
1170             left -= size;
1171         } else
1172             space = FALSE;
1173         *pcbNeeded += size;
1174     }
1175     if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1176                                  &size, unicode)) {
1177         if(space && size <= left) {
1178             pi2->pParameters = (LPWSTR)ptr;
1179             ptr += size;
1180             left -= size;
1181         } else
1182             space = FALSE;
1183         *pcbNeeded += size;
1184     }
1185     if(pi2) {
1186         pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes"); 
1187         pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1188         pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1189                                                         "Default Priority");
1190         pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1191         pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1192     }
1193
1194     if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1195         memset(pi2, 0, sizeof(*pi2));
1196
1197     return space;
1198 }
1199
1200 /*********************************************************************
1201  *    WINSPOOL_GetPrinter_4
1202  *
1203  * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1204  */
1205 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1206                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1207                                   BOOL unicode)
1208 {
1209     DWORD size, left = cbBuf;
1210     BOOL space = (cbBuf > 0);
1211     LPBYTE ptr = buf;
1212
1213     *pcbNeeded = 0;
1214
1215     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1216                                  unicode)) {
1217         if(space && size <= left) {
1218             pi4->pPrinterName = (LPWSTR)ptr;
1219             ptr += size;
1220             left -= size;
1221         } else
1222             space = FALSE;
1223         *pcbNeeded += size;
1224     }
1225     if(pi4) {
1226         pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes"); 
1227     }
1228
1229     if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1230         memset(pi4, 0, sizeof(*pi4));
1231
1232     return space;
1233 }
1234
1235 /*********************************************************************
1236  *    WINSPOOL_GetPrinter_5
1237  *
1238  * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1239  */
1240 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1241                                   LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1242                                   BOOL unicode)
1243 {
1244     DWORD size, left = cbBuf;
1245     BOOL space = (cbBuf > 0);
1246     LPBYTE ptr = buf;
1247
1248     *pcbNeeded = 0;
1249
1250     if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1251                                  unicode)) {
1252         if(space && size <= left) {
1253             pi5->pPrinterName = (LPWSTR)ptr;
1254             ptr += size;
1255             left -= size;
1256         } else
1257             space = FALSE;
1258         *pcbNeeded += size;
1259     }
1260     if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1261                                  unicode)) {
1262         if(space && size <= left) {
1263             pi5->pPortName = (LPWSTR)ptr;
1264             ptr += size;
1265             left -= size;
1266         } else
1267             space = FALSE;
1268         *pcbNeeded += size;
1269     }
1270     if(pi5) {
1271         pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes"); 
1272         pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1273                                                                 "dnsTimeout"); 
1274         pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1275                                                                  "txTimeout"); 
1276     }
1277
1278     if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1279         memset(pi5, 0, sizeof(*pi5));
1280
1281     return space;
1282 }
1283
1284 /*****************************************************************************
1285  *          WINSPOOL_GetPrinter
1286  *
1287  *    Implementation of GetPrinterA|W.  Relies on PRINTER_INFO_*W being
1288  *    essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1289  *    just a collection of pointers to strings.
1290  */
1291 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1292                                 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1293 {
1294     OPENEDPRINTER *lpOpenedPrinter;
1295     DWORD size, needed = 0;
1296     LPBYTE ptr = NULL;
1297     HKEY hkeyPrinter, hkeyPrinters;
1298     BOOL ret;
1299
1300     TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1301
1302     lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1303     if(!lpOpenedPrinter) {
1304         SetLastError(ERROR_INVALID_HANDLE);
1305         return FALSE;
1306     }
1307     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1308        ERROR_SUCCESS) {
1309         ERR("Can't create Printers key\n");
1310         return FALSE;
1311     }
1312     if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1313        != ERROR_SUCCESS) {
1314         ERR("Can't find opened printer %s in registry\n",
1315             debugstr_w(lpOpenedPrinter->lpsPrinterName));
1316         RegCloseKey(hkeyPrinters);
1317         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1318         return FALSE;
1319     }
1320
1321     switch(Level) {
1322     case 2:
1323       {
1324         PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1325
1326         size = sizeof(PRINTER_INFO_2W);
1327         if(size <= cbBuf) {
1328             ptr = pPrinter + size;
1329             cbBuf -= size;
1330             memset(pPrinter, 0, size);
1331         } else {
1332             pi2 = NULL;
1333             cbBuf = 0;
1334         }
1335         ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1336                                     unicode);
1337         needed += size;
1338         break;
1339       }
1340       
1341     case 4:
1342       {
1343         PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1344         
1345         size = sizeof(PRINTER_INFO_4W);
1346         if(size <= cbBuf) {
1347             ptr = pPrinter + size;
1348             cbBuf -= size;
1349             memset(pPrinter, 0, size);
1350         } else {
1351             pi4 = NULL;
1352             cbBuf = 0;
1353         }
1354         ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1355                                     unicode);
1356         needed += size;
1357         break;
1358       }
1359
1360
1361     case 5:
1362       {
1363         PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1364
1365         size = sizeof(PRINTER_INFO_5W);
1366         if(size <= cbBuf) {
1367             ptr = pPrinter + size;
1368             cbBuf -= size;
1369             memset(pPrinter, 0, size);
1370         } else {
1371             pi5 = NULL;
1372             cbBuf = 0;
1373         }
1374
1375         ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1376                                     unicode);
1377         needed += size;
1378         break;
1379       }
1380
1381     default:
1382         FIXME("Unimplemented level %ld\n", Level);
1383         SetLastError(ERROR_INVALID_LEVEL);
1384         RegCloseKey(hkeyPrinters);
1385         RegCloseKey(hkeyPrinter);
1386         return FALSE;
1387     }
1388
1389     RegCloseKey(hkeyPrinter);
1390     RegCloseKey(hkeyPrinters);
1391
1392     TRACE("returing %d needed = %ld\n", ret, needed);
1393     if(pcbNeeded) *pcbNeeded = needed;
1394     if(!ret)
1395         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1396     return ret;
1397 }
1398
1399 /*****************************************************************************
1400  *          GetPrinterW  [WINSPOOL.194]
1401  */
1402 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1403                         DWORD cbBuf, LPDWORD pcbNeeded)
1404 {
1405     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1406                                TRUE);
1407 }
1408
1409 /*****************************************************************************
1410  *          GetPrinterA  [WINSPOOL.187]
1411  */
1412 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1413                     DWORD cbBuf, LPDWORD pcbNeeded)
1414 {
1415     return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1416                                FALSE);
1417 }
1418
1419 /*****************************************************************************
1420  *          WINSPOOL_EnumPrinters
1421  *
1422  *    Implementation of EnumPrintersA|W
1423  */
1424 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1425                                   DWORD dwLevel, LPBYTE lpbPrinters,
1426                                   DWORD cbBuf, LPDWORD lpdwNeeded,
1427                                   LPDWORD lpdwReturned, BOOL unicode)
1428
1429 {
1430     HKEY hkeyPrinters, hkeyPrinter;
1431     WCHAR PrinterName[255];
1432     DWORD needed = 0, number = 0;
1433     DWORD used, i, left;
1434     PBYTE pi, buf;
1435
1436     if(lpbPrinters)
1437         memset(lpbPrinters, 0, cbBuf);
1438     if(lpdwReturned)
1439         *lpdwReturned = 0;
1440
1441     if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1442         FIXME("dwType = %08lx\n", dwType);
1443         SetLastError(ERROR_INVALID_FLAGS);
1444         return FALSE;
1445     }
1446
1447     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1448        ERROR_SUCCESS) {
1449         ERR("Can't create Printers key\n");
1450         return FALSE;
1451     }
1452   
1453     if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1454                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1455         RegCloseKey(hkeyPrinters);
1456         ERR("Can't query Printers key\n");
1457         return FALSE;
1458     }
1459     TRACE("Found %ld printers\n", number);
1460
1461     switch(dwLevel) {
1462     case 1:
1463         RegCloseKey(hkeyPrinters);
1464         if (lpdwReturned)
1465             *lpdwReturned = number;
1466         return TRUE;
1467
1468     case 2:
1469         used = number * sizeof(PRINTER_INFO_2W);
1470         break;
1471     case 4:
1472         used = number * sizeof(PRINTER_INFO_4W);
1473         break;
1474     case 5:
1475         used = number * sizeof(PRINTER_INFO_5W);
1476         break;
1477
1478     default:
1479         SetLastError(ERROR_INVALID_LEVEL);
1480         RegCloseKey(hkeyPrinters);
1481         return FALSE;
1482     }
1483     pi = (used <= cbBuf) ? lpbPrinters : NULL;
1484
1485     for(i = 0; i < number; i++) {
1486         if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) != 
1487            ERROR_SUCCESS) {
1488             ERR("Can't enum key number %ld\n", i);
1489             RegCloseKey(hkeyPrinters);
1490             return FALSE;
1491         }
1492         TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1493         if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1494            ERROR_SUCCESS) {
1495             ERR("Can't open key %s\n", debugstr_w(PrinterName));
1496             RegCloseKey(hkeyPrinters);
1497             return FALSE;
1498         }
1499
1500         if(cbBuf > used) {
1501             buf = lpbPrinters + used;
1502             left = cbBuf - used;
1503         } else {
1504             buf = NULL;
1505             left = 0;
1506         }
1507
1508         switch(dwLevel) {
1509         case 2:
1510             WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1511                                   left, &needed, unicode);
1512             used += needed;
1513             if(pi) pi += sizeof(PRINTER_INFO_2W);
1514             break;
1515         case 4:
1516             WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1517                                   left, &needed, unicode);
1518             used += needed;
1519             if(pi) pi += sizeof(PRINTER_INFO_4W);
1520             break;
1521         case 5:
1522             WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1523                                   left, &needed, unicode);
1524             used += needed;
1525             if(pi) pi += sizeof(PRINTER_INFO_5W);
1526             break;
1527         default:
1528             ERR("Shouldn't be here!\n");
1529             RegCloseKey(hkeyPrinter);
1530             RegCloseKey(hkeyPrinters);
1531             return FALSE;
1532         }
1533         RegCloseKey(hkeyPrinter);
1534     }
1535     RegCloseKey(hkeyPrinters);
1536
1537     if(lpdwNeeded)
1538         *lpdwNeeded = used;
1539
1540     if(used > cbBuf) {
1541         if(lpbPrinters)
1542             memset(lpbPrinters, 0, cbBuf);
1543         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1544         return FALSE;
1545     }
1546     if(lpdwReturned)
1547         *lpdwReturned = number;  
1548     SetLastError(ERROR_SUCCESS);
1549     return TRUE;
1550 }
1551
1552
1553 /******************************************************************
1554  *              EnumPrintersW        [WINSPOOL.175]
1555  *
1556  *    Enumerates the available printers, print servers and print
1557  *    providers, depending on the specified flags, name and level.
1558  *
1559  * RETURNS:
1560  *
1561  *    If level is set to 1:
1562  *      Not implemented yet! 
1563  *      Returns TRUE with an empty list.
1564  *
1565  *    If level is set to 2:
1566  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1567  *      Returns an array of PRINTER_INFO_2 data structures in the 
1568  *      lpbPrinters buffer. Note that according to MSDN also an 
1569  *      OpenPrinter should be performed on every remote printer.
1570  *
1571  *    If level is set to 4 (officially WinNT only):
1572  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1573  *      Fast: Only the registry is queried to retrieve printer names,
1574  *      no connection to the driver is made.
1575  *      Returns an array of PRINTER_INFO_4 data structures in the 
1576  *      lpbPrinters buffer.
1577  *
1578  *    If level is set to 5 (officially WinNT4/Win9x only):
1579  *      Fast: Only the registry is queried to retrieve printer names,
1580  *      no connection to the driver is made.
1581  *      Returns an array of PRINTER_INFO_5 data structures in the 
1582  *      lpbPrinters buffer.
1583  *
1584  *    If level set to 3 or 6+:
1585  *          returns zero (faillure!)
1586  *      
1587  *    Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
1588  *    for information.
1589  *
1590  * BUGS:
1591  *    - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1592  *    - Only levels 2, 4 and 5 are implemented at the moment.
1593  *    - 16-bit printer drivers are not enumerated.
1594  *    - Returned amount of bytes used/needed does not match the real Windoze 
1595  *      implementation (as in this implementation, all strings are part 
1596  *      of the buffer, whereas Win32 keeps them somewhere else)
1597  *    - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1598  *
1599  * NOTE:
1600  *    - In a regular Wine installation, no registry settings for printers
1601  *      exist, which makes this function return an empty list.
1602  */
1603 BOOL  WINAPI EnumPrintersW(
1604                 DWORD dwType,        /* Types of print objects to enumerate */
1605                 LPWSTR lpszName,     /* name of objects to enumerate */
1606                 DWORD dwLevel,       /* type of printer info structure */
1607                 LPBYTE lpbPrinters,  /* buffer which receives info */
1608                 DWORD cbBuf,         /* max size of buffer in bytes */
1609                 LPDWORD lpdwNeeded,  /* pointer to var: # bytes used/needed */
1610                 LPDWORD lpdwReturned /* number of entries returned */
1611                 )
1612 {
1613     return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1614                                  lpdwNeeded, lpdwReturned, TRUE);
1615 }
1616
1617 /******************************************************************
1618  *              EnumPrintersA        [WINSPOOL.174]
1619  *
1620  */
1621 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1622                           DWORD dwLevel, LPBYTE lpbPrinters,
1623                           DWORD cbBuf, LPDWORD lpdwNeeded,
1624                           LPDWORD lpdwReturned)
1625 {
1626     BOOL ret;
1627     LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1628
1629     ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1630                                 lpdwNeeded, lpdwReturned, FALSE);
1631     HeapFree(GetProcessHeap(),0,lpszNameW);
1632     return ret;
1633 }
1634
1635
1636 /*****************************************************************************
1637  *          WINSPOOL_GetPrinterDriver
1638  */
1639 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1640                                       DWORD Level, LPBYTE pDriverInfo,
1641                                       DWORD cbBuf, LPDWORD pcbNeeded,
1642                                       BOOL unicode)
1643 {
1644     OPENEDPRINTER *lpOpenedPrinter;
1645     WCHAR DriverName[100];
1646     DWORD ret, type, size, dw, needed = 0;
1647     LPBYTE ptr = NULL;
1648     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1649     
1650     TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1651           Level,pDriverInfo,cbBuf, pcbNeeded);
1652
1653     ZeroMemory(pDriverInfo, cbBuf);
1654
1655     lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1656     if(!lpOpenedPrinter) {
1657         SetLastError(ERROR_INVALID_HANDLE);
1658         return FALSE;
1659     }
1660     if(pEnvironment) {
1661         FIXME("pEnvironment = %s\n", debugstr_w(pEnvironment));
1662         SetLastError(ERROR_INVALID_ENVIRONMENT);
1663         return FALSE;
1664     }
1665     if(Level < 1 || Level > 3) {
1666         SetLastError(ERROR_INVALID_LEVEL);
1667         return FALSE;
1668     }
1669     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1670        ERROR_SUCCESS) {
1671         ERR("Can't create Printers key\n");
1672         return FALSE;
1673     }
1674     if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1675        != ERROR_SUCCESS) {
1676         ERR("Can't find opened printer %s in registry\n",
1677             debugstr_w(lpOpenedPrinter->lpsPrinterName));
1678         RegCloseKey(hkeyPrinters);
1679         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1680         return FALSE;
1681     }
1682     size = sizeof(DriverName);
1683     ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1684                            (LPBYTE)DriverName, &size);
1685     RegCloseKey(hkeyPrinter);
1686     RegCloseKey(hkeyPrinters);
1687     if(ret != ERROR_SUCCESS) {
1688         ERR("Can't get DriverName for printer %s\n",
1689             debugstr_w(lpOpenedPrinter->lpsPrinterName));
1690         return FALSE;
1691     }
1692     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1693        ERROR_SUCCESS) {
1694         ERR("Can't create Drivers key\n");
1695         return FALSE;
1696     }
1697     if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver)
1698        != ERROR_SUCCESS) {
1699         ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1700         RegCloseKey(hkeyDrivers);
1701         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1702         return FALSE;
1703     }
1704
1705     switch(Level) {
1706     case 1:
1707         size = sizeof(DRIVER_INFO_1W);
1708         break;
1709     case 2:
1710         size = sizeof(DRIVER_INFO_2W);
1711         break;
1712     case 3:
1713         size = sizeof(DRIVER_INFO_3W);
1714         break;
1715     default:
1716         ERR("Invalid level\n");
1717         return FALSE;
1718     }
1719
1720     if(size <= cbBuf) {
1721         ptr = pDriverInfo + size;
1722         cbBuf -= size;
1723     } else
1724         cbBuf = 0;
1725     needed = size;
1726
1727     if(unicode)
1728         size = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1729     else
1730         size = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL,
1731                                    NULL);
1732
1733     if(size <= cbBuf) {
1734         cbBuf -= size;
1735         if(unicode)
1736             lstrcpyW((LPWSTR)ptr, DriverName);
1737         else
1738             WideCharToMultiByte(CP_ACP, 0, DriverName, -1, ptr, size, NULL,
1739                                 NULL);
1740         if(Level == 1)
1741             ((DRIVER_INFO_1W *)pDriverInfo)->pName = (LPWSTR)ptr;
1742         else
1743             ((DRIVER_INFO_2W *)pDriverInfo)->pName = (LPWSTR)ptr;
1744         ptr += size;
1745     }
1746     needed += size;
1747
1748     if(Level > 1) {
1749         DRIVER_INFO_2W *di2 = (DRIVER_INFO_2W *)pDriverInfo;
1750
1751         size = sizeof(dw);
1752         if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw,
1753                             &size) !=
1754            ERROR_SUCCESS)
1755             WARN("Can't get Version\n");
1756         else if(cbBuf)
1757             di2->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         if(size <= cbBuf) {
1767             cbBuf -= size;
1768             if(unicode)
1769                 lstrcpyW((LPWSTR)ptr, pEnvironment);
1770             else
1771                 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, ptr, size,
1772                                     NULL, NULL);
1773             di2->pEnvironment = (LPWSTR)ptr;
1774             ptr += size;
1775         } else 
1776             cbBuf = 0;
1777         needed += size;
1778
1779         if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, ptr, cbBuf, &size,
1780                                      unicode)) {
1781             if(cbBuf && size <= cbBuf) {
1782                 di2->pDriverPath = (LPWSTR)ptr;
1783                 ptr += size;
1784             } else
1785                 cbBuf = 0;
1786             needed += size;
1787         }
1788         if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, ptr, cbBuf, &size,
1789                                      unicode)) {
1790             if(cbBuf && size <= cbBuf) {
1791                 di2->pDataFile = (LPWSTR)ptr;
1792                 ptr += size;
1793             } else
1794                 cbBuf = 0;
1795             needed += size;
1796         }
1797         if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, ptr,
1798                                      cbBuf, &size, unicode)) {
1799             if(cbBuf && size <= cbBuf) {
1800                 di2->pConfigFile = (LPWSTR)ptr;
1801                 ptr += size;
1802             } else
1803                 cbBuf = 0;
1804             needed += size;
1805         }
1806     }
1807     if(Level > 2) {
1808         DRIVER_INFO_3W *di3 = (DRIVER_INFO_3W *)pDriverInfo;
1809
1810         if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, ptr, cbBuf, &size,
1811                                      unicode)) {
1812             if(cbBuf && size <= cbBuf) {
1813                 di3->pHelpFile = (LPWSTR)ptr;
1814                 ptr += size;
1815             } else
1816                 cbBuf = 0;
1817             needed += size;
1818         }
1819         if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, ptr, cbBuf,
1820                                      &size, unicode)) {
1821             if(cbBuf && size <= cbBuf) {
1822                 di3->pDependentFiles = (LPWSTR)ptr;
1823                 ptr += size;
1824             } else
1825                 cbBuf = 0;
1826             needed += size;
1827         }
1828         if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, ptr, cbBuf, &size,
1829                                      unicode)) {
1830             if(cbBuf && size <= cbBuf) {
1831                 di3->pMonitorName = (LPWSTR)ptr;
1832                 ptr += size;
1833             } else
1834                 cbBuf = 0;
1835             needed += size;
1836         }
1837         if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, ptr, cbBuf, &size,
1838                                      unicode)) {
1839             if(cbBuf && size <= cbBuf) {
1840                 di3->pDefaultDataType = (LPWSTR)ptr;
1841                 ptr += size;
1842             } else
1843                 cbBuf = 0;
1844             needed += size;
1845         }
1846     }
1847     RegCloseKey(hkeyDriver);
1848     RegCloseKey(hkeyDrivers);
1849
1850     if(pcbNeeded) *pcbNeeded = needed;
1851     if(cbBuf) return TRUE;
1852     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1853     return FALSE;
1854 }
1855
1856 /*****************************************************************************
1857  *          GetPrinterDriverA  [WINSPOOL.190]
1858  */
1859 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1860                               DWORD Level, LPBYTE pDriverInfo,
1861                               DWORD cbBuf, LPDWORD pcbNeeded)
1862 {
1863     BOOL ret;
1864     LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
1865     ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
1866                                     cbBuf, pcbNeeded, FALSE);
1867     HeapFree(GetProcessHeap(),0,pEnvW);
1868     return ret;
1869 }
1870 /*****************************************************************************
1871  *          GetPrinterDriverW  [WINSPOOL.193]
1872  */
1873 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1874                                   DWORD Level, LPBYTE pDriverInfo, 
1875                                   DWORD cbBuf, LPDWORD pcbNeeded)
1876 {
1877     return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
1878                                      pDriverInfo, cbBuf, pcbNeeded, TRUE);
1879 }
1880
1881 /*****************************************************************************
1882  *       GetPrinterDriverDirectoryA  [WINSPOOL.191]
1883  */
1884 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1885                                        DWORD Level, LPBYTE pDriverDirectory,
1886                                        DWORD cbBuf, LPDWORD pcbNeeded)
1887 {
1888     DWORD needed;
1889
1890     TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1891           pDriverDirectory, cbBuf, pcbNeeded);
1892     if(pName != NULL) {
1893         FIXME("pName = `%s' - unsupported\n", pName);
1894         SetLastError(ERROR_INVALID_PARAMETER);
1895         return FALSE;
1896     }
1897     if(pEnvironment != NULL) {
1898         FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1899         SetLastError(ERROR_INVALID_ENVIRONMENT);
1900         return FALSE;
1901     }
1902     if(Level != 1)  /* win95 ignores this so we just carry on */
1903         WARN("Level = %ld - assuming 1\n", Level);
1904     
1905     /* FIXME should read from registry */
1906     needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
1907     needed++;
1908     if(pcbNeeded)
1909         *pcbNeeded = needed;
1910     if(needed > cbBuf) {
1911         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1912         return FALSE;
1913     }
1914     return TRUE;
1915 }
1916
1917
1918 /*****************************************************************************
1919  *       GetPrinterDriverDirectoryW  [WINSPOOL.192]
1920  */
1921 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
1922                                        DWORD Level, LPBYTE pDriverDirectory,
1923                                        DWORD cbBuf, LPDWORD pcbNeeded)
1924 {
1925     LPSTR pNameA = NULL, pEnvironmentA = NULL;
1926     BOOL ret;
1927
1928     if(pName)
1929         pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
1930     if(pEnvironment)
1931         pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
1932     ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
1933                                       pDriverDirectory, cbBuf, pcbNeeded );
1934     if(pNameA)
1935         HeapFree( GetProcessHeap(), 0, pNameA );
1936     if(pEnvironmentA)
1937         HeapFree( GetProcessHeap(), 0, pEnvironment );
1938
1939     return ret;
1940 }
1941
1942 /*****************************************************************************
1943  *          AddPrinterDriverA  [WINSPOOL.120]
1944  */
1945 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
1946 {
1947     DRIVER_INFO_3A di3;
1948     HKEY hkeyDrivers, hkeyName;
1949
1950     TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
1951
1952     if(level != 2 && level != 3) {
1953         SetLastError(ERROR_INVALID_LEVEL);
1954         return FALSE;
1955     }
1956     if(pName != NULL) {
1957         FIXME("pName= `%s' - unsupported\n", pName);
1958         SetLastError(ERROR_INVALID_PARAMETER);
1959         return FALSE;
1960     }
1961     if(!pDriverInfo) {
1962         WARN("pDriverInfo == NULL");
1963         SetLastError(ERROR_INVALID_PARAMETER);
1964         return FALSE;
1965     }
1966     
1967     if(level == 3)
1968         di3 = *(DRIVER_INFO_3A *)pDriverInfo;
1969     else {
1970         memset(&di3, 0, sizeof(di3));
1971         *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
1972     }
1973
1974     if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
1975        !di3.pDataFile) {
1976         SetLastError(ERROR_INVALID_PARAMETER);
1977         return FALSE;
1978     }
1979     if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
1980     if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
1981     if(!di3.pHelpFile) di3.pHelpFile = "";
1982     if(!di3.pMonitorName) di3.pMonitorName = "";
1983
1984     if(di3.pEnvironment) {
1985         FIXME("pEnvironment = `%s'\n", di3.pEnvironment);
1986         SetLastError(ERROR_INVALID_ENVIRONMENT);
1987         return FALSE;
1988     }
1989     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1990        ERROR_SUCCESS) {
1991         ERR("Can't create Drivers key\n");
1992         return FALSE;
1993     }
1994
1995     if(level == 2) { /* apparently can't overwrite with level2 */
1996         if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
1997             RegCloseKey(hkeyName);
1998             RegCloseKey(hkeyDrivers);
1999             WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2000             SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2001             return FALSE;
2002         }
2003     }
2004     if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2005         RegCloseKey(hkeyDrivers);
2006         ERR("Can't create Name key\n");
2007         return FALSE;
2008     }
2009     RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2010                    0);
2011     RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2012     RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2013     RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion, 
2014                    sizeof(DWORD));
2015     RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2016     RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2017                    di3.pDependentFiles, 0);
2018     RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2019     RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2020     RegCloseKey(hkeyName);
2021     RegCloseKey(hkeyDrivers);
2022
2023     return TRUE;
2024 }
2025 /*****************************************************************************
2026  *          AddPrinterDriverW  [WINSPOOL.121]
2027  */
2028 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level, 
2029                                    LPBYTE pDriverInfo)
2030 {
2031     FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2032           level,pDriverInfo);
2033     return FALSE;
2034 }
2035
2036
2037 /*****************************************************************************
2038  *          PrinterProperties  [WINSPOOL.201]
2039  *
2040  *     Displays a dialog to set the properties of the printer.
2041  *
2042  * RETURNS 
2043  *     nonzero on succes or zero on faillure
2044  *
2045  * BUGS
2046  *         implemented as stub only
2047  */
2048 BOOL WINAPI PrinterProperties(HWND hWnd,      /* handle to parent window */
2049                               HANDLE hPrinter /* handle to printer object */
2050 ){
2051     FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2052     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2053     return FALSE;
2054 }
2055
2056 /*****************************************************************************
2057  *          EnumJobsA [WINSPOOL.162]
2058  *
2059  */
2060 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2061                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2062                       LPDWORD pcReturned)
2063 {
2064     FIXME("stub\n");
2065     if(pcbNeeded) *pcbNeeded = 0;
2066     if(pcReturned) *pcReturned = 0;
2067     return TRUE;
2068 }
2069
2070
2071 /*****************************************************************************
2072  *          EnumJobsW [WINSPOOL.163]
2073  *
2074  */
2075 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2076                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2077                       LPDWORD pcReturned)
2078 {
2079     FIXME("stub\n");
2080     if(pcbNeeded) *pcbNeeded = 0;
2081     if(pcReturned) *pcReturned = 0;
2082     return TRUE;
2083 }