Replaced a static ten element array with a dynamic pointer array.
[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  */
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\\Wine\\Drivers\\";
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((printerHandle <=0) || 
107        (printerHandle > (pOpenedPrinterDPA->nItemCount - 1)))
108         return NULL;
109
110     pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle);
111
112     return pOpenedPrinter;
113 }
114
115 /******************************************************************
116  *              DeviceCapabilities32A    [WINSPOOL.151]
117  *
118  */
119 INT WINAPI DeviceCapabilitiesA(LPCSTR pDeivce,LPCSTR pPort, WORD cap,
120                                LPSTR pOutput, LPDEVMODEA lpdm)
121 {
122     return GDI_CallDeviceCapabilities16(pDeivce, pPort, cap, pOutput, lpdm);
123
124 }
125
126
127 /*****************************************************************************
128  *          DeviceCapabilities32W 
129  */
130 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
131                                WORD fwCapability, LPWSTR pOutput,
132                                const DEVMODEW *pDevMode)
133 {
134     FIXME("(%p,%p,%d,%p,%p): stub\n",
135           pDevice, pPort, fwCapability, pOutput, pDevMode);
136     return -1;
137 }
138
139 /******************************************************************
140  *              DocumentProperties32A   [WINSPOOL.155]
141  *
142  */
143 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
144                                 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
145                                 LPDEVMODEA pDevModeInput,DWORD fMode )
146 {
147     LPOPENEDPRINTERA lpOpenedPrinter;
148     LPSTR lpName = pDeviceName;
149
150     TRACE("(%d,%d,%s,%p,%p,%ld)\n",
151         hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
152     );
153
154     if(!pDeviceName) {
155         lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
156         if(!lpOpenedPrinter) {
157             SetLastError(ERROR_INVALID_HANDLE);
158             return -1;
159         }
160         lpName = lpOpenedPrinter->lpsPrinterName;
161     }
162
163     return GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, NULL,
164                                    pDevModeInput, NULL, fMode);
165
166 }
167
168
169 /*****************************************************************************
170  *          DocumentProperties32W 
171  */
172 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
173                                   LPWSTR pDeviceName,
174                                   LPDEVMODEW pDevModeOutput,
175                                   LPDEVMODEW pDevModeInput, DWORD fMode)
176 {
177     FIXME("(%d,%d,%s,%p,%p,%ld): stub\n",
178           hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
179           fMode);
180     return -1;
181 }
182
183
184 /******************************************************************
185  *              OpenPrinter32A        [WINSPOOL.196]
186  *
187  */
188 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
189                              LPPRINTER_DEFAULTSA pDefault)
190 {
191   /* Not implemented: use the DesiredAccess of pDefault to set 
192      the access rights to the printer */
193
194     LPOPENEDPRINTERA lpOpenedPrinter;
195
196     TRACE("(printerName: %s, pDefault %p\n", lpPrinterName, pDefault);
197
198     /* Get a place in the opened printer buffer*/
199     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntryA();
200
201     if((lpOpenedPrinter != NULL) && (lpPrinterName !=NULL) && 
202        (phPrinter != NULL))
203     {
204         /* Get the name of the printer */
205         lpOpenedPrinter->lpsPrinterName = 
206           HeapAlloc(GetProcessHeap(), 0, lstrlenA(lpPrinterName));
207         lstrcpyA(lpOpenedPrinter->lpsPrinterName, lpPrinterName);
208
209         /* Get the unique handle of the printer*/
210         *phPrinter = lpOpenedPrinter->hPrinter;
211
212         if (pDefault != NULL)
213         {
214             /* Allocate enough memory for the lpDefault structure */
215             lpOpenedPrinter->lpDefault = 
216               HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTER_DEFAULTSA));
217             lpOpenedPrinter->lpDefault->pDevMode =
218               HeapAlloc(GetProcessHeap(), 0, sizeof(DEVMODEA));
219             lpOpenedPrinter->lpDefault->pDatatype = 
220               HeapAlloc(GetProcessHeap(), 0, lstrlenA(pDefault->pDatatype));
221
222             /*Copy the information from incoming parameter*/
223             memcpy(lpOpenedPrinter->lpDefault->pDevMode, pDefault->pDevMode,
224                    sizeof(DEVMODEA));
225             lstrcpyA(lpOpenedPrinter->lpDefault->pDatatype,
226                      pDefault->pDatatype);
227             lpOpenedPrinter->lpDefault->DesiredAccess =
228               pDefault->DesiredAccess;
229         }
230
231         return TRUE;
232     }
233
234     if(lpOpenedPrinter == NULL)
235         FIXME("Reach the OpenedPrinterTable maximum, augment this max.\n");
236      return FALSE;
237 }
238
239 /******************************************************************
240  *              OpenPrinter32W        [WINSPOOL.197]
241  *
242  */
243 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
244                              LPPRINTER_DEFAULTSW pDefault)
245 {
246     FIXME("(%s,%p,%p):stub\n",debugstr_w(lpPrinterName), phPrinter,
247           pDefault);
248     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
249     return FALSE;
250 }
251
252
253
254
255 /******************************************************************
256  *              ENUMPRINTERS_GetDWORDFromRegistryA    internal
257  *
258  * Reads a DWORD from registry KeyName 
259  *
260  * RETURNS
261  *    value on OK or NULL on error
262  */
263 DWORD ENUMPRINTERS_GetDWORDFromRegistryA(
264                  HKEY  hPrinterSettings,  /* handle to registry key */
265                  LPSTR KeyName            /* name key to retrieve string from*/
266 ){
267  DWORD DataSize=8;
268  DWORD DataType;
269  BYTE  Data[8];
270  DWORD Result=684;
271
272  if (RegQueryValueExA(hPrinterSettings, KeyName, NULL, &DataType,
273                                         Data, &DataSize)!=ERROR_SUCCESS)
274         FIXME("Query of register '%s' didn't succeed?\n", KeyName);
275  if (DataType == REG_DWORD_LITTLE_ENDIAN)
276         Result = Data[0] + (Data[1]<<8) + (Data[2]<<16) + (Data[3]<<24);
277  if (DataType == REG_DWORD_BIG_ENDIAN)
278         Result = Data[3] + (Data[2]<<8) + (Data[1]<<16) + (Data[0]<<24);
279  return(Result);
280 }
281
282
283 /******************************************************************
284  *              ENUMPRINTERS_AddStringFromRegistryA    internal
285  *
286  * Reads a string from registry KeyName and writes it at
287  * lpbPrinters[dwNextStringPos]. Store reference to string in Dest.
288  *
289  * RETURNS
290  *    FALSE if there is still space left in the buffer.
291  */
292 BOOL ENUMPRINTERS_AddStringFromRegistryA(
293                 HKEY  hPrinterSettings, /* handle to registry key */
294                 LPSTR KeyName,          /* name key to retrieve string from*/
295                 LPSTR* Dest,            /* pointer to write string addres to */
296                 LPBYTE lpbPrinters,     /* buffer which receives info*/
297                 LPDWORD dwNextStringPos,/* pos in buffer for next string */
298                 DWORD  dwBufSize,       /* max size of buffer in bytes */
299                 BOOL   bCalcSpaceOnly   /* TRUE if out-of-space in buffer */
300 ){                   
301  DWORD DataSize=34;
302  DWORD DataType;
303  LPSTR Data = (LPSTR) malloc(DataSize*sizeof(char));
304
305  while(RegQueryValueExA(hPrinterSettings, KeyName, NULL, &DataType,
306                                         Data, &DataSize)==ERROR_MORE_DATA)
307     {
308      Data = (LPSTR) realloc(Data, DataSize+2);
309     }
310
311  if (DataType == REG_SZ)
312         {                   
313          if (bCalcSpaceOnly==FALSE)
314          *Dest = &lpbPrinters[*dwNextStringPos];
315          *dwNextStringPos += DataSize+1;
316          if (*dwNextStringPos > dwBufSize)
317                 bCalcSpaceOnly=TRUE;
318          if (bCalcSpaceOnly==FALSE)
319         {
320          if (DataSize==0)               /* DataSize = 0 means empty string, even though*/
321                 *Dest[0]=0;                     /* the data itself needs not to be empty */
322          else
323                  strcpy(*Dest, Data);
324         }
325         }
326  else
327         WARN("Expected string setting, got something else from registry");
328     
329  if (Data)
330     free(Data);
331  return(bCalcSpaceOnly);
332 }
333
334
335
336 /******************************************************************
337  *              ENUMPRINTERS_AddInfo2A        internal
338  *
339  *    Creates a PRINTER_INFO_2A structure at:  lpbPrinters[dwNextStructPos]
340  *    for printer PrinterNameKey.
341  *    Note that there is no check whether the information really fits!
342  *
343  * RETURNS
344  *    FALSE if there is still space left in the buffer.
345  *
346  * BUGS:
347  *    This function should not only read the registry but also ask the driver
348  *    for information.
349  */
350 BOOL ENUMPRINTERS_AddInfo2A(
351                    LPSTR lpszPrinterName,/* name of printer to fill struct for*/
352                    LPBYTE lpbPrinters,   /* buffer which receives info*/
353                    DWORD  dwNextStructPos,  /* pos in buffer for struct */
354                    LPDWORD dwNextStringPos, /* pos in buffer for next string */
355                                    DWORD  dwBufSize,        /* max size of buffer in bytes */
356                    BOOL   bCalcSpaceOnly    /* TRUE if out-of-space in buffer */
357 ){                   
358  HKEY  hPrinterSettings;
359  DWORD DevSize=0;
360  DWORD DataType;
361  LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
362                                                                                            strlen(lpszPrinterName)+2);
363  LPPRINTER_INFO_2A lpPInfo2 = (LPPRINTER_INFO_2A) &lpbPrinters[dwNextStructPos];
364
365  /* open the registry to find the attributes, etc of the printer */
366  if (lpszPrinterSettings!=NULL)
367         {
368      strcpy(lpszPrinterSettings,Printers);
369      strcat(lpszPrinterSettings,lpszPrinterName);
370     }
371  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0, 
372                                                 KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
373         {
374      WARN("The registry did not contain my printer anymore?\n");
375     }
376  else
377     {
378      if (bCalcSpaceOnly==FALSE)
379      lpPInfo2->pServerName = NULL;
380      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
381                                           "Name", &(lpPInfo2->pPrinterName), 
382                                   lpbPrinters, dwNextStringPos, 
383                                   dwBufSize, bCalcSpaceOnly);
384      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
385                                           "Share Name", &(lpPInfo2->pShareName), 
386                                   lpbPrinters, dwNextStringPos, 
387                                   dwBufSize, bCalcSpaceOnly);
388      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
389                                           "Port", &(lpPInfo2->pPortName), 
390                                   lpbPrinters, dwNextStringPos, 
391                                   dwBufSize, bCalcSpaceOnly);
392      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
393                                           "Printer Driver", &(lpPInfo2->pDriverName), 
394                                   lpbPrinters, dwNextStringPos, 
395                                   dwBufSize, bCalcSpaceOnly);
396      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
397                                           "Description", &(lpPInfo2->pComment), 
398                                   lpbPrinters, dwNextStringPos, 
399                                   dwBufSize, bCalcSpaceOnly);
400      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
401                                           "Location", &(lpPInfo2->pLocation), 
402                                   lpbPrinters, dwNextStringPos, 
403                                   dwBufSize, bCalcSpaceOnly);
404
405      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
406                                           "Separator File", &(lpPInfo2->pSepFile), 
407                                   lpbPrinters, dwNextStringPos, 
408                                   dwBufSize, bCalcSpaceOnly);
409      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
410                                           "Print Processor", &(lpPInfo2->pPrintProcessor), 
411                                   lpbPrinters, dwNextStringPos, 
412                                   dwBufSize, bCalcSpaceOnly);
413      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
414                                           "Datatype", &(lpPInfo2->pDatatype), 
415                                   lpbPrinters, dwNextStringPos, 
416                                   dwBufSize, bCalcSpaceOnly);
417      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
418                                           "Parameters", &(lpPInfo2->pParameters), 
419                                   lpbPrinters, dwNextStringPos, 
420                                   dwBufSize, bCalcSpaceOnly);
421      if (bCalcSpaceOnly == FALSE)
422         {                             
423      lpPInfo2->pSecurityDescriptor = NULL; /* EnumPrinters doesn't return this*/
424
425                                           /* FIXME: Attributes gets LOCAL as no REMOTE exists*/
426          lpPInfo2->Attributes = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
427                                                                 "Attributes") +PRINTER_ATTRIBUTE_LOCAL; 
428          lpPInfo2->Priority   = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
429                                                                 "Priority"); 
430          lpPInfo2->DefaultPriority = ENUMPRINTERS_GetDWORDFromRegistryA(
431                                                                 hPrinterSettings, "Default Priority"); 
432          lpPInfo2->StartTime  = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
433                                                                 "StartTime"); 
434          lpPInfo2->UntilTime  = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
435                                                                 "UntilTime"); 
436          lpPInfo2->Status     = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
437                                                                 "Status"); 
438          lpPInfo2->cJobs      = 0;    /* FIXME: according to MSDN, this does not 
439                                                            * reflect the TotalJobs Key ??? */
440          lpPInfo2->AveragePPM = 0;    /* FIXME: according to MSDN, this does not 
441                                                            * reflect the TotalPages Key ??? */
442
443      /* and read the devModes structure... */
444       RegQueryValueExA(hPrinterSettings, "pDevMode", NULL, &DataType,
445                                         NULL, &DevSize); /* should return ERROR_MORE_DATA */
446               lpPInfo2->pDevMode = (LPDEVMODEA) &lpbPrinters[*dwNextStringPos];
447       *dwNextStringPos += DevSize + 1;      
448         } 
449  if (*dwNextStringPos > dwBufSize)
450         bCalcSpaceOnly=TRUE;
451  if (bCalcSpaceOnly==FALSE)
452               RegQueryValueExA(hPrinterSettings, "pDevMode", NULL, &DataType,
453                                         (LPBYTE)lpPInfo2->pDevMode, &DevSize); 
454         }                                 
455
456  if (lpszPrinterSettings)
457          free(lpszPrinterSettings);
458
459  return(bCalcSpaceOnly);     
460 }
461
462 /******************************************************************
463  *              ENUMPRINTERS_AddInfo4A        internal
464  *
465  *    Creates a PRINTER_INFO_4A structure at:  lpbPrinters[dwNextStructPos]
466  *    for printer PrinterNameKey.
467  *    Note that there is no check whether the information really fits!
468  *
469  * RETURNS
470  *    FALSE if there is still space left in the buffer.
471  *
472  * BUGS:
473  *    This function should not exist in Win95 mode, but does anyway.
474  */
475 BOOL ENUMPRINTERS_AddInfo4A(
476                    LPSTR lpszPrinterName,/* name of printer to fill struct for*/
477                    LPBYTE lpbPrinters,   /* buffer which receives info*/
478                    DWORD  dwNextStructPos,  /* pos in buffer for struct */
479                    LPDWORD dwNextStringPos, /* pos in buffer for next string */
480                                    DWORD  dwBufSize,        /* max size of buffer in bytes */
481                    BOOL   bCalcSpaceOnly    /* TRUE if out-of-space in buffer */
482 ){                   
483  HKEY  hPrinterSettings;
484  LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
485                                                                                            strlen(lpszPrinterName)+2);
486  LPPRINTER_INFO_4A lpPInfo4 = (LPPRINTER_INFO_4A) &lpbPrinters[dwNextStructPos];
487  
488  /* open the registry to find the attributes of the printer */
489  if (lpszPrinterSettings!=NULL)
490         {
491      strcpy(lpszPrinterSettings,Printers);
492      strcat(lpszPrinterSettings,lpszPrinterName);
493     }
494  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0, 
495                                                 KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
496         {
497      WARN("The registry did not contain my printer anymore?\n");
498     }
499  else
500     {
501      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
502                                           "Name", &(lpPInfo4->pPrinterName), 
503                                   lpbPrinters, dwNextStringPos, 
504                                   dwBufSize, bCalcSpaceOnly);
505                                           /* FIXME: Attributes gets LOCAL as no REMOTE exists*/
506      if (bCalcSpaceOnly==FALSE)                      
507          lpPInfo4->Attributes = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
508                                                                 "Attributes") +PRINTER_ATTRIBUTE_LOCAL; 
509     }
510  if (lpszPrinterSettings)
511          free(lpszPrinterSettings);
512
513  return(bCalcSpaceOnly);     
514 }
515
516 /******************************************************************
517  *              ENUMPRINTERS_AddInfo5A        internal
518  *
519  *    Creates a PRINTER_INFO_5A structure at:  lpbPrinters[dwNextStructPos]
520  *    for printer PrinterNameKey.
521  *    Settings are read from the registry.
522  *    Note that there is no check whether the information really fits!
523  * RETURNS
524  *    FALSE if there is still space left in the buffer.
525  */
526 BOOL ENUMPRINTERS_AddInfo5A(
527                    LPSTR lpszPrinterName,/* name of printer to fill struct for*/
528                    LPBYTE lpbPrinters,   /* buffer which receives info*/
529                    DWORD  dwNextStructPos,  /* pos in buffer for struct */
530                    LPDWORD dwNextStringPos, /* pos in buffer for next string */
531                                    DWORD  dwBufSize,        /* max size of buffer in bytes */
532                    BOOL   bCalcSpaceOnly    /* TRUE if out-of-space in buffer */
533 ){                   
534  HKEY  hPrinterSettings;
535  LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
536                                                                                            strlen(lpszPrinterName)+2);
537  LPPRINTER_INFO_5A lpPInfo5 = (LPPRINTER_INFO_5A) &lpbPrinters[dwNextStructPos];
538
539  /* open the registry to find the attributes, etc of the printer */
540  if (lpszPrinterSettings!=NULL)
541         {
542      strcpy(lpszPrinterSettings,Printers);
543      strcat(lpszPrinterSettings,lpszPrinterName);
544     }
545  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0, 
546                                                 KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
547         {
548      WARN("The registry did not contain my printer anymore?\n");
549     }
550  else
551     {
552      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
553                                           "Name", &(lpPInfo5->pPrinterName), 
554                                   lpbPrinters, dwNextStringPos, 
555                                   dwBufSize, bCalcSpaceOnly);
556      bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings, 
557                                           "Port", &(lpPInfo5->pPortName), lpbPrinters,
558                                   dwNextStringPos, dwBufSize, bCalcSpaceOnly);
559                                           /* FIXME: Attributes gets LOCAL as no REMOTE exists*/
560      if (bCalcSpaceOnly == FALSE)
561            {
562          lpPInfo5->Attributes = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
563                                                                 "Attributes") +PRINTER_ATTRIBUTE_LOCAL; 
564          lpPInfo5->DeviceNotSelectedTimeOut 
565                                           = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
566                                                                 "txTimeout"); 
567          lpPInfo5->TransmissionRetryTimeout
568                                           = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
569                                                                 "dnsTimeout"); 
570     }
571     }
572     
573  if (lpszPrinterSettings)
574          free(lpszPrinterSettings);
575
576  return(bCalcSpaceOnly);     
577 }
578
579
580 /******************************************************************
581  *              EnumPrintersA        [WINSPOOL.174]
582  *
583  *    Enumerates the available printers, print servers and print
584  *    providers, depending on the specified flags, name and level.
585  *
586  * RETURNS:
587  *
588  *    If level is set to 1:
589  *      Not implemented yet! 
590  *      Returns TRUE with an empty list.
591  *
592  *    If level is set to 2:
593  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
594  *      Returns an array of PRINTER_INFO_2 data structures in the 
595  *      lpbPrinters buffer. Note that according to MSDN also an 
596  *      OpenPrinter should be performed on every remote printer.
597  *
598  *    If level is set to 4 (officially WinNT only):
599  *              Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
600  *      Fast: Only the registry is queried to retrieve printer names,
601  *      no connection to the driver is made.
602  *      Returns an array of PRINTER_INFO_4 data structures in the 
603  *      lpbPrinters buffer.
604  *
605  *    If level is set to 5 (officially WinNT4/Win9x only):
606  *      Fast: Only the registry is queried to retrieve printer names,
607  *      no connection to the driver is made.
608  *      Returns an array of PRINTER_INFO_5 data structures in the 
609  *      lpbPrinters buffer.
610  *
611  *    If level set to 3 or 6+:
612  *          returns zero (faillure!)
613  *      
614  *    Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
615  *    for information.
616  *
617  * BUGS:
618  *    - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
619  *    - Only levels 2, 4 and 5 are implemented at the moment.
620  *    - 16-bit printer drivers are not enumerated.
621  *    - Returned amount of bytes used/needed does not match the real Windoze 
622  *      implementation (as in this implementation, all strings are part 
623  *      of the buffer, whereas Win32 keeps them somewhere else)
624  *    - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
625  *
626  * NOTE:
627  *    - In a regular Wine installation, no registry settings for printers
628  *      exist, which makes this function return an empty list.
629  */
630 BOOL  WINAPI EnumPrintersA(
631                 DWORD dwType,        /* Types of print objects to enumerate */
632                 LPSTR lpszName,      /* name of objects to enumerate */
633                 DWORD dwLevel,       /* type of printer info structure */
634                 LPBYTE lpbPrinters,  /* buffer which receives info */
635                 DWORD cbBuf,         /* max size of buffer in bytes */
636                 LPDWORD lpdwNeeded,  /* pointer to var: # bytes used/needed */
637                 LPDWORD lpdwReturned /* number of entries returned */
638                 )
639 {
640  HKEY  hPrinterListKey;
641  DWORD dwIndex=0;
642  char  PrinterName[255];
643  DWORD PrinterNameLength=255;
644  FILETIME FileTime;
645  DWORD dwNextStringPos;  /* position of next space for a string in the buffer*/
646  DWORD dwStructPrinterInfoSize; /* size of a Printer_Info_X structure */
647  BOOL  bCalcSpaceOnly=FALSE;/*if TRUE: don't store data, just calculate space*/
648  
649  TRACE("entered.\n");
650
651  /* test whether we're requested to really fill in. If so,
652   * zero out the data area, and initialise some returns to zero,
653   * to prevent problems 
654   */
655  if (lpbPrinters==NULL || cbBuf==0)
656          bCalcSpaceOnly=TRUE;
657  else
658  {
659   int i;
660   for (i=0; i<cbBuf; i++)
661           lpbPrinters[i]=0;
662  }
663  *lpdwReturned=0;
664  *lpdwNeeded = 0;
665
666  /* check for valid Flags */
667  if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME)))
668    {
669      FIXME("dwType = %08lx\n", dwType);
670      SetLastError(ERROR_INVALID_FLAGS);
671      return(0);
672    }
673  switch(dwLevel)
674         {
675      case 1:
676              return(TRUE);
677      case 2:
678      case 4:
679      case 5:
680          break;
681      default:
682      SetLastError(ERROR_INVALID_PARAMETER);
683              return(FALSE);
684     }   
685
686  /* Enter critical section to prevent AddPrinters() et al. to
687   * modify whilst we're reading in the registry
688   */
689  InitializeCriticalSection(&PRINT32_RegistryBlocker);
690  EnterCriticalSection(&PRINT32_RegistryBlocker);
691  
692  /* get a pointer to a list of all printer names in the registry */ 
693  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Printers, 0, KEY_READ,
694                                   &hPrinterListKey) !=ERROR_SUCCESS)
695         {
696      /* Oh no! An empty list of printers!
697       * (which is a valid configuration anyway)
698       */
699      TRACE("No entries in the Printers part of the registry\n");
700     }
701
702  /* count the number of entries and check if it fits in the buffer
703   */
704  while(RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
705                    NULL, NULL, NULL, &FileTime)==ERROR_SUCCESS)
706     {
707      PrinterNameLength=255;
708      dwIndex++;
709     }
710  *lpdwReturned = dwIndex;    
711  switch(dwLevel)
712         {
713      case 1:
714         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_1A);
715         break;
716      case 2:
717         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_2A);
718         break;     
719      case 4:
720         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_4A);
721         break;
722      case 5:
723         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_5A);
724         break;
725      default:
726         dwStructPrinterInfoSize = 0;
727         break;     
728     } 
729  if (dwIndex*dwStructPrinterInfoSize+1 > cbBuf)
730         bCalcSpaceOnly = TRUE;
731     
732  /* the strings which contain e.g. PrinterName, PortName, etc,
733   * are also stored in lpbPrinters, but after the regular structs.
734   * dwNextStringPos will always point to the next free place for a 
735   * string.
736   */  
737  dwNextStringPos=(dwIndex+1)*dwStructPrinterInfoSize;    
738
739  /* check each entry: if OK, add to list in corresponding INFO .
740   */    
741  for(dwIndex=0; dwIndex < *lpdwReturned; dwIndex++)
742     {
743      PrinterNameLength=255;
744      if (RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
745                    NULL, NULL, NULL, &FileTime)!=ERROR_SUCCESS)
746         break;  /* exit for loop*/
747         
748      /* check whether this printer is allowed in the list
749       * by comparing name to lpszName 
750       */
751      if (dwType & PRINTER_ENUM_NAME)
752         if (strcmp(PrinterName,lpszName)!=0)
753                 continue;               
754
755      switch(dwLevel)
756         {
757          case 1:
758                 /* FIXME: unimplemented */
759             break;
760          case 2:
761             bCalcSpaceOnly = ENUMPRINTERS_AddInfo2A(PrinterName, lpbPrinters,
762                                                 dwIndex*dwStructPrinterInfoSize,
763                                 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
764             break;
765          case 4:
766             bCalcSpaceOnly = ENUMPRINTERS_AddInfo4A(PrinterName, lpbPrinters,
767                                                 dwIndex*dwStructPrinterInfoSize,
768                                 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
769             break;
770          case 5:
771             bCalcSpaceOnly = ENUMPRINTERS_AddInfo5A(PrinterName, lpbPrinters,
772                                                 dwIndex*dwStructPrinterInfoSize,
773                                 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
774             break;
775         }       
776     }
777  RegCloseKey(hPrinterListKey);
778  *lpdwNeeded = dwNextStringPos;
779  
780  if (bCalcSpaceOnly==TRUE)
781         {
782     if  (lpbPrinters!=NULL)
783                 {
784           int i;
785           for (i=0; i<cbBuf; i++)
786                   lpbPrinters[i]=0;
787             } 
788      *lpdwReturned=0;    
789     } 
790  LeaveCriticalSection(&PRINT32_RegistryBlocker); 
791  return(TRUE);
792 }
793
794 /******************************************************************
795  *              EnumPrinters32W        [WINSPOOL.175]
796  *
797  */
798 BOOL  WINAPI EnumPrintersW(DWORD dwType, LPWSTR lpszName,
799                                DWORD dwLevel, LPBYTE lpbPrinters,
800                                DWORD cbBuf, LPDWORD lpdwNeeded,
801                                LPDWORD lpdwReturned)
802 {
803     FIXME("Nearly empty stub\n");
804     *lpdwReturned=0;
805     *lpdwNeeded = 0;
806     return TRUE;
807 }
808
809 /******************************************************************
810  *              AddMonitor32A        [WINSPOOL.107]
811  *
812  */
813 BOOL WINAPI AddMonitorA(LPCSTR pName, DWORD Level, LPBYTE pMonitors)
814 {
815     FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
816     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
817     return FALSE;
818 }
819
820 /******************************************************************
821  *              DeletePrinterDriver32A        [WINSPOOL.146]
822  *
823  */
824 BOOL WINAPI
825 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
826 {
827     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
828           debugstr_a(pDriverName));
829     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
830     return FALSE;
831 }
832
833
834 /******************************************************************
835  *              DeleteMonitor32A        [WINSPOOL.135]
836  *
837  */
838 BOOL WINAPI
839 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
840 {
841     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
842           debugstr_a(pMonitorName));
843     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
844     return FALSE;
845 }
846
847
848 /******************************************************************
849  *              DeletePort32A        [WINSPOOL.137]
850  *
851  */
852 BOOL WINAPI
853 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
854 {
855     FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
856           debugstr_a(pPortName));
857     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
858     return FALSE;
859 }
860
861 /******************************************************************************
862  *    SetPrinter32W  [WINSPOOL.214]
863  */
864 BOOL WINAPI
865 SetPrinterW(
866   HANDLE  hPrinter,
867   DWORD     Level,
868   LPBYTE    pPrinter,
869   DWORD     Command) {
870
871        FIXME("():stub\n");
872   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
873        return FALSE;
874 }
875
876 /******************************************************************************
877  *    WritePrinter32  [WINSPOOL.223]
878  */
879 BOOL WINAPI
880 WritePrinter( 
881   HANDLE  hPrinter,
882   LPVOID  pBuf,
883   DWORD   cbBuf,
884   LPDWORD pcWritten) {
885
886        FIXME("():stub\n");
887   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
888        return FALSE;
889 }
890
891 /*****************************************************************************
892  *          AddForm32A  [WINSPOOL.103]
893  */
894 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
895 {
896     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
897     return 1;
898 }
899
900 /*****************************************************************************
901  *          AddForm32W  [WINSPOOL.104]
902  */
903 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
904 {
905     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
906     return 1;
907 }
908
909 /*****************************************************************************
910  *          AddJob32A  [WINSPOOL.105]
911  */
912 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
913                         DWORD cbBuf, LPDWORD pcbNeeded)
914 {
915     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
916           pcbNeeded);
917     return 1;
918 }
919
920 /*****************************************************************************
921  *          AddJob32W  [WINSPOOL.106]
922  */
923 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
924                         LPDWORD pcbNeeded)
925 {
926     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
927           pcbNeeded);
928     return 1;
929 }
930
931 /*****************************************************************************
932  *          AddPrinter32A  [WINSPOOL.117]
933  */
934 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
935 {
936     PRINTER_INFO_2A *pi = (PRINTER_INFO_2A *) pPrinter;
937
938     HANDLE retval;
939     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
940
941     TRACE("(%s,%ld,%p)\n", pName, Level, pPrinter);
942     
943     if(pName != NULL) {
944         FIXME("pName = `%s' - unsupported\n", pName);
945         SetLastError(ERROR_INVALID_PARAMETER);
946         return 0;
947     }
948     if(Level != 2) {
949         WARN("Level = %ld\n", Level);
950         SetLastError(ERROR_INVALID_LEVEL);
951         return 0;
952     }
953     if(!pPrinter) {
954         SetLastError(ERROR_INVALID_PARAMETER);
955         return 0;
956     }
957     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
958        ERROR_SUCCESS) {
959         ERR("Can't create Printers key\n");
960         return 0;
961     }
962     if(RegOpenKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
963        ERROR_SUCCESS) {
964         SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
965         RegCloseKey(hkeyPrinter);
966         RegCloseKey(hkeyPrinters);
967         return 0;
968     }
969     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
970        ERROR_SUCCESS) {
971         ERR("Can't create Drivers key\n");
972         RegCloseKey(hkeyPrinters);
973         return 0;
974     }
975     if(RegOpenKeyA(hkeyDrivers, pi->pDriverName, &hkeyDriver) != 
976        ERROR_SUCCESS) {
977         WARN("Can't find driver `%s'\n", pi->pDriverName);
978         RegCloseKey(hkeyPrinters);
979         RegCloseKey(hkeyDrivers);
980         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
981         return 0;
982     }
983     RegCloseKey(hkeyDriver);
984     RegCloseKey(hkeyDrivers);
985     if(strcasecmp(pi->pPrintProcessor, "WinPrint")) {  /* FIXME */
986         WARN("Can't find processor `%s'\n", pi->pPrintProcessor);
987         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
988         RegCloseKey(hkeyPrinters);
989         return 0;
990     }
991     if(RegCreateKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
992        ERROR_SUCCESS) {
993         WARN("Can't create printer `%s'\n", pi->pPrinterName);
994         SetLastError(ERROR_INVALID_PRINTER_NAME);
995         RegCloseKey(hkeyPrinters);
996         return 0;
997     }
998     RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
999                    (LPSTR)&pi->Attributes, sizeof(DWORD));
1000     RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1001                    (LPSTR)&pi->pDevMode,
1002                    pi->pDevMode ? pi->pDevMode->dmSize : 0);
1003     RegSetValueExA(hkeyPrinter, "Description", 0, REG_SZ, pi->pComment, 0);
1004     RegSetValueExA(hkeyPrinter, "Location", 0, REG_SZ, pi->pLocation, 0);
1005     RegSetValueExA(hkeyPrinter, "Name", 0, REG_SZ, pi->pPrinterName, 0);
1006     RegSetValueExA(hkeyPrinter, "Parameters", 0, REG_SZ, pi->pParameters, 0);
1007     RegSetValueExA(hkeyPrinter, "Port", 0, REG_SZ, pi->pPortName, 0);
1008     RegSetValueExA(hkeyPrinter, "Print Processor", 0, REG_SZ,
1009                    pi->pPrintProcessor, 0);
1010     RegSetValueExA(hkeyPrinter, "Printer Driver", 0, REG_SZ, pi->pDriverName,
1011                    0);
1012     RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1013                    (LPSTR)&pi->Priority, sizeof(DWORD));
1014     RegSetValueExA(hkeyPrinter, "Separator File", 0, REG_SZ, pi->pSepFile, 0);
1015     RegSetValueExA(hkeyPrinter, "Share Name", 0, REG_SZ, pi->pShareName, 0);
1016     RegSetValueExA(hkeyPrinter, "Start Time", 0, REG_DWORD,
1017                    (LPSTR)&pi->StartTime, sizeof(DWORD));
1018     RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1019                    (LPSTR)&pi->Status, sizeof(DWORD));
1020     RegSetValueExA(hkeyPrinter, "Until Time", 0, REG_DWORD,
1021                    (LPSTR)&pi->UntilTime, sizeof(DWORD));
1022
1023     RegCloseKey(hkeyPrinter);
1024     RegCloseKey(hkeyPrinters);
1025     if(!OpenPrinterA(pi->pPrinterName, &retval, NULL)) {
1026         ERR("OpenPrinter failing\n");
1027         return 0;
1028     }
1029     return retval;
1030 }
1031
1032 /*****************************************************************************
1033  *          AddPrinter32W  [WINSPOOL.122]
1034  */
1035 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1036 {
1037     FIXME("(%p,%ld,%p): stub\n", pName, Level, pPrinter);
1038     return 0;
1039 }
1040
1041
1042 /*****************************************************************************
1043  *          ClosePrinter32  [WINSPOOL.126]
1044  */
1045 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1046 {
1047     LPOPENEDPRINTERA lpOpenedPrinter;
1048
1049     TRACE("Handle %d\n", hPrinter);
1050
1051     if (!pOpenedPrinterDPA)
1052         return FALSE;
1053
1054     if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1)))
1055     {
1056         lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1057         HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
1058         lpOpenedPrinter->lpsPrinterName = NULL;
1059         
1060         /* Free the memory of lpDefault if it has been initialized*/
1061         if(lpOpenedPrinter->lpDefault != NULL)
1062         {
1063             HeapFree(GetProcessHeap(), 0,
1064                      lpOpenedPrinter->lpDefault->pDevMode);
1065             HeapFree(GetProcessHeap(), 0,
1066                      lpOpenedPrinter->lpDefault->pDatatype);
1067             HeapFree(GetProcessHeap(), 0,
1068                      lpOpenedPrinter->lpDefault);
1069             lpOpenedPrinter->lpDefault = NULL;
1070         }
1071         
1072         lpOpenedPrinter->hPrinter = -1;
1073
1074         return TRUE;
1075     }
1076     return FALSE;
1077 }
1078
1079 /*****************************************************************************
1080  *          DeleteForm32A  [WINSPOOL.133]
1081  */
1082 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1083 {
1084     FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1085     return 1;
1086 }
1087
1088 /*****************************************************************************
1089  *          DeleteForm32W  [WINSPOOL.134]
1090  */
1091 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1092 {
1093     FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1094     return 1;
1095 }
1096
1097 /*****************************************************************************
1098  *          DeletePrinter32  [WINSPOOL.143]
1099  */
1100 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1101 {
1102     FIXME("(%d): stub\n", hPrinter);
1103     return 1;
1104 }
1105
1106 /*****************************************************************************
1107  *          SetPrinter32A  [WINSPOOL.211]
1108  */
1109 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1110                            DWORD Command)
1111 {
1112     FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1113     return FALSE;
1114 }
1115
1116 /*****************************************************************************
1117  *          SetJob32A  [WINSPOOL.209]
1118  */
1119 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1120                        LPBYTE pJob, DWORD Command)
1121 {
1122     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1123          Command);
1124     return FALSE;
1125 }
1126
1127 /*****************************************************************************
1128  *          SetJob32W  [WINSPOOL.210]
1129  */
1130 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1131                        LPBYTE pJob, DWORD Command)
1132 {
1133     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1134          Command);
1135     return FALSE;
1136 }
1137
1138 /*****************************************************************************
1139  *          GetForm32A  [WINSPOOL.181]
1140  */
1141 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1142                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1143 {
1144     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1145          Level,pForm,cbBuf,pcbNeeded); 
1146     return FALSE;
1147 }
1148
1149 /*****************************************************************************
1150  *          GetForm32W  [WINSPOOL.182]
1151  */
1152 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1153                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1154 {
1155     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1156           debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1157     return FALSE;
1158 }
1159
1160 /*****************************************************************************
1161  *          SetForm32A  [WINSPOOL.207]
1162  */
1163 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1164                         LPBYTE pForm)
1165 {
1166     FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1167     return FALSE;
1168 }
1169
1170 /*****************************************************************************
1171  *          SetForm32W  [WINSPOOL.208]
1172  */
1173 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1174                         LPBYTE pForm)
1175 {
1176     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1177     return FALSE;
1178 }
1179
1180 /*****************************************************************************
1181  *          ReadPrinter32  [WINSPOOL.202]
1182  */
1183 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1184                            LPDWORD pNoBytesRead)
1185 {
1186     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1187     return FALSE;
1188 }
1189
1190 /*****************************************************************************
1191  *          ResetPrinter32A  [WINSPOOL.203]
1192  */
1193 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1194 {
1195     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1196     return FALSE;
1197 }
1198
1199 /*****************************************************************************
1200  *          ResetPrinter32W  [WINSPOOL.204]
1201  */
1202 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1203 {
1204     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1205     return FALSE;
1206 }
1207
1208
1209 /*****************************************************************************
1210  *    WINSPOOL_GetStringFromRegA
1211  *
1212  * Get ValueName from hkey storing result in str.  buflen is space left in str
1213  */ 
1214 static BOOL WINSPOOL_GetStringFromRegA(HKEY hkey, LPCSTR ValueName, LPSTR ptr,
1215                                        DWORD buflen, DWORD *needed)
1216 {
1217     DWORD sz = buflen, type;
1218     LONG ret;
1219
1220     ret = RegQueryValueExA(hkey, ValueName, 0, &type, ptr, &sz);
1221
1222     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1223         ERR("Got ret = %ld\n", ret);
1224         return FALSE;
1225     }
1226     *needed = sz;
1227     return TRUE;
1228 }
1229
1230
1231 /*****************************************************************************
1232  *          GetPrinter32A  [WINSPOOL.187]
1233  */
1234 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1235                         DWORD cbBuf, LPDWORD pcbNeeded)
1236 {
1237     OPENEDPRINTERA *lpOpenedPrinter;
1238     DWORD size, needed = 0;
1239     LPBYTE ptr = NULL;
1240     HKEY hkeyPrinter, hkeyPrinters;
1241     
1242     TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1243
1244     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1245     if(!lpOpenedPrinter) {
1246         SetLastError(ERROR_INVALID_HANDLE);
1247         return FALSE;
1248     }
1249     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1250        ERROR_SUCCESS) {
1251         ERR("Can't create Printers key\n");
1252         return FALSE;
1253     }
1254     if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1255        != ERROR_SUCCESS) {
1256         ERR("Can't find opened printer `%s' in registry\n",
1257             lpOpenedPrinter->lpsPrinterName);
1258         RegCloseKey(hkeyPrinters);
1259         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1260         return FALSE;
1261     }
1262
1263     switch(Level) {
1264     case 2:
1265       {
1266         PRINTER_INFO_2A *pi2 = (PRINTER_INFO_2A *)pPrinter;
1267
1268         size = sizeof(PRINTER_INFO_2A);
1269         if(size <= cbBuf) {
1270             ptr = pPrinter + size;
1271             cbBuf -= size;
1272             memset(pPrinter, 0, size);
1273         } else
1274             cbBuf = 0;
1275         needed = size;
1276
1277         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
1278         if(cbBuf && size <= cbBuf) {
1279             pi2->pPrinterName = ptr;
1280             ptr += size;
1281         } else
1282             cbBuf = 0;
1283         needed += size;
1284
1285         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
1286         if(cbBuf && size <= cbBuf) {
1287             pi2->pPortName = ptr;
1288             ptr += size;
1289         } else
1290             cbBuf = 0;
1291         needed += size;
1292
1293         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Printer Driver", ptr, cbBuf,
1294                                    &size);
1295         if(cbBuf && size <= cbBuf) {
1296             pi2->pDriverName = ptr;
1297             ptr += size;
1298         } else
1299             cbBuf = 0;
1300         needed += size;
1301
1302         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Default DevMode", ptr, cbBuf,
1303                                    &size);
1304         if(cbBuf && size <= cbBuf) {
1305             pi2->pDevMode = (LPDEVMODEA)ptr;
1306             ptr += size;
1307         } else
1308             cbBuf = 0;
1309         needed += size;
1310
1311         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Print Processor", ptr, cbBuf,
1312                                    &size);
1313         if(cbBuf && size <= cbBuf) {
1314             pi2->pPrintProcessor = ptr;
1315             ptr += size;
1316         } else
1317             cbBuf = 0;
1318         needed += size;
1319
1320         break;
1321       }
1322       
1323     case 5:
1324       {
1325         PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A *)pPrinter;
1326
1327         size = sizeof(PRINTER_INFO_5A);
1328         if(size <= cbBuf) {
1329             ptr = pPrinter + size;
1330             cbBuf -= size;
1331             memset(pPrinter, 0, size);
1332         } else
1333             cbBuf = 0;
1334         needed = size;
1335
1336         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
1337         if(cbBuf && size <= cbBuf) {
1338             pi5->pPrinterName = ptr;
1339             ptr += size;
1340         } else
1341             cbBuf = 0;
1342         needed += size;
1343
1344         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
1345         if(cbBuf && size <= cbBuf) {
1346             pi5->pPortName = ptr;
1347             ptr += size;
1348         } else
1349             cbBuf = 0;
1350         needed += size;
1351
1352         break;
1353       }
1354
1355     default:
1356         FIXME("Unimplemented level %ld\n", Level);
1357         SetLastError(ERROR_INVALID_LEVEL);
1358         RegCloseKey(hkeyPrinters);
1359         RegCloseKey(hkeyPrinter);
1360         return FALSE;
1361     }
1362
1363     RegCloseKey(hkeyPrinter);
1364     RegCloseKey(hkeyPrinters);
1365
1366     if(pcbNeeded) *pcbNeeded = needed;
1367     if(cbBuf) return TRUE;
1368     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1369     return FALSE;
1370 }
1371
1372
1373 /*****************************************************************************
1374  *          GetPrinter32W  [WINSPOOL.194]
1375  */
1376 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1377                     DWORD cbBuf, LPDWORD pcbNeeded)
1378 {
1379     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pPrinter,
1380           cbBuf, pcbNeeded);
1381     return FALSE;
1382 }
1383
1384
1385 /*****************************************************************************
1386  *          GetPrinterDriver32A  [WINSPOOL.190]
1387  */
1388 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1389                               DWORD Level, LPBYTE pDriverInfo,
1390                               DWORD cbBuf, LPDWORD pcbNeeded)
1391 {
1392     OPENEDPRINTERA *lpOpenedPrinter;
1393     char DriverName[100];
1394     DWORD ret, type, size, dw, needed = 0;
1395     LPBYTE ptr = NULL;
1396     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1397     
1398     TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,pEnvironment,
1399          Level,pDriverInfo,cbBuf, pcbNeeded);
1400
1401     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1402     if(!lpOpenedPrinter) {
1403         SetLastError(ERROR_INVALID_HANDLE);
1404         return FALSE;
1405     }
1406     if(pEnvironment) {
1407         FIXME("pEnvironment = `%s'\n", pEnvironment);
1408         SetLastError(ERROR_INVALID_ENVIRONMENT);
1409         return FALSE;
1410     }
1411     if(Level < 1 || Level > 3) {
1412         SetLastError(ERROR_INVALID_LEVEL);
1413         return FALSE;
1414     }
1415     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1416        ERROR_SUCCESS) {
1417         ERR("Can't create Printers key\n");
1418         return FALSE;
1419     }
1420     if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1421        != ERROR_SUCCESS) {
1422         ERR("Can't find opened printer `%s' in registry\n",
1423             lpOpenedPrinter->lpsPrinterName);
1424         RegCloseKey(hkeyPrinters);
1425         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1426         return FALSE;
1427     }
1428     size = sizeof(DriverName);
1429     ret = RegQueryValueExA(hkeyPrinter, "Printer Driver", 0, &type, DriverName,
1430                            &size);
1431     RegCloseKey(hkeyPrinter);
1432     RegCloseKey(hkeyPrinters);
1433     if(ret != ERROR_SUCCESS) {
1434         ERR("Can't get DriverName for printer `%s'\n",
1435             lpOpenedPrinter->lpsPrinterName);
1436         return FALSE;
1437     }
1438     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1439        ERROR_SUCCESS) {
1440         ERR("Can't create Drivers key\n");
1441         return FALSE;
1442     }
1443     if(RegOpenKeyA(hkeyDrivers, DriverName, &hkeyDriver)
1444        != ERROR_SUCCESS) {
1445         ERR("Can't find driver `%s' in registry\n", DriverName);
1446         RegCloseKey(hkeyDrivers);
1447         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1448         return FALSE;
1449     }
1450
1451     switch(Level) {
1452     case 1:
1453         size = sizeof(DRIVER_INFO_1A);
1454         break;
1455     case 2:
1456         size = sizeof(DRIVER_INFO_2A);
1457         break;
1458     case 3:
1459         size = sizeof(DRIVER_INFO_3A);
1460         break;
1461     default:
1462         ERR("Invalid level\n");
1463         return FALSE;
1464     }
1465
1466     if(size <= cbBuf) {
1467         ptr = pDriverInfo + size;
1468         cbBuf -= size;
1469     } else
1470         cbBuf = 0;
1471     needed = size;
1472
1473     size = strlen(DriverName) + 1;
1474     if(size <= cbBuf) {
1475         cbBuf -= size;
1476         strcpy(ptr, DriverName);
1477         if(Level == 1)
1478             ((DRIVER_INFO_1A *)pDriverInfo)->pName = ptr;
1479         else
1480             ((DRIVER_INFO_2A *)pDriverInfo)->pName = ptr;    
1481         ptr += size;
1482     }
1483     needed += size;
1484
1485     if(Level > 1) {
1486         DRIVER_INFO_2A *di2 = (DRIVER_INFO_2A *)pDriverInfo;
1487
1488         size = sizeof(dw);
1489         if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw,
1490                             &size) !=
1491            ERROR_SUCCESS)
1492             WARN("Can't get Version\n");
1493         else if(cbBuf)
1494             di2->cVersion = dw;
1495
1496         size = strlen("Wine") + 1;  /* FIXME */
1497         if(size <= cbBuf) {
1498             cbBuf -= size;
1499             strcpy(ptr, "Wine");
1500             di2->pEnvironment = ptr;
1501             ptr += size;
1502         } else 
1503             cbBuf = 0;
1504         needed += size;
1505
1506         WINSPOOL_GetStringFromRegA(hkeyDriver, "Driver", ptr, cbBuf, &size);
1507         if(cbBuf && size <= cbBuf) {
1508             di2->pDriverPath = ptr;
1509             ptr += size;
1510         } else
1511             cbBuf = 0;
1512         needed += size;
1513
1514         WINSPOOL_GetStringFromRegA(hkeyDriver, "Data File", ptr, cbBuf, &size);
1515         if(cbBuf && size <= cbBuf) {
1516             di2->pDataFile = ptr;
1517             ptr += size;
1518         } else
1519             cbBuf = 0;
1520         needed += size;
1521
1522         WINSPOOL_GetStringFromRegA(hkeyDriver, "Configuration File", ptr,
1523                                    cbBuf, &size);
1524         if(cbBuf && size <= cbBuf) {
1525             di2->pConfigFile = ptr;
1526             ptr += size;
1527         } else
1528             cbBuf = 0;
1529         needed += size;
1530     }
1531
1532     if(Level > 2) {
1533         DRIVER_INFO_3A *di3 = (DRIVER_INFO_3A *)pDriverInfo;
1534
1535         WINSPOOL_GetStringFromRegA(hkeyDriver, "Help File", ptr, cbBuf, &size);
1536         if(cbBuf && size <= cbBuf) {
1537             di3->pHelpFile = ptr;
1538             ptr += size;
1539         } else
1540             cbBuf = 0;
1541         needed += size;
1542
1543         WINSPOOL_GetStringFromRegA(hkeyDriver, "Dependent Files", ptr, cbBuf,
1544                                    &size);
1545         if(cbBuf && size <= cbBuf) {
1546             di3->pDependentFiles = ptr;
1547             ptr += size;
1548         } else
1549             cbBuf = 0;
1550         needed += size;
1551
1552         WINSPOOL_GetStringFromRegA(hkeyDriver, "Monitor", ptr, cbBuf, &size);
1553         if(cbBuf && size <= cbBuf) {
1554             di3->pMonitorName = ptr;
1555             ptr += size;
1556         } else
1557             cbBuf = 0;
1558         needed += size;
1559
1560         WINSPOOL_GetStringFromRegA(hkeyDriver, "DataType", ptr, cbBuf, &size);
1561         if(cbBuf && size <= cbBuf) {
1562             di3->pDefaultDataType = ptr;
1563             ptr += size;
1564         } else
1565             cbBuf = 0;
1566         needed += size;
1567     }
1568     RegCloseKey(hkeyDriver);
1569     RegCloseKey(hkeyDrivers);
1570
1571     if(pcbNeeded) *pcbNeeded = needed;
1572     if(cbBuf) return TRUE;
1573     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1574     return FALSE;
1575 }
1576
1577 /*****************************************************************************
1578  *          GetPrinterDriver32W  [WINSPOOL.193]
1579  */
1580 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1581                                   DWORD Level, LPBYTE pDriverInfo, 
1582                                   DWORD cbBuf, LPDWORD pcbNeeded)
1583 {
1584     FIXME("(%d,%p,%ld,%p,%ld,%p): stub\n",hPrinter,pEnvironment,
1585           Level,pDriverInfo,cbBuf, pcbNeeded);
1586     return FALSE;
1587 }
1588
1589 /*****************************************************************************
1590  *       GetPrinterDriverDirectoryA  [WINSPOOL.191]
1591  */
1592 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1593                                        DWORD Level, LPBYTE pDriverDirectory,
1594                                        DWORD cbBuf, LPDWORD pcbNeeded)
1595 {
1596     DWORD needed;
1597
1598     TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1599           pDriverDirectory, cbBuf, pcbNeeded);
1600     if(pName != NULL) {
1601         FIXME("pName = `%s' - unsupported\n", pName);
1602         SetLastError(ERROR_INVALID_PARAMETER);
1603         return FALSE;
1604     }
1605     if(pEnvironment != NULL) {
1606         FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1607         SetLastError(ERROR_INVALID_ENVIRONMENT);
1608         return FALSE;
1609     }
1610     if(Level != 1)  /* win95 ignores this so we just carry on */
1611         WARN("Level = %ld - assuming 1\n", Level);
1612     
1613     /* FIXME should read from registry */
1614     needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
1615     needed++;
1616     if(pcbNeeded)
1617         *pcbNeeded = needed;
1618     if(needed > cbBuf) {
1619         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1620         return FALSE;
1621     }
1622     return TRUE;
1623 }
1624
1625
1626 /*****************************************************************************
1627  *       GetPrinterDriverDirectoryW  [WINSPOOL.192]
1628  */
1629 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
1630                                        DWORD Level, LPBYTE pDriverDirectory,
1631                                        DWORD cbBuf, LPDWORD pcbNeeded)
1632 {
1633     LPSTR pNameA = NULL, pEnvironmentA = NULL;
1634     BOOL ret;
1635
1636     if(pName)
1637         pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
1638     if(pEnvironment)
1639         pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
1640     ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
1641                                       pDriverDirectory, cbBuf, pcbNeeded );
1642     if(pNameA)
1643         HeapFree( GetProcessHeap(), 0, pNameA );
1644     if(pEnvironmentA)
1645         HeapFree( GetProcessHeap(), 0, pEnvironment );
1646
1647     return ret;
1648 }
1649
1650 /*****************************************************************************
1651  *          AddPrinterDriver32A  [WINSPOOL.120]
1652  */
1653 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
1654 {
1655     DRIVER_INFO_3A di3;
1656     HKEY hkeyDrivers, hkeyName;
1657
1658     TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
1659
1660     if(level != 2 && level != 3) {
1661         SetLastError(ERROR_INVALID_LEVEL);
1662         return FALSE;
1663     }
1664     if(pName != NULL) {
1665         FIXME("pName= `%s' - unsupported\n", pName);
1666         SetLastError(ERROR_INVALID_PARAMETER);
1667         return FALSE;
1668     }
1669     if(!pDriverInfo) {
1670         WARN("pDriverInfo == NULL");
1671         SetLastError(ERROR_INVALID_PARAMETER);
1672         return FALSE;
1673     }
1674     
1675     if(level == 3)
1676         di3 = *(DRIVER_INFO_3A *)pDriverInfo;
1677     else {
1678         memset(&di3, 0, sizeof(di3));
1679         *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
1680     }
1681
1682     if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
1683        !di3.pDataFile) {
1684         SetLastError(ERROR_INVALID_PARAMETER);
1685         return FALSE;
1686     }
1687     if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
1688     if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
1689     if(!di3.pHelpFile) di3.pHelpFile = "";
1690     if(!di3.pMonitorName) di3.pMonitorName = "";
1691
1692     if(di3.pEnvironment) {
1693         FIXME("pEnvironment = `%s'\n", di3.pEnvironment);
1694         SetLastError(ERROR_INVALID_ENVIRONMENT);
1695         return FALSE;
1696     }
1697     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1698        ERROR_SUCCESS) {
1699         ERR("Can't create Drivers key\n");
1700         return FALSE;
1701     }
1702
1703     if(level == 2) { /* apparently can't overwrite with level2 */
1704         if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
1705             RegCloseKey(hkeyName);
1706             RegCloseKey(hkeyDrivers);
1707             WARN("Trying to create existing printer driver `%s'\n", di3.pName);
1708             SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1709             return FALSE;
1710         }
1711     }
1712     if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
1713         RegCloseKey(hkeyDrivers);
1714         ERR("Can't create Name key\n");
1715         return FALSE;
1716     }
1717     RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
1718                    0);
1719     RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
1720     RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
1721     RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion, 
1722                    sizeof(DWORD));
1723     RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
1724     RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
1725                    di3.pDependentFiles, 0);
1726     RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
1727     RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
1728     RegCloseKey(hkeyName);
1729     RegCloseKey(hkeyDrivers);
1730
1731     return TRUE;
1732 }
1733 /*****************************************************************************
1734  *          AddPrinterDriver32W  [WINSPOOL.121]
1735  */
1736 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level, 
1737                                    LPBYTE pDriverInfo)
1738 {
1739     FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
1740           level,pDriverInfo);
1741     return FALSE;
1742 }
1743
1744
1745 /*****************************************************************************
1746  *          PrinterProperties  [WINSPOOL.201]
1747  *
1748  *     Displays a dialog to set the properties of the printer.
1749  *
1750  * RETURNS 
1751  *     nonzero on succes or zero on faillure
1752  *
1753  * BUGS
1754  *         implemented as stub only
1755  */
1756 BOOL WINAPI PrinterProperties(HWND hWnd,      /* handle to parent window */
1757                               HANDLE hPrinter /* handle to printer object */
1758 ){
1759     FIXME("(%d,%d): stub\n", hWnd, hPrinter);
1760     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1761     return FALSE;
1762 }
1763
1764 /*****************************************************************************
1765  *          EnumJobsA [WINSPOOL.162]
1766  *
1767  */
1768 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
1769                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
1770                       LPDWORD pcReturned)
1771 {
1772     FIXME("stub\n");
1773     if(pcbNeeded) *pcbNeeded = 0;
1774     if(pcReturned) *pcReturned = 0;
1775     return TRUE;
1776 }
1777
1778
1779 /*****************************************************************************
1780  *          EnumJobsW [WINSPOOL.163]
1781  *
1782  */
1783 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
1784                       DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
1785                       LPDWORD pcReturned)
1786 {
1787     FIXME("stub\n");
1788     if(pcbNeeded) *pcbNeeded = 0;
1789     if(pcReturned) *pcReturned = 0;
1790     return TRUE;
1791 }