Moved dll-specific make rules to a separate Makedll.rules file.
[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, Huw D M Davies
7  */
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include "winspool.h"
13 #include "winbase.h"
14 #include "winerror.h"
15 #include "winreg.h"
16 #include "debugtools.h"
17 #include "heap.h"
18 #include "commctrl.h"
19
20 DEFAULT_DEBUG_CHANNEL(winspool)
21
22 CRITICAL_SECTION PRINT32_RegistryBlocker;
23
24 typedef struct _OPENEDPRINTERA
25 {
26     LPSTR lpsPrinterName;
27     HANDLE hPrinter;
28     LPPRINTER_DEFAULTSA lpDefault;
29 } OPENEDPRINTERA, *LPOPENEDPRINTERA;
30
31 /* The OpenedPrinter Table dynamic array */
32 static HDPA pOpenedPrinterDPA = NULL;
33
34 extern HDPA   (WINAPI* WINSPOOL_DPA_CreateEx) (INT, HANDLE);
35 extern LPVOID (WINAPI* WINSPOOL_DPA_GetPtr) (const HDPA, INT);
36 extern INT    (WINAPI* WINSPOOL_DPA_InsertPtr) (const HDPA, INT, LPVOID);
37
38 static char Printers[] =
39  "System\\CurrentControlSet\\control\\Print\\Printers\\";
40 static char Drivers[] =
41 "System\\CurrentControlSet\\control\\Print\\Environments\\Windows 4.0\\Drivers\\"; /* Hmm, well */
42
43 /******************************************************************
44  *  WINSPOOL_GetOpenedPrinterEntryA
45  *  Get the first place empty in the opened printer table
46  */
47 static LPOPENEDPRINTERA WINSPOOL_GetOpenedPrinterEntryA()
48 {
49     int i;
50     LPOPENEDPRINTERA pOpenedPrinter;
51
52     /*
53      * Create the opened printers' handle dynamic array.
54      */
55     if (!pOpenedPrinterDPA)
56     {
57         pOpenedPrinterDPA = WINSPOOL_DPA_CreateEx(10, GetProcessHeap());
58         for (i = 0; i < 10; i++)
59         {
60             pOpenedPrinter = HeapAlloc(GetProcessHeap(),
61                                        HEAP_ZERO_MEMORY,
62                                        sizeof(OPENEDPRINTERA));
63             pOpenedPrinter->hPrinter = -1;
64             WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
65         }
66     }
67
68     /*
69      * Search for a handle not yet allocated.
70      */
71     for (i = 0; i < pOpenedPrinterDPA->nItemCount; i++)
72     {
73         pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, i);
74
75         if (pOpenedPrinter->hPrinter == -1)
76         {
77             pOpenedPrinter->hPrinter = i + 1;
78             return pOpenedPrinter;
79         }
80     }
81
82     /*
83      * Didn't find one, insert new element in the array.
84      */
85     if (i == pOpenedPrinterDPA->nItemCount)
86     {
87         pOpenedPrinter = HeapAlloc(GetProcessHeap(),
88                                    HEAP_ZERO_MEMORY,
89                                    sizeof(OPENEDPRINTERA));
90         pOpenedPrinter->hPrinter = i + 1;
91         WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
92         return pOpenedPrinter;
93     }
94
95     return NULL;
96 }
97
98 /******************************************************************
99  *  WINSPOOL_GetOpenedPrinterA
100  *  Get the pointer to the opened printer referred by the handle
101  */
102 static LPOPENEDPRINTERA WINSPOOL_GetOpenedPrinterA(int printerHandle)
103 {
104     LPOPENEDPRINTERA pOpenedPrinter;
105
106     if(!pOpenedPrinterDPA) return NULL;
107     if((printerHandle <=0) || 
108        (printerHandle > (pOpenedPrinterDPA->nItemCount - 1)))
109         return NULL;
110
111     pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1);
112
113     return pOpenedPrinter;
114 }
115
116 /******************************************************************
117  *              DeviceCapabilities32A    [WINSPOOL.151]
118  *
119  */
120 INT WINAPI DeviceCapabilitiesA(LPCSTR pDeivce,LPCSTR pPort, WORD cap,
121                                LPSTR pOutput, LPDEVMODEA lpdm)
122 {
123     INT ret;
124     ret = GDI_CallDeviceCapabilities16(pDeivce, pPort, cap, pOutput, lpdm);
125
126     /* If DC_PAPERSIZE map POINT16s to POINTs */
127     if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
128         POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
129         INT i;
130         memcpy(tmp, pOutput, ret * sizeof(POINT16));
131         for(i = 0; i < ret; i++)
132             CONV_POINT16TO32(tmp + i, (POINT*)pOutput + i);
133         HeapFree( GetProcessHeap(), 0, tmp );
134     }
135     return ret;
136 }
137
138
139 /*****************************************************************************
140  *          DeviceCapabilities32W 
141  */
142 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
143                                WORD fwCapability, LPWSTR pOutput,
144                                const DEVMODEW *pDevMode)
145 {
146     FIXME("(%p,%p,%d,%p,%p): stub\n",
147           pDevice, pPort, fwCapability, pOutput, pDevMode);
148     return -1;
149 }
150
151 /******************************************************************
152  *              DocumentProperties32A   [WINSPOOL.155]
153  *
154  */
155 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
156                                 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
157                                 LPDEVMODEA pDevModeInput,DWORD fMode )
158 {
159     LPOPENEDPRINTERA lpOpenedPrinter;
160     LPSTR lpName = pDeviceName;
161
162     TRACE("(%d,%d,%s,%p,%p,%ld)\n",
163         hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
164     );
165
166     if(!pDeviceName) {
167         lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
168         if(!lpOpenedPrinter) {
169             SetLastError(ERROR_INVALID_HANDLE);
170             return -1;
171         }
172         lpName = lpOpenedPrinter->lpsPrinterName;
173     }
174
175     return GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
176                                    pDevModeInput, NULL, fMode);
177
178 }
179
180
181 /*****************************************************************************
182  *          DocumentProperties32W 
183  */
184 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
185                                   LPWSTR pDeviceName,
186                                   LPDEVMODEW pDevModeOutput,
187                                   LPDEVMODEW pDevModeInput, DWORD fMode)
188 {
189     FIXME("(%d,%d,%s,%p,%p,%ld): stub\n",
190           hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
191           fMode);
192     return -1;
193 }
194
195
196 /******************************************************************
197  *              OpenPrinter32A        [WINSPOOL.196]
198  *
199  */
200 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
201                              LPPRINTER_DEFAULTSA pDefault)
202 {
203   /* Not implemented: use the DesiredAccess of pDefault to set 
204      the access rights to the printer */
205
206     LPOPENEDPRINTERA lpOpenedPrinter;
207     HKEY hkeyPrinters, hkeyPrinter;
208
209     if (!lpPrinterName) {
210        WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
211        SetLastError(ERROR_INVALID_PARAMETER);
212        return FALSE;
213     }
214
215     TRACE("(printerName: %s, pDefault %p\n", lpPrinterName, pDefault);
216
217     /* Check Printer exists */
218     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
219        ERROR_SUCCESS) {
220         ERR("Can't create Printers key\n");
221         SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
222         return FALSE;
223     }
224
225     if(RegOpenKeyA(hkeyPrinters, lpPrinterName, &hkeyPrinter)
226        != ERROR_SUCCESS) {
227         WARN("Can't find printer `%s' in registry\n", lpPrinterName);
228         RegCloseKey(hkeyPrinters);
229         SetLastError(ERROR_INVALID_PARAMETER);
230         return FALSE;
231     }
232     RegCloseKey(hkeyPrinter);
233     RegCloseKey(hkeyPrinters);
234
235     if(!phPrinter) /* This seems to be what win95 does anyway */
236         return TRUE;
237
238     /* Get a place in the opened printer buffer*/
239     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntryA();
240     if(!lpOpenedPrinter) {
241         ERR("Can't allocate printer slot\n");
242         SetLastError(ERROR_OUTOFMEMORY);
243         return FALSE;
244     }
245
246     /* Get the name of the printer */
247     lpOpenedPrinter->lpsPrinterName = 
248       HEAP_strdupA( GetProcessHeap(), 0, lpPrinterName );
249
250     /* Get the unique handle of the printer*/
251     *phPrinter = lpOpenedPrinter->hPrinter;
252
253     if (pDefault != NULL) {
254         lpOpenedPrinter->lpDefault = 
255           HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTER_DEFAULTSA));
256         lpOpenedPrinter->lpDefault->pDevMode =
257           HeapAlloc(GetProcessHeap(), 0, sizeof(DEVMODEA));
258         memcpy(lpOpenedPrinter->lpDefault->pDevMode, pDefault->pDevMode,
259                sizeof(DEVMODEA));
260         lpOpenedPrinter->lpDefault->pDatatype = 
261           HEAP_strdupA( GetProcessHeap(), 0, pDefault->pDatatype );
262         lpOpenedPrinter->lpDefault->DesiredAccess =
263           pDefault->DesiredAccess;
264     }
265     
266     return TRUE;
267
268 }
269
270 /******************************************************************
271  *              OpenPrinter32W        [WINSPOOL.197]
272  *
273  */
274 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
275                              LPPRINTER_DEFAULTSW pDefault)
276 {
277     FIXME("(%s,%p,%p):stub\n",debugstr_w(lpPrinterName), phPrinter,
278           pDefault);
279     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
280     return FALSE;
281 }
282
283 /******************************************************************
284  *              AddMonitor32A        [WINSPOOL.107]
285  *
286  */
287 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
288 {
289     FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
290     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
291     return FALSE;
292 }
293
294 /******************************************************************
295  *              DeletePrinterDriver32A        [WINSPOOL.146]
296  *
297  */
298 BOOL WINAPI
299 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
300 {
301     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
302           debugstr_a(pDriverName));
303     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
304     return FALSE;
305 }
306
307
308 /******************************************************************
309  *              DeleteMonitor32A        [WINSPOOL.135]
310  *
311  */
312 BOOL WINAPI
313 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
314 {
315     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
316           debugstr_a(pMonitorName));
317     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
318     return FALSE;
319 }
320
321
322 /******************************************************************
323  *              DeletePort32A        [WINSPOOL.137]
324  *
325  */
326 BOOL WINAPI
327 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
328 {
329     FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
330           debugstr_a(pPortName));
331     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
332     return FALSE;
333 }
334
335 /******************************************************************************
336  *    SetPrinter32W  [WINSPOOL.214]
337  */
338 BOOL WINAPI
339 SetPrinterW(
340   HANDLE  hPrinter,
341   DWORD     Level,
342   LPBYTE    pPrinter,
343   DWORD     Command) {
344
345        FIXME("():stub\n");
346   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
347        return FALSE;
348 }
349
350 /******************************************************************************
351  *    WritePrinter32  [WINSPOOL.223]
352  */
353 BOOL WINAPI
354 WritePrinter( 
355   HANDLE  hPrinter,
356   LPVOID  pBuf,
357   DWORD   cbBuf,
358   LPDWORD pcWritten) {
359
360        FIXME("():stub\n");
361   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
362        return FALSE;
363 }
364
365 /*****************************************************************************
366  *          AddForm32A  [WINSPOOL.103]
367  */
368 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
369 {
370     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
371     return 1;
372 }
373
374 /*****************************************************************************
375  *          AddForm32W  [WINSPOOL.104]
376  */
377 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
378 {
379     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
380     return 1;
381 }
382
383 /*****************************************************************************
384  *          AddJob32A  [WINSPOOL.105]
385  */
386 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
387                         DWORD cbBuf, LPDWORD pcbNeeded)
388 {
389     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
390           pcbNeeded);
391     return 1;
392 }
393
394 /*****************************************************************************
395  *          AddJob32W  [WINSPOOL.106]
396  */
397 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
398                         LPDWORD pcbNeeded)
399 {
400     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
401           pcbNeeded);
402     return 1;
403 }
404
405 /*****************************************************************************
406  *          AddPrinter32A  [WINSPOOL.117]
407  */
408 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
409 {
410     PRINTER_INFO_2A *pi = (PRINTER_INFO_2A *) pPrinter;
411
412     HANDLE retval;
413     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
414
415     TRACE("(%s,%ld,%p)\n", pName, Level, pPrinter);
416     
417     if(pName != NULL) {
418         FIXME("pName = `%s' - unsupported\n", pName);
419         SetLastError(ERROR_INVALID_PARAMETER);
420         return 0;
421     }
422     if(Level != 2) {
423         WARN("Level = %ld\n", Level);
424         SetLastError(ERROR_INVALID_LEVEL);
425         return 0;
426     }
427     if(!pPrinter) {
428         SetLastError(ERROR_INVALID_PARAMETER);
429         return 0;
430     }
431     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
432        ERROR_SUCCESS) {
433         ERR("Can't create Printers key\n");
434         return 0;
435     }
436     if(RegOpenKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
437        ERROR_SUCCESS) {
438         SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
439         RegCloseKey(hkeyPrinter);
440         RegCloseKey(hkeyPrinters);
441         return 0;
442     }
443     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
444        ERROR_SUCCESS) {
445         ERR("Can't create Drivers key\n");
446         RegCloseKey(hkeyPrinters);
447         return 0;
448     }
449     if(RegOpenKeyA(hkeyDrivers, pi->pDriverName, &hkeyDriver) != 
450        ERROR_SUCCESS) {
451         WARN("Can't find driver `%s'\n", pi->pDriverName);
452         RegCloseKey(hkeyPrinters);
453         RegCloseKey(hkeyDrivers);
454         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
455         return 0;
456     }
457     RegCloseKey(hkeyDriver);
458     RegCloseKey(hkeyDrivers);
459     if(strcasecmp(pi->pPrintProcessor, "WinPrint")) {  /* FIXME */
460         WARN("Can't find processor `%s'\n", pi->pPrintProcessor);
461         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
462         RegCloseKey(hkeyPrinters);
463         return 0;
464     }
465     if(RegCreateKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
466        ERROR_SUCCESS) {
467         WARN("Can't create printer `%s'\n", pi->pPrinterName);
468         SetLastError(ERROR_INVALID_PRINTER_NAME);
469         RegCloseKey(hkeyPrinters);
470         return 0;
471     }
472     RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
473                    (LPSTR)&pi->Attributes, sizeof(DWORD));
474     RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
475                    (LPSTR)&pi->pDevMode,
476                    pi->pDevMode ? pi->pDevMode->dmSize : 0);
477     RegSetValueExA(hkeyPrinter, "Description", 0, REG_SZ, pi->pComment, 0);
478     RegSetValueExA(hkeyPrinter, "Location", 0, REG_SZ, pi->pLocation, 0);
479     RegSetValueExA(hkeyPrinter, "Name", 0, REG_SZ, pi->pPrinterName, 0);
480     RegSetValueExA(hkeyPrinter, "Parameters", 0, REG_SZ, pi->pParameters, 0);
481     RegSetValueExA(hkeyPrinter, "Port", 0, REG_SZ, pi->pPortName, 0);
482     RegSetValueExA(hkeyPrinter, "Print Processor", 0, REG_SZ,
483                    pi->pPrintProcessor, 0);
484     RegSetValueExA(hkeyPrinter, "Printer Driver", 0, REG_SZ, pi->pDriverName,
485                    0);
486     RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
487                    (LPSTR)&pi->Priority, sizeof(DWORD));
488     RegSetValueExA(hkeyPrinter, "Separator File", 0, REG_SZ, pi->pSepFile, 0);
489     RegSetValueExA(hkeyPrinter, "Share Name", 0, REG_SZ, pi->pShareName, 0);
490     RegSetValueExA(hkeyPrinter, "Start Time", 0, REG_DWORD,
491                    (LPSTR)&pi->StartTime, sizeof(DWORD));
492     RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
493                    (LPSTR)&pi->Status, sizeof(DWORD));
494     RegSetValueExA(hkeyPrinter, "Until Time", 0, REG_DWORD,
495                    (LPSTR)&pi->UntilTime, sizeof(DWORD));
496
497     RegCloseKey(hkeyPrinter);
498     RegCloseKey(hkeyPrinters);
499     if(!OpenPrinterA(pi->pPrinterName, &retval, NULL)) {
500         ERR("OpenPrinter failing\n");
501         return 0;
502     }
503     return retval;
504 }
505
506 /*****************************************************************************
507  *          AddPrinter32W  [WINSPOOL.122]
508  */
509 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
510 {
511     FIXME("(%p,%ld,%p): stub\n", pName, Level, pPrinter);
512     return 0;
513 }
514
515
516 /*****************************************************************************
517  *          ClosePrinter32  [WINSPOOL.126]
518  */
519 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
520 {
521     LPOPENEDPRINTERA lpOpenedPrinter;
522
523     TRACE("Handle %d\n", hPrinter);
524
525     if (!pOpenedPrinterDPA)
526         return FALSE;
527
528     if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1)))
529     {
530         lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
531         HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
532         lpOpenedPrinter->lpsPrinterName = NULL;
533         
534         /* Free the memory of lpDefault if it has been initialized*/
535         if(lpOpenedPrinter->lpDefault != NULL)
536         {
537             HeapFree(GetProcessHeap(), 0,
538                      lpOpenedPrinter->lpDefault->pDevMode);
539             HeapFree(GetProcessHeap(), 0,
540                      lpOpenedPrinter->lpDefault->pDatatype);
541             HeapFree(GetProcessHeap(), 0,
542                      lpOpenedPrinter->lpDefault);
543             lpOpenedPrinter->lpDefault = NULL;
544         }
545         
546         lpOpenedPrinter->hPrinter = -1;
547
548         return TRUE;
549     }
550     return FALSE;
551 }
552
553 /*****************************************************************************
554  *          DeleteForm32A  [WINSPOOL.133]
555  */
556 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
557 {
558     FIXME("(%d,%s): stub\n", hPrinter, pFormName);
559     return 1;
560 }
561
562 /*****************************************************************************
563  *          DeleteForm32W  [WINSPOOL.134]
564  */
565 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
566 {
567     FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
568     return 1;
569 }
570
571 /*****************************************************************************
572  *          DeletePrinter32  [WINSPOOL.143]
573  */
574 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
575 {
576     FIXME("(%d): stub\n", hPrinter);
577     return 1;
578 }
579
580 /*****************************************************************************
581  *          SetPrinter32A  [WINSPOOL.211]
582  */
583 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
584                            DWORD Command)
585 {
586     FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
587     return FALSE;
588 }
589
590 /*****************************************************************************
591  *          SetJob32A  [WINSPOOL.209]
592  */
593 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
594                        LPBYTE pJob, DWORD Command)
595 {
596     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
597          Command);
598     return FALSE;
599 }
600
601 /*****************************************************************************
602  *          SetJob32W  [WINSPOOL.210]
603  */
604 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
605                        LPBYTE pJob, DWORD Command)
606 {
607     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
608          Command);
609     return FALSE;
610 }
611
612 /*****************************************************************************
613  *          GetForm32A  [WINSPOOL.181]
614  */
615 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
616                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
617 {
618     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
619          Level,pForm,cbBuf,pcbNeeded); 
620     return FALSE;
621 }
622
623 /*****************************************************************************
624  *          GetForm32W  [WINSPOOL.182]
625  */
626 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
627                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
628 {
629     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
630           debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
631     return FALSE;
632 }
633
634 /*****************************************************************************
635  *          SetForm32A  [WINSPOOL.207]
636  */
637 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
638                         LPBYTE pForm)
639 {
640     FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
641     return FALSE;
642 }
643
644 /*****************************************************************************
645  *          SetForm32W  [WINSPOOL.208]
646  */
647 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
648                         LPBYTE pForm)
649 {
650     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
651     return FALSE;
652 }
653
654 /*****************************************************************************
655  *          ReadPrinter32  [WINSPOOL.202]
656  */
657 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
658                            LPDWORD pNoBytesRead)
659 {
660     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
661     return FALSE;
662 }
663
664 /*****************************************************************************
665  *          ResetPrinter32A  [WINSPOOL.203]
666  */
667 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
668 {
669     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
670     return FALSE;
671 }
672
673 /*****************************************************************************
674  *          ResetPrinter32W  [WINSPOOL.204]
675  */
676 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
677 {
678     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
679     return FALSE;
680 }
681
682
683 /*****************************************************************************
684  *    WINSPOOL_GetStringFromRegA
685  *
686  * Get ValueName from hkey storing result in str.  buflen is space left in str
687  */ 
688 static BOOL WINSPOOL_GetStringFromRegA(HKEY hkey, LPCSTR ValueName, LPSTR ptr,
689                                        DWORD buflen, DWORD *needed)
690 {
691     DWORD sz = buflen, type;
692     LONG ret;
693
694     ret = RegQueryValueExA(hkey, ValueName, 0, &type, ptr, &sz);
695
696     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
697         ERR("Got ret = %ld\n", ret);
698         return FALSE;
699     }
700     *needed = sz;
701     return TRUE;
702 }
703
704 /*********************************************************************
705  *    WINSPOOL_GetPrinter_2A
706  *
707  * Fills out a PRINTER_INFO_2A struct storing the strings in buf.
708  */
709 static BOOL WINSPOOL_GetPrinter_2A(HKEY hkeyPrinter, PRINTER_INFO_2A *pi2,
710                                    LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
711 {
712     DWORD size, left = cbBuf;
713     BOOL space = (cbBuf > 0);
714     LPBYTE ptr = buf;
715
716     *pcbNeeded = 0;
717
718     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, left, &size);
719     if(space && size <= left) {
720         pi2->pPrinterName = ptr;
721         ptr += size;
722         left -= size;
723     } else
724         space = FALSE;
725     *pcbNeeded += size;
726
727     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, left, &size);
728     if(space && size <= left) {
729         pi2->pPortName = ptr;
730         ptr += size;
731         left -= size;
732     } else
733         space = FALSE;
734     *pcbNeeded += size;
735
736     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Printer Driver", ptr, left,
737                                &size);
738     if(space && size <= left) {
739         pi2->pDriverName = ptr;
740         ptr += size;
741         left -= size;
742     } else
743         space = FALSE;
744     *pcbNeeded += size;
745
746     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Default DevMode", ptr, left,
747                                &size);
748     if(space && size <= left) {
749         pi2->pDevMode = (LPDEVMODEA)ptr;
750         ptr += size;
751         left -= size;
752     } else
753         space = FALSE;
754     *pcbNeeded += size;
755
756     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Print Processor", ptr, left,
757                                &size);
758     if(space && size <= left) {
759         pi2->pPrintProcessor = ptr;
760         ptr += size;
761         left -= size;
762     } else
763         space = FALSE;
764     *pcbNeeded += size;
765
766     if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
767         memset(pi2, 0, sizeof(*pi2));
768
769     return space;
770 }
771
772 /*********************************************************************
773  *    WINSPOOL_GetPrinter_4A
774  *
775  * Fills out a PRINTER_INFO_4A struct storing the strings in buf.
776  */
777 static BOOL WINSPOOL_GetPrinter_4A(HKEY hkeyPrinter, PRINTER_INFO_4A *pi4,
778                                    LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
779 {
780     DWORD size, left = cbBuf;
781     BOOL space = (cbBuf > 0);
782     LPBYTE ptr = buf;
783
784     *pcbNeeded = 0;
785
786     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, left, &size);
787     if(space && size <= left) {
788         pi4->pPrinterName = ptr;
789         ptr += size;
790         left -= size;
791     } else
792         space = FALSE;
793
794     *pcbNeeded += size;
795
796     if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
797         memset(pi4, 0, sizeof(*pi4));
798
799     return space;
800 }
801
802 /*********************************************************************
803  *    WINSPOOL_GetPrinter_5A
804  *
805  * Fills out a PRINTER_INFO_5A struct storing the strings in buf.
806  */
807 static BOOL WINSPOOL_GetPrinter_5A(HKEY hkeyPrinter, PRINTER_INFO_5A *pi5,
808                                    LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
809 {
810     DWORD size, left = cbBuf;
811     BOOL space = (cbBuf > 0);
812     LPBYTE ptr = buf;
813
814     *pcbNeeded = 0;
815
816     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, left, &size);
817     if(space && size <= left) {
818         pi5->pPrinterName = ptr;
819         ptr += size;
820         left -= size;
821     } else
822         space = FALSE;
823     *pcbNeeded += size;
824
825     WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, left, &size);
826     if(space && size <= left) {
827         pi5->pPortName = ptr;
828         ptr += size;
829         left -= size;
830     } else
831         space = FALSE;
832     *pcbNeeded += size;
833
834     if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
835         memset(pi5, 0, sizeof(*pi5));
836
837     return space;
838 }
839
840 /*****************************************************************************
841  *          GetPrinterA  [WINSPOOL.187]
842  */
843 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
844                         DWORD cbBuf, LPDWORD pcbNeeded)
845 {
846     OPENEDPRINTERA *lpOpenedPrinter;
847     DWORD size, needed = 0;
848     LPBYTE ptr = NULL;
849     HKEY hkeyPrinter, hkeyPrinters;
850     BOOL ret;
851
852     TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
853
854     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
855     if(!lpOpenedPrinter) {
856         SetLastError(ERROR_INVALID_HANDLE);
857         return FALSE;
858     }
859     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
860        ERROR_SUCCESS) {
861         ERR("Can't create Printers key\n");
862         return FALSE;
863     }
864     if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
865        != ERROR_SUCCESS) {
866         ERR("Can't find opened printer `%s' in registry\n",
867             lpOpenedPrinter->lpsPrinterName);
868         RegCloseKey(hkeyPrinters);
869         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
870         return FALSE;
871     }
872
873     switch(Level) {
874     case 2:
875       {
876         PRINTER_INFO_2A *pi2 = (PRINTER_INFO_2A *)pPrinter;
877
878         size = sizeof(PRINTER_INFO_2A);
879         if(size <= cbBuf) {
880             ptr = pPrinter + size;
881             cbBuf -= size;
882             memset(pPrinter, 0, size);
883         } else {
884             pi2 = NULL;
885             cbBuf = 0;
886         }
887         ret = WINSPOOL_GetPrinter_2A(hkeyPrinter, pi2, ptr, cbBuf, &needed);
888         needed += size;
889         break;
890       }
891       
892     case 4:
893       {
894         PRINTER_INFO_4A *pi4 = (PRINTER_INFO_4A *)pPrinter;
895         
896         size = sizeof(PRINTER_INFO_4A);
897         if(size <= cbBuf) {
898             ptr = pPrinter + size;
899             cbBuf -= size;
900             memset(pPrinter, 0, size);
901         } else {
902             pi4 = NULL;
903             cbBuf = 0;
904         }
905         ret = WINSPOOL_GetPrinter_4A(hkeyPrinter, pi4, ptr, cbBuf, &needed);
906         needed += size;
907         break;
908       }
909
910
911     case 5:
912       {
913         PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A *)pPrinter;
914
915         size = sizeof(PRINTER_INFO_5A);
916         if(size <= cbBuf) {
917             ptr = pPrinter + size;
918             cbBuf -= size;
919             memset(pPrinter, 0, size);
920         } else {
921             pi5 = NULL;
922             cbBuf = 0;
923         }
924
925         ret = WINSPOOL_GetPrinter_5A(hkeyPrinter, pi5, ptr, cbBuf, &needed);
926         needed += size;
927         break;
928       }
929
930     default:
931         FIXME("Unimplemented level %ld\n", Level);
932         SetLastError(ERROR_INVALID_LEVEL);
933         RegCloseKey(hkeyPrinters);
934         RegCloseKey(hkeyPrinter);
935         return FALSE;
936     }
937
938     RegCloseKey(hkeyPrinter);
939     RegCloseKey(hkeyPrinters);
940
941     if(pcbNeeded) *pcbNeeded = needed;
942     if(!ret)
943         SetLastError(ERROR_INSUFFICIENT_BUFFER);
944     return ret;
945 }
946
947
948 /*****************************************************************************
949  *          GetPrinterW  [WINSPOOL.194]
950  */
951 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
952                     DWORD cbBuf, LPDWORD pcbNeeded)
953 {
954     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pPrinter,
955           cbBuf, pcbNeeded);
956     return FALSE;
957 }
958
959 /******************************************************************
960  *              EnumPrintersA        [WINSPOOL.174]
961  *
962  *    Enumerates the available printers, print servers and print
963  *    providers, depending on the specified flags, name and level.
964  *
965  * RETURNS:
966  *
967  *    If level is set to 1:
968  *      Not implemented yet! 
969  *      Returns TRUE with an empty list.
970  *
971  *    If level is set to 2:
972  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
973  *      Returns an array of PRINTER_INFO_2 data structures in the 
974  *      lpbPrinters buffer. Note that according to MSDN also an 
975  *      OpenPrinter should be performed on every remote printer.
976  *
977  *    If level is set to 4 (officially WinNT only):
978  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
979  *      Fast: Only the registry is queried to retrieve printer names,
980  *      no connection to the driver is made.
981  *      Returns an array of PRINTER_INFO_4 data structures in the 
982  *      lpbPrinters buffer.
983  *
984  *    If level is set to 5 (officially WinNT4/Win9x only):
985  *      Fast: Only the registry is queried to retrieve printer names,
986  *      no connection to the driver is made.
987  *      Returns an array of PRINTER_INFO_5 data structures in the 
988  *      lpbPrinters buffer.
989  *
990  *    If level set to 3 or 6+:
991  *          returns zero (faillure!)
992  *      
993  *    Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
994  *    for information.
995  *
996  * BUGS:
997  *    - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
998  *    - Only levels 2, 4 and 5 are implemented at the moment.
999  *    - 16-bit printer drivers are not enumerated.
1000  *    - Returned amount of bytes used/needed does not match the real Windoze 
1001  *      implementation (as in this implementation, all strings are part 
1002  *      of the buffer, whereas Win32 keeps them somewhere else)
1003  *    - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1004  *
1005  * NOTE:
1006  *    - In a regular Wine installation, no registry settings for printers
1007  *      exist, which makes this function return an empty list.
1008  */
1009 BOOL  WINAPI EnumPrintersA(
1010                 DWORD dwType,        /* Types of print objects to enumerate */
1011                 LPSTR lpszName,      /* name of objects to enumerate */
1012                 DWORD dwLevel,       /* type of printer info structure */
1013                 LPBYTE lpbPrinters,  /* buffer which receives info */
1014                 DWORD cbBuf,         /* max size of buffer in bytes */
1015                 LPDWORD lpdwNeeded,  /* pointer to var: # bytes used/needed */
1016                 LPDWORD lpdwReturned /* number of entries returned */
1017                 )
1018
1019 {
1020     HKEY hkeyPrinters, hkeyPrinter;
1021     char PrinterName[255];
1022     DWORD needed = 0, number = 0;
1023     DWORD used, i, left;
1024     PBYTE pi, buf;
1025
1026     if(lpbPrinters)
1027         memset(lpbPrinters, 0, cbBuf);
1028     if(lpdwReturned)
1029         *lpdwReturned = 0;
1030
1031     if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1032         FIXME("dwType = %08lx\n", dwType);
1033         SetLastError(ERROR_INVALID_FLAGS);
1034         return FALSE;
1035     }
1036
1037     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1038        ERROR_SUCCESS) {
1039         ERR("Can't create Printers key\n");
1040         return FALSE;
1041     }
1042   
1043     if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1044                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1045         RegCloseKey(hkeyPrinters);
1046         ERR("Can't query Printers key\n");
1047         return FALSE;
1048     }
1049     TRACE("Found %ld printers\n", number);
1050
1051     switch(dwLevel) {
1052     case 1:
1053         RegCloseKey(hkeyPrinters);
1054         if (lpdwReturned)
1055             *lpdwReturned = number;
1056         return TRUE;
1057
1058     case 2:
1059         used = number * sizeof(PRINTER_INFO_2A);
1060         break;
1061     case 4:
1062         used = number * sizeof(PRINTER_INFO_4A);
1063         break;
1064     case 5:
1065         used = number * sizeof(PRINTER_INFO_5A);
1066         break;
1067
1068     default:
1069         SetLastError(ERROR_INVALID_LEVEL);
1070         RegCloseKey(hkeyPrinters);
1071         return FALSE;
1072     }
1073     pi = (used <= cbBuf) ? lpbPrinters : NULL;
1074
1075     for(i = 0; i < number; i++) {
1076         if(RegEnumKeyA(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) != 
1077            ERROR_SUCCESS) {
1078             ERR("Can't enum key number %ld\n", i);
1079             RegCloseKey(hkeyPrinters);
1080             return FALSE;
1081         }
1082         if(RegOpenKeyA(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1083            ERROR_SUCCESS) {
1084             ERR("Can't open key '%s'\n", PrinterName);
1085             RegCloseKey(hkeyPrinters);
1086             return FALSE;
1087         }
1088
1089         if(cbBuf > used) {
1090             buf = lpbPrinters + used;
1091             left = cbBuf - used;
1092         } else {
1093             buf = NULL;
1094             left = 0;
1095         }
1096
1097         switch(dwLevel) {
1098         case 2:
1099             WINSPOOL_GetPrinter_2A(hkeyPrinter, (PRINTER_INFO_2A *)pi, buf,
1100                                    left, &needed);
1101             used += needed;
1102             if(pi) pi += sizeof(PRINTER_INFO_2A);
1103             break;
1104         case 4:
1105             WINSPOOL_GetPrinter_4A(hkeyPrinter, (PRINTER_INFO_4A *)pi, buf,
1106                                    left, &needed);
1107             used += needed;
1108             if(pi) pi += sizeof(PRINTER_INFO_4A);
1109             break;
1110         case 5:
1111             WINSPOOL_GetPrinter_5A(hkeyPrinter, (PRINTER_INFO_5A *)pi, buf,
1112                                    left, &needed);
1113             used += needed;
1114             if(pi) pi += sizeof(PRINTER_INFO_5A);
1115             break;
1116         default:
1117             ERR("Shouldn't be here!\n");
1118             RegCloseKey(hkeyPrinter);
1119             RegCloseKey(hkeyPrinters);
1120             return FALSE;
1121         }
1122         RegCloseKey(hkeyPrinter);
1123     }
1124     RegCloseKey(hkeyPrinters);
1125
1126     if(lpdwNeeded)
1127         *lpdwNeeded = used;
1128     if(used > cbBuf) {
1129         if(lpbPrinters)
1130             memset(lpbPrinters, 0, cbBuf);
1131         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1132         return FALSE;
1133     }
1134     if(lpdwReturned)
1135         *lpdwReturned = number;  
1136     SetLastError(ERROR_SUCCESS);
1137     return TRUE;
1138 }
1139
1140 /******************************************************************
1141  *              EnumPrintersW        [WINSPOOL.175]
1142  *
1143  */
1144 BOOL  WINAPI EnumPrintersW(DWORD dwType, LPWSTR lpszName,
1145                                DWORD dwLevel, LPBYTE lpbPrinters,
1146                                DWORD cbBuf, LPDWORD lpdwNeeded,
1147                                LPDWORD lpdwReturned)
1148 {
1149     FIXME("Nearly empty stub\n");
1150     *lpdwReturned=0;
1151     *lpdwNeeded = 0;
1152     return TRUE;
1153 }
1154
1155
1156 /*****************************************************************************
1157  *          GetPrinterDriver32A  [WINSPOOL.190]
1158  */
1159 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1160                               DWORD Level, LPBYTE pDriverInfo,
1161                               DWORD cbBuf, LPDWORD pcbNeeded)
1162 {
1163     OPENEDPRINTERA *lpOpenedPrinter;
1164     char DriverName[100];
1165     DWORD ret, type, size, dw, needed = 0;
1166     LPBYTE ptr = NULL;
1167     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1168     
1169     TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,pEnvironment,
1170          Level,pDriverInfo,cbBuf, pcbNeeded);
1171
1172     ZeroMemory(pDriverInfo, cbBuf);
1173
1174     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1175     if(!lpOpenedPrinter) {
1176         SetLastError(ERROR_INVALID_HANDLE);
1177         return FALSE;
1178     }
1179     if(pEnvironment) {
1180         FIXME("pEnvironment = `%s'\n", pEnvironment);
1181         SetLastError(ERROR_INVALID_ENVIRONMENT);
1182         return FALSE;
1183     }
1184     if(Level < 1 || Level > 3) {
1185         SetLastError(ERROR_INVALID_LEVEL);
1186         return FALSE;
1187     }
1188     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1189        ERROR_SUCCESS) {
1190         ERR("Can't create Printers key\n");
1191         return FALSE;
1192     }
1193     if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1194        != ERROR_SUCCESS) {
1195         ERR("Can't find opened printer `%s' in registry\n",
1196             lpOpenedPrinter->lpsPrinterName);
1197         RegCloseKey(hkeyPrinters);
1198         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1199         return FALSE;
1200     }
1201     size = sizeof(DriverName);
1202     ret = RegQueryValueExA(hkeyPrinter, "Printer Driver", 0, &type, DriverName,
1203                            &size);
1204     RegCloseKey(hkeyPrinter);
1205     RegCloseKey(hkeyPrinters);
1206     if(ret != ERROR_SUCCESS) {
1207         ERR("Can't get DriverName for printer `%s'\n",
1208             lpOpenedPrinter->lpsPrinterName);
1209         return FALSE;
1210     }
1211     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1212        ERROR_SUCCESS) {
1213         ERR("Can't create Drivers key\n");
1214         return FALSE;
1215     }
1216     if(RegOpenKeyA(hkeyDrivers, DriverName, &hkeyDriver)
1217        != ERROR_SUCCESS) {
1218         ERR("Can't find driver `%s' in registry\n", DriverName);
1219         RegCloseKey(hkeyDrivers);
1220         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1221         return FALSE;
1222     }
1223
1224     switch(Level) {
1225     case 1:
1226         size = sizeof(DRIVER_INFO_1A);
1227         break;
1228     case 2:
1229         size = sizeof(DRIVER_INFO_2A);
1230         break;
1231     case 3:
1232         size = sizeof(DRIVER_INFO_3A);
1233         break;
1234     default:
1235         ERR("Invalid level\n");
1236         return FALSE;
1237     }
1238
1239     if(size <= cbBuf) {
1240         ptr = pDriverInfo + size;
1241         cbBuf -= size;
1242     } else
1243         cbBuf = 0;
1244     needed = size;
1245
1246     size = strlen(DriverName) + 1;
1247     if(size <= cbBuf) {
1248         cbBuf -= size;
1249         strcpy(ptr, DriverName);
1250         if(Level == 1)
1251             ((DRIVER_INFO_1A *)pDriverInfo)->pName = ptr;
1252         else
1253             ((DRIVER_INFO_2A *)pDriverInfo)->pName = ptr;    
1254         ptr += size;
1255     }
1256     needed += size;
1257
1258     if(Level > 1) {
1259         DRIVER_INFO_2A *di2 = (DRIVER_INFO_2A *)pDriverInfo;
1260
1261         size = sizeof(dw);
1262         if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw,
1263                             &size) !=
1264            ERROR_SUCCESS)
1265             WARN("Can't get Version\n");
1266         else if(cbBuf)
1267             di2->cVersion = dw;
1268
1269         size = strlen("Wine") + 1;  /* FIXME */
1270         if(size <= cbBuf) {
1271             cbBuf -= size;
1272             strcpy(ptr, "Wine");
1273             di2->pEnvironment = ptr;
1274             ptr += size;
1275         } else 
1276             cbBuf = 0;
1277         needed += size;
1278
1279         WINSPOOL_GetStringFromRegA(hkeyDriver, "Driver", ptr, cbBuf, &size);
1280         if(cbBuf && size <= cbBuf) {
1281             di2->pDriverPath = ptr;
1282             ptr += size;
1283         } else
1284             cbBuf = 0;
1285         needed += size;
1286
1287         WINSPOOL_GetStringFromRegA(hkeyDriver, "Data File", ptr, cbBuf, &size);
1288         if(cbBuf && size <= cbBuf) {
1289             di2->pDataFile = ptr;
1290             ptr += size;
1291         } else
1292             cbBuf = 0;
1293         needed += size;
1294
1295         WINSPOOL_GetStringFromRegA(hkeyDriver, "Configuration File", ptr,
1296                                    cbBuf, &size);
1297         if(cbBuf && size <= cbBuf) {
1298             di2->pConfigFile = ptr;
1299             ptr += size;
1300         } else
1301             cbBuf = 0;
1302         needed += size;
1303     }
1304
1305     if(Level > 2) {
1306         DRIVER_INFO_3A *di3 = (DRIVER_INFO_3A *)pDriverInfo;
1307
1308         WINSPOOL_GetStringFromRegA(hkeyDriver, "Help File", ptr, cbBuf, &size);
1309         if(cbBuf && size <= cbBuf) {
1310             di3->pHelpFile = ptr;
1311             ptr += size;
1312         } else
1313             cbBuf = 0;
1314         needed += size;
1315
1316         WINSPOOL_GetStringFromRegA(hkeyDriver, "Dependent Files", ptr, cbBuf,
1317                                    &size);
1318         if(cbBuf && size <= cbBuf) {
1319             di3->pDependentFiles = ptr;
1320             ptr += size;
1321         } else
1322             cbBuf = 0;
1323         needed += size;
1324
1325         WINSPOOL_GetStringFromRegA(hkeyDriver, "Monitor", ptr, cbBuf, &size);
1326         if(cbBuf && size <= cbBuf) {
1327             di3->pMonitorName = ptr;
1328             ptr += size;
1329         } else
1330             cbBuf = 0;
1331         needed += size;
1332
1333         WINSPOOL_GetStringFromRegA(hkeyDriver, "DataType", ptr, cbBuf, &size);
1334         if(cbBuf && size <= cbBuf) {
1335             di3->pDefaultDataType = ptr;
1336             ptr += size;
1337         } else
1338             cbBuf = 0;
1339         needed += size;
1340     }
1341     RegCloseKey(hkeyDriver);
1342     RegCloseKey(hkeyDrivers);
1343
1344     if(pcbNeeded) *pcbNeeded = needed;
1345     if(cbBuf) return TRUE;
1346     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1347     return FALSE;
1348 }
1349
1350 /*****************************************************************************
1351  *          GetPrinterDriver32W  [WINSPOOL.193]
1352  */
1353 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1354                                   DWORD Level, LPBYTE pDriverInfo, 
1355                                   DWORD cbBuf, LPDWORD pcbNeeded)
1356 {
1357     FIXME("(%d,%p,%ld,%p,%ld,%p): stub\n",hPrinter,pEnvironment,
1358           Level,pDriverInfo,cbBuf, pcbNeeded);
1359     return FALSE;
1360 }
1361
1362 /*****************************************************************************
1363  *       GetPrinterDriverDirectoryA  [WINSPOOL.191]
1364  */
1365 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1366                                        DWORD Level, LPBYTE pDriverDirectory,
1367                                        DWORD cbBuf, LPDWORD pcbNeeded)
1368 {
1369     DWORD needed;
1370
1371     TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1372           pDriverDirectory, cbBuf, pcbNeeded);
1373     if(pName != NULL) {
1374         FIXME("pName = `%s' - unsupported\n", pName);
1375         SetLastError(ERROR_INVALID_PARAMETER);
1376         return FALSE;
1377     }
1378     if(pEnvironment != NULL) {
1379         FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1380         SetLastError(ERROR_INVALID_ENVIRONMENT);
1381         return FALSE;
1382     }
1383     if(Level != 1)  /* win95 ignores this so we just carry on */
1384         WARN("Level = %ld - assuming 1\n", Level);
1385     
1386     /* FIXME should read from registry */
1387     needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
1388     needed++;
1389     if(pcbNeeded)
1390         *pcbNeeded = needed;
1391     if(needed > cbBuf) {
1392         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1393         return FALSE;
1394     }
1395     return TRUE;
1396 }
1397
1398
1399 /*****************************************************************************
1400  *       GetPrinterDriverDirectoryW  [WINSPOOL.192]
1401  */
1402 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
1403                                        DWORD Level, LPBYTE pDriverDirectory,
1404                                        DWORD cbBuf, LPDWORD pcbNeeded)
1405 {
1406     LPSTR pNameA = NULL, pEnvironmentA = NULL;
1407     BOOL ret;
1408
1409     if(pName)
1410         pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
1411     if(pEnvironment)
1412         pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
1413     ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
1414                                       pDriverDirectory, cbBuf, pcbNeeded );
1415     if(pNameA)
1416         HeapFree( GetProcessHeap(), 0, pNameA );
1417     if(pEnvironmentA)
1418         HeapFree( GetProcessHeap(), 0, pEnvironment );
1419
1420     return ret;
1421 }
1422
1423 /*****************************************************************************
1424  *          AddPrinterDriver32A  [WINSPOOL.120]
1425  */
1426 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
1427 {
1428     DRIVER_INFO_3A di3;
1429     HKEY hkeyDrivers, hkeyName;
1430
1431     TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
1432
1433     if(level != 2 && level != 3) {
1434         SetLastError(ERROR_INVALID_LEVEL);
1435         return FALSE;
1436     }
1437     if(pName != NULL) {
1438         FIXME("pName= `%s' - unsupported\n", pName);
1439         SetLastError(ERROR_INVALID_PARAMETER);
1440         return FALSE;
1441     }
1442     if(!pDriverInfo) {
1443         WARN("pDriverInfo == NULL");
1444         SetLastError(ERROR_INVALID_PARAMETER);
1445         return FALSE;
1446     }
1447     
1448     if(level == 3)
1449         di3 = *(DRIVER_INFO_3A *)pDriverInfo;
1450     else {
1451         memset(&di3, 0, sizeof(di3));
1452         *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
1453     }
1454
1455     if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
1456        !di3.pDataFile) {
1457         SetLastError(ERROR_INVALID_PARAMETER);
1458         return FALSE;
1459     }
1460     if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
1461     if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
1462     if(!di3.pHelpFile) di3.pHelpFile = "";
1463     if(!di3.pMonitorName) di3.pMonitorName = "";
1464
1465     if(di3.pEnvironment) {
1466         FIXME("pEnvironment = `%s'\n", di3.pEnvironment);
1467         SetLastError(ERROR_INVALID_ENVIRONMENT);
1468         return FALSE;
1469     }
1470     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1471        ERROR_SUCCESS) {
1472         ERR("Can't create Drivers key\n");
1473         return FALSE;
1474     }
1475
1476     if(level == 2) { /* apparently can't overwrite with level2 */
1477         if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
1478             RegCloseKey(hkeyName);
1479             RegCloseKey(hkeyDrivers);
1480             WARN("Trying to create existing printer driver `%s'\n", di3.pName);
1481             SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1482             return FALSE;
1483         }
1484     }
1485     if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
1486         RegCloseKey(hkeyDrivers);
1487         ERR("Can't create Name key\n");
1488         return FALSE;
1489     }
1490     RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
1491                    0);
1492     RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
1493     RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
1494     RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion, 
1495                    sizeof(DWORD));
1496     RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
1497     RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
1498                    di3.pDependentFiles, 0);
1499     RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
1500     RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
1501     RegCloseKey(hkeyName);
1502     RegCloseKey(hkeyDrivers);
1503
1504     return TRUE;
1505 }
1506 /*****************************************************************************
1507  *          AddPrinterDriver32W  [WINSPOOL.121]
1508  */
1509 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level, 
1510                                    LPBYTE pDriverInfo)
1511 {
1512     FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
1513           level,pDriverInfo);
1514     return FALSE;
1515 }
1516
1517
1518 /*****************************************************************************
1519  *          PrinterProperties  [WINSPOOL.201]
1520  *
1521  *     Displays a dialog to set the properties of the printer.
1522  *
1523  * RETURNS 
1524  *     nonzero on succes or zero on faillure
1525  *
1526  * BUGS
1527  *         implemented as stub only
1528  */
1529 BOOL WINAPI PrinterProperties(HWND hWnd,      /* handle to parent window */
1530                               HANDLE hPrinter /* handle to printer object */
1531 ){
1532     FIXME("(%d,%d): stub\n", hWnd, hPrinter);
1533     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1534     return FALSE;
1535 }
1536
1537 /*****************************************************************************
1538  *          EnumJobsA [WINSPOOL.162]
1539  *
1540  */
1541 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
1542                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
1543                       LPDWORD pcReturned)
1544 {
1545     FIXME("stub\n");
1546     if(pcbNeeded) *pcbNeeded = 0;
1547     if(pcReturned) *pcReturned = 0;
1548     return TRUE;
1549 }
1550
1551
1552 /*****************************************************************************
1553  *          EnumJobsW [WINSPOOL.163]
1554  *
1555  */
1556 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
1557                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
1558                       LPDWORD pcReturned)
1559 {
1560     FIXME("stub\n");
1561     if(pcbNeeded) *pcbNeeded = 0;
1562     if(pcReturned) *pcReturned = 0;
1563     return TRUE;
1564 }