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