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