Compiler warnings fix.
[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*/                  DWORD cbBuf,       /* max size of buffer in bytes */
601                     LPDWORD lpdwNeeded,/* pointer to var: # bytes used/needed */
602                                 LPDWORD lpdwReturned/* number of entries returned */
603                    )
604 {
605  HKEY  hPrinterListKey;
606  DWORD dwIndex=0;
607  char  PrinterName[255];
608  DWORD PrinterNameLength=255;
609  FILETIME FileTime;
610  DWORD dwNextStringPos;   /* position of next space for a string in the buffer*/
611  DWORD dwStructPrinterInfoSize; /* size of a Printer_Info_X structure */
612  BOOL  bCalcSpaceOnly=FALSE;/* if TRUE: don't store data, just calculate space*/
613  
614  TRACE("entered.\n");
615
616  /* test whether we're requested to really fill in. If so,
617   * zero out the data area, and initialise some returns to zero,
618   * to prevent problems 
619   */
620  if (lpbPrinters==NULL || cbBuf==0)
621          bCalcSpaceOnly=TRUE;
622  else
623  {
624   int i;
625   for (i=0; i<cbBuf; i++)
626           lpbPrinters[i]=0;
627  }
628  *lpdwReturned=0;
629  *lpdwNeeded = 0;
630
631  /* check for valid Flags */
632  if (dwType != PRINTER_ENUM_LOCAL && dwType != PRINTER_ENUM_NAME)
633         {
634      SetLastError(ERROR_INVALID_FLAGS);
635      return(0);
636     }
637  switch(dwLevel)
638         {
639      case 1:
640              return(TRUE);
641      case 2:
642      case 4:
643      case 5:
644          break;
645      default:
646      SetLastError(ERROR_INVALID_PARAMETER);
647              return(FALSE);
648     }   
649
650  /* Enter critical section to prevent AddPrinters() et al. to
651   * modify whilst we're reading in the registry
652   */
653  InitializeCriticalSection(&PRINT32_RegistryBlocker);
654  EnterCriticalSection(&PRINT32_RegistryBlocker);
655  
656  /* get a pointer to a list of all printer names in the registry */ 
657  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Printers, 0, KEY_READ,
658                                   &hPrinterListKey) !=ERROR_SUCCESS)
659         {
660      /* Oh no! An empty list of printers!
661       * (which is a valid configuration anyway)
662       */
663      TRACE("No entries in the Printers part of the registry\n");
664     }
665
666  /* count the number of entries and check if it fits in the buffer
667   */
668  while(RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
669                    NULL, NULL, NULL, &FileTime)==ERROR_SUCCESS)
670     {
671      PrinterNameLength=255;
672      dwIndex++;
673     }
674  *lpdwReturned = dwIndex;    
675  switch(dwLevel)
676         {
677      case 1:
678         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_1A);
679         break;
680      case 2:
681         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_2A);
682         break;     
683      case 4:
684         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_4A);
685         break;
686      case 5:
687         dwStructPrinterInfoSize = sizeof(PRINTER_INFO_5A);
688         break;
689      default:
690         dwStructPrinterInfoSize = 0;
691         break;     
692     } 
693  if (dwIndex*dwStructPrinterInfoSize+1 > cbBuf)
694         bCalcSpaceOnly = TRUE;
695     
696  /* the strings which contain e.g. PrinterName, PortName, etc,
697   * are also stored in lpbPrinters, but after the regular structs.
698   * dwNextStringPos will always point to the next free place for a 
699   * string.
700   */  
701  dwNextStringPos=(dwIndex+1)*dwStructPrinterInfoSize;    
702
703  /* check each entry: if OK, add to list in corresponding INFO .
704   */    
705  for(dwIndex=0; dwIndex < *lpdwReturned; dwIndex++)
706     {
707      PrinterNameLength=255;
708      if (RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
709                    NULL, NULL, NULL, &FileTime)!=ERROR_SUCCESS)
710         break;  /* exit for loop*/
711         
712      /* check whether this printer is allowed in the list
713       * by comparing name to lpszName 
714       */
715      if (dwType == PRINTER_ENUM_NAME)
716         if (strcmp(PrinterName,lpszName)!=0)
717                 continue;               
718
719      switch(dwLevel)
720         {
721          case 1:
722                 /* FIXME: unimplemented */
723             break;
724          case 2:
725             bCalcSpaceOnly = ENUMPRINTERS_AddInfo2A(PrinterName, lpbPrinters,
726                                                 dwIndex*dwStructPrinterInfoSize,
727                                 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
728             break;
729          case 4:
730             bCalcSpaceOnly = ENUMPRINTERS_AddInfo4A(PrinterName, lpbPrinters,
731                                                 dwIndex*dwStructPrinterInfoSize,
732                                 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
733             break;
734          case 5:
735             bCalcSpaceOnly = ENUMPRINTERS_AddInfo5A(PrinterName, lpbPrinters,
736                                                 dwIndex*dwStructPrinterInfoSize,
737                                 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
738             break;
739         }       
740     }
741  RegCloseKey(hPrinterListKey);
742  *lpdwNeeded = dwNextStringPos;
743  
744  if (bCalcSpaceOnly==TRUE)
745         {
746     if  (lpbPrinters!=NULL)
747                 {
748           int i;
749           for (i=0; i<cbBuf; i++)
750                   lpbPrinters[i]=0;
751             } 
752      *lpdwReturned=0;    
753     } 
754  LeaveCriticalSection(&PRINT32_RegistryBlocker); 
755  return(TRUE);
756 }
757
758 /******************************************************************
759  *              EnumPrinters32W        [WINSPOOL.175]
760  *
761  */
762 BOOL  WINAPI EnumPrintersW(DWORD dwType, LPWSTR lpszName,
763                                DWORD dwLevel, LPBYTE lpbPrinters,
764                                DWORD cbBuf, LPDWORD lpdwNeeded,
765                                LPDWORD lpdwReturned)
766 {
767     FIXME("Nearly empty stub\n");
768     *lpdwReturned=0;
769     *lpdwNeeded = 0;
770     return TRUE;
771 }
772
773 /******************************************************************
774  *              AddMonitor32A        [WINSPOOL.107]
775  *
776  */
777 BOOL WINAPI AddMonitorA(LPCSTR pName, DWORD Level, LPBYTE pMonitors)
778 {
779     FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
780     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
781     return FALSE;
782 }
783
784 /******************************************************************
785  *              DeletePrinterDriver32A        [WINSPOOL.146]
786  *
787  */
788 BOOL WINAPI
789 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
790 {
791     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
792           debugstr_a(pDriverName));
793     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
794     return FALSE;
795 }
796
797
798 /******************************************************************
799  *              DeleteMonitor32A        [WINSPOOL.135]
800  *
801  */
802 BOOL WINAPI
803 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
804 {
805     FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
806           debugstr_a(pMonitorName));
807     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
808     return FALSE;
809 }
810
811
812 /******************************************************************
813  *              DeletePort32A        [WINSPOOL.137]
814  *
815  */
816 BOOL WINAPI
817 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
818 {
819     FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
820           debugstr_a(pPortName));
821     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
822     return FALSE;
823 }
824
825 /******************************************************************************
826  *    SetPrinter32W  [WINSPOOL.214]
827  */
828 BOOL WINAPI
829 SetPrinterW(
830   HANDLE  hPrinter,
831   DWORD     Level,
832   LPBYTE    pPrinter,
833   DWORD     Command) {
834
835        FIXME("():stub\n");
836   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
837        return FALSE;
838 }
839
840 /******************************************************************************
841  *    WritePrinter32  [WINSPOOL.223]
842  */
843 BOOL WINAPI
844 WritePrinter( 
845   HANDLE  hPrinter,
846   LPVOID  pBuf,
847   DWORD   cbBuf,
848   LPDWORD pcWritten) {
849
850        FIXME("():stub\n");
851   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
852        return FALSE;
853 }
854
855 /*****************************************************************************
856  *          AddForm32A  [WINSPOOL.103]
857  */
858 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
859 {
860     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
861     return 1;
862 }
863
864 /*****************************************************************************
865  *          AddForm32W  [WINSPOOL.104]
866  */
867 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
868 {
869     FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
870     return 1;
871 }
872
873 /*****************************************************************************
874  *          AddJob32A  [WINSPOOL.105]
875  */
876 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
877                         DWORD cbBuf, LPDWORD pcbNeeded)
878 {
879     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
880           pcbNeeded);
881     return 1;
882 }
883
884 /*****************************************************************************
885  *          AddJob32W  [WINSPOOL.106]
886  */
887 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
888                         LPDWORD pcbNeeded)
889 {
890     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
891           pcbNeeded);
892     return 1;
893 }
894
895 /*****************************************************************************
896  *          AddPrinter32A  [WINSPOOL.117]
897  */
898 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
899 {
900     PRINTER_INFO_2A *pi = (PRINTER_INFO_2A *) pPrinter;
901
902     HANDLE retval;
903     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
904
905     TRACE("(%s,%ld,%p)\n", pName, Level, pPrinter);
906     
907     if(pName != NULL) {
908         FIXME("pName = `%s' - unsupported\n", pName);
909         SetLastError(ERROR_INVALID_PARAMETER);
910         return 0;
911     }
912     if(Level != 2) {
913         WARN("Level = %ld\n", Level);
914         SetLastError(ERROR_INVALID_LEVEL);
915         return 0;
916     }
917     if(!pPrinter) {
918         SetLastError(ERROR_INVALID_PARAMETER);
919         return 0;
920     }
921     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
922        ERROR_SUCCESS) {
923         ERR("Can't create Printers key\n");
924         return 0;
925     }
926     if(RegOpenKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
927        ERROR_SUCCESS) {
928         SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
929         RegCloseKey(hkeyPrinter);
930         RegCloseKey(hkeyPrinters);
931         return 0;
932     }
933     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
934        ERROR_SUCCESS) {
935         ERR("Can't create Drivers key\n");
936         RegCloseKey(hkeyPrinters);
937         return 0;
938     }
939     if(RegOpenKeyA(hkeyDrivers, pi->pDriverName, &hkeyDriver) != 
940        ERROR_SUCCESS) {
941         WARN("Can't find driver `%s'\n", pi->pDriverName);
942         RegCloseKey(hkeyPrinters);
943         RegCloseKey(hkeyDrivers);
944         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
945         return 0;
946     }
947     RegCloseKey(hkeyDriver);
948     RegCloseKey(hkeyDrivers);
949     if(strcasecmp(pi->pPrintProcessor, "WinPrint")) {  /* FIXME */
950         WARN("Can't find processor `%s'\n", pi->pPrintProcessor);
951         SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
952         RegCloseKey(hkeyPrinters);
953         return 0;
954     }
955     if(RegCreateKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
956        ERROR_SUCCESS) {
957         WARN("Can't create printer `%s'\n", pi->pPrinterName);
958         SetLastError(ERROR_INVALID_PRINTER_NAME);
959         RegCloseKey(hkeyPrinters);
960         return 0;
961     }
962     RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
963                    (LPSTR)&pi->Attributes, sizeof(DWORD));
964     RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
965                    (LPSTR)&pi->pDevMode,
966                    pi->pDevMode ? pi->pDevMode->dmSize : 0);
967     RegSetValueExA(hkeyPrinter, "Description", 0, REG_SZ, pi->pComment, 0);
968     RegSetValueExA(hkeyPrinter, "Location", 0, REG_SZ, pi->pLocation, 0);
969     RegSetValueExA(hkeyPrinter, "Name", 0, REG_SZ, pi->pPrinterName, 0);
970     RegSetValueExA(hkeyPrinter, "Parameters", 0, REG_SZ, pi->pParameters, 0);
971     RegSetValueExA(hkeyPrinter, "Port", 0, REG_SZ, pi->pPortName, 0);
972     RegSetValueExA(hkeyPrinter, "Print Processor", 0, REG_SZ,
973                    pi->pPrintProcessor, 0);
974     RegSetValueExA(hkeyPrinter, "Printer Driver", 0, REG_SZ, pi->pDriverName,
975                    0);
976     RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
977                    (LPSTR)&pi->Priority, sizeof(DWORD));
978     RegSetValueExA(hkeyPrinter, "Separator File", 0, REG_SZ, pi->pSepFile, 0);
979     RegSetValueExA(hkeyPrinter, "Share Name", 0, REG_SZ, pi->pShareName, 0);
980     RegSetValueExA(hkeyPrinter, "Start Time", 0, REG_DWORD,
981                    (LPSTR)&pi->StartTime, sizeof(DWORD));
982     RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
983                    (LPSTR)&pi->Status, sizeof(DWORD));
984     RegSetValueExA(hkeyPrinter, "Until Time", 0, REG_DWORD,
985                    (LPSTR)&pi->UntilTime, sizeof(DWORD));
986
987     RegCloseKey(hkeyPrinter);
988     RegCloseKey(hkeyPrinters);
989     if(!OpenPrinterA(pi->pPrinterName, &retval, NULL)) {
990         ERR("OpenPrinter failing\n");
991         return 0;
992     }
993     return retval;
994 }
995
996 /*****************************************************************************
997  *          AddPrinter32W  [WINSPOOL.122]
998  */
999 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1000 {
1001     FIXME("(%p,%ld,%p): stub\n", pName, Level, pPrinter);
1002     return 0;
1003 }
1004
1005
1006 /*****************************************************************************
1007  *          ClosePrinter32  [WINSPOOL.126]
1008  */
1009 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1010 {
1011     LPOPENEDPRINTERA lpOpenedPrinter;
1012
1013     if ((hPrinter != -1) && (hPrinter < NUM_PRINTER_MAX + 1))
1014     {
1015         lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1016         HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
1017         lpOpenedPrinter->lpsPrinterName = NULL;
1018         
1019         /* Free the memory of lpDefault if it has been initialized*/
1020         if(lpOpenedPrinter->lpDefault != NULL)
1021         {
1022             HeapFree(GetProcessHeap(), 0,
1023                      lpOpenedPrinter->lpDefault->pDevMode);
1024             HeapFree(GetProcessHeap(), 0,
1025                      lpOpenedPrinter->lpDefault->pDatatype);
1026             HeapFree(GetProcessHeap(), 0,
1027                      lpOpenedPrinter->lpDefault);
1028             lpOpenedPrinter->lpDefault = NULL;
1029         }
1030         
1031         lpOpenedPrinter->hPrinter = -1;
1032         
1033         return TRUE;
1034     }
1035     return FALSE;
1036 }
1037
1038 /*****************************************************************************
1039  *          DeleteForm32A  [WINSPOOL.133]
1040  */
1041 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1042 {
1043     FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1044     return 1;
1045 }
1046
1047 /*****************************************************************************
1048  *          DeleteForm32W  [WINSPOOL.134]
1049  */
1050 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1051 {
1052     FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1053     return 1;
1054 }
1055
1056 /*****************************************************************************
1057  *          DeletePrinter32  [WINSPOOL.143]
1058  */
1059 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1060 {
1061     FIXME("(%d): stub\n", hPrinter);
1062     return 1;
1063 }
1064
1065 /*****************************************************************************
1066  *          SetPrinter32A  [WINSPOOL.211]
1067  */
1068 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1069                            DWORD Command)
1070 {
1071     FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1072     return FALSE;
1073 }
1074
1075 /*****************************************************************************
1076  *          SetJob32A  [WINSPOOL.209]
1077  */
1078 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1079                        LPBYTE pJob, DWORD Command)
1080 {
1081     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1082          Command);
1083     return FALSE;
1084 }
1085
1086 /*****************************************************************************
1087  *          SetJob32W  [WINSPOOL.210]
1088  */
1089 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1090                        LPBYTE pJob, DWORD Command)
1091 {
1092     FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1093          Command);
1094     return FALSE;
1095 }
1096
1097 /*****************************************************************************
1098  *          GetForm32A  [WINSPOOL.181]
1099  */
1100 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1101                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1102 {
1103     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1104          Level,pForm,cbBuf,pcbNeeded); 
1105     return FALSE;
1106 }
1107
1108 /*****************************************************************************
1109  *          GetForm32W  [WINSPOOL.182]
1110  */
1111 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1112                  LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1113 {
1114     FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1115           debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1116     return FALSE;
1117 }
1118
1119 /*****************************************************************************
1120  *          SetForm32A  [WINSPOOL.207]
1121  */
1122 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1123                         LPBYTE pForm)
1124 {
1125     FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1126     return FALSE;
1127 }
1128
1129 /*****************************************************************************
1130  *          SetForm32W  [WINSPOOL.208]
1131  */
1132 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1133                         LPBYTE pForm)
1134 {
1135     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1136     return FALSE;
1137 }
1138
1139 /*****************************************************************************
1140  *          ReadPrinter32  [WINSPOOL.202]
1141  */
1142 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1143                            LPDWORD pNoBytesRead)
1144 {
1145     FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1146     return FALSE;
1147 }
1148
1149 /*****************************************************************************
1150  *          ResetPrinter32A  [WINSPOOL.203]
1151  */
1152 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1153 {
1154     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1155     return FALSE;
1156 }
1157
1158 /*****************************************************************************
1159  *          ResetPrinter32W  [WINSPOOL.204]
1160  */
1161 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1162 {
1163     FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1164     return FALSE;
1165 }
1166
1167
1168 /*****************************************************************************
1169  *    WINSPOOL_GetStringFromRegA
1170  *
1171  * Get ValueName from hkey storing result in str.  buflen is space left in str
1172  */ 
1173 static BOOL WINSPOOL_GetStringFromRegA(HKEY hkey, LPCSTR ValueName, LPSTR ptr,
1174                                        DWORD buflen, DWORD *needed)
1175 {
1176     DWORD sz = buflen, type;
1177     LONG ret;
1178
1179     ret = RegQueryValueExA(hkey, ValueName, 0, &type, ptr, &sz);
1180
1181     if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1182         ERR("Got ret = %ld\n", ret);
1183         return FALSE;
1184     }
1185     *needed = sz;
1186     return TRUE;
1187 }
1188
1189
1190 /*****************************************************************************
1191  *          GetPrinter32A  [WINSPOOL.187]
1192  */
1193 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1194                         DWORD cbBuf, LPDWORD pcbNeeded)
1195 {
1196     OPENEDPRINTERA *lpOpenedPrinter;
1197     DWORD size, needed = 0;
1198     LPBYTE ptr = NULL;
1199     HKEY hkeyPrinter, hkeyPrinters;
1200     
1201     TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1202
1203     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1204     if(!lpOpenedPrinter) {
1205         SetLastError(ERROR_INVALID_HANDLE);
1206         return FALSE;
1207     }
1208     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1209        ERROR_SUCCESS) {
1210         ERR("Can't create Printers key\n");
1211         return FALSE;
1212     }
1213     if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1214        != ERROR_SUCCESS) {
1215         ERR("Can't find opened printer `%s' in registry\n",
1216             lpOpenedPrinter->lpsPrinterName);
1217         RegCloseKey(hkeyPrinters);
1218         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1219         return FALSE;
1220     }
1221
1222     switch(Level) {
1223     case 2:
1224       {
1225         PRINTER_INFO_2A *pi2 = (PRINTER_INFO_2A *)pPrinter;
1226
1227         size = sizeof(PRINTER_INFO_2A);
1228         if(size <= cbBuf) {
1229             ptr = pPrinter + size;
1230             cbBuf -= size;
1231             memset(pPrinter, 0, size);
1232         } else
1233             cbBuf = 0;
1234         needed = size;
1235
1236         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
1237         if(size <= cbBuf) {
1238             pi2->pPrinterName = ptr;
1239             ptr += size;
1240         } else
1241             cbBuf = 0;
1242         needed += size;
1243
1244         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
1245         if(size <= cbBuf) {
1246             pi2->pPortName = ptr;
1247             ptr += size;
1248         } else
1249             cbBuf = 0;
1250         needed += size;
1251
1252         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Printer Driver", ptr, cbBuf,
1253                                    &size);
1254         if(size <= cbBuf) {
1255             pi2->pDriverName = ptr;
1256             ptr += size;
1257         } else
1258             cbBuf = 0;
1259         needed += size;
1260
1261         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Default DevMode", ptr, cbBuf,
1262                                    &size);
1263         if(size <= cbBuf) {
1264             pi2->pDevMode = (LPDEVMODEA)ptr;
1265             ptr += size;
1266         } else
1267             cbBuf = 0;
1268         needed += size;
1269
1270         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Print Processor", ptr, cbBuf,
1271                                    &size);
1272         if(size <= cbBuf) {
1273             pi2->pPrintProcessor = ptr;
1274             ptr += size;
1275         } else
1276             cbBuf = 0;
1277         needed += size;
1278
1279         break;
1280       }
1281       
1282     case 5:
1283       {
1284         PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A *)pPrinter;
1285
1286         size = sizeof(PRINTER_INFO_5A);
1287         if(size <= cbBuf) {
1288             ptr = pPrinter + size;
1289             cbBuf -= size;
1290             memset(pPrinter, 0, size);
1291         } else
1292             cbBuf = 0;
1293         needed = size;
1294
1295         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
1296         if(size <= cbBuf) {
1297             pi5->pPrinterName = ptr;
1298             ptr += size;
1299         } else
1300             cbBuf = 0;
1301         needed += size;
1302
1303         WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
1304         if(size <= cbBuf) {
1305             pi5->pPortName = ptr;
1306             ptr += size;
1307         } else
1308             cbBuf = 0;
1309         needed += size;
1310
1311         break;
1312       }
1313
1314     default:
1315         FIXME("Unimplemented level %ld\n", Level);
1316         SetLastError(ERROR_INVALID_LEVEL);
1317         RegCloseKey(hkeyPrinters);
1318         RegCloseKey(hkeyPrinter);
1319         return FALSE;
1320     }
1321
1322     RegCloseKey(hkeyPrinter);
1323     RegCloseKey(hkeyPrinters);
1324
1325     if(pcbNeeded) *pcbNeeded = needed;
1326     if(cbBuf) return TRUE;
1327     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1328     return FALSE;
1329 }
1330
1331
1332 /*****************************************************************************
1333  *          GetPrinter32W  [WINSPOOL.194]
1334  */
1335 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1336                     DWORD cbBuf, LPDWORD pcbNeeded)
1337 {
1338     FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pPrinter,
1339           cbBuf, pcbNeeded);
1340     return FALSE;
1341 }
1342
1343
1344 /*****************************************************************************
1345  *          GetPrinterDriver32A  [WINSPOOL.190]
1346  */
1347 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1348                               DWORD Level, LPBYTE pDriverInfo,
1349                               DWORD cbBuf, LPDWORD pcbNeeded)
1350 {
1351     OPENEDPRINTERA *lpOpenedPrinter;
1352     char DriverName[100];
1353     DWORD ret, type, size, dw, needed = 0;
1354     LPBYTE ptr = NULL;
1355     HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1356     
1357     TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,pEnvironment,
1358          Level,pDriverInfo,cbBuf, pcbNeeded);
1359
1360     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1361     if(!lpOpenedPrinter) {
1362         SetLastError(ERROR_INVALID_HANDLE);
1363         return FALSE;
1364     }
1365     if(pEnvironment) {
1366         FIXME("pEnvironment = `%s'\n", pEnvironment);
1367         SetLastError(ERROR_INVALID_ENVIRONMENT);
1368         return FALSE;
1369     }
1370     if(Level < 1 || Level > 3) {
1371         SetLastError(ERROR_INVALID_LEVEL);
1372         return FALSE;
1373     }
1374     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1375        ERROR_SUCCESS) {
1376         ERR("Can't create Printers key\n");
1377         return FALSE;
1378     }
1379     if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1380        != ERROR_SUCCESS) {
1381         ERR("Can't find opened printer `%s' in registry\n",
1382             lpOpenedPrinter->lpsPrinterName);
1383         RegCloseKey(hkeyPrinters);
1384         SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1385         return FALSE;
1386     }
1387     size = sizeof(DriverName);
1388     ret = RegQueryValueExA(hkeyPrinter, "Printer Driver", 0, &type, DriverName,
1389                            &size);
1390     RegCloseKey(hkeyPrinter);
1391     RegCloseKey(hkeyPrinters);
1392     if(ret != ERROR_SUCCESS) {
1393         ERR("Can't get DriverName for printer `%s'\n",
1394             lpOpenedPrinter->lpsPrinterName);
1395         return FALSE;
1396     }
1397     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1398        ERROR_SUCCESS) {
1399         ERR("Can't create Drivers key\n");
1400         return FALSE;
1401     }
1402     if(RegOpenKeyA(hkeyDrivers, DriverName, &hkeyDriver)
1403        != ERROR_SUCCESS) {
1404         ERR("Can't find driver `%s' in registry\n", DriverName);
1405         RegCloseKey(hkeyDrivers);
1406         SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1407         return FALSE;
1408     }
1409
1410     switch(Level) {
1411     case 1:
1412         size = sizeof(DRIVER_INFO_1A);
1413         break;
1414     case 2:
1415         size = sizeof(DRIVER_INFO_2A);
1416         break;
1417     case 3:
1418         size = sizeof(DRIVER_INFO_3A);
1419         break;
1420     default:
1421         ERR("Invalid level\n");
1422         return FALSE;
1423     }
1424
1425     if(size <= cbBuf) {
1426         ptr = pDriverInfo + size;
1427         cbBuf -= size;
1428     } else
1429         cbBuf = 0;
1430     needed = size;
1431
1432     size = strlen(DriverName) + 1;
1433     if(size <= cbBuf) {
1434         cbBuf -= size;
1435         strcpy(ptr, DriverName);
1436         if(Level == 1)
1437             ((DRIVER_INFO_1A *)pDriverInfo)->pName = ptr;
1438         else
1439             ((DRIVER_INFO_2A *)pDriverInfo)->pName = ptr;    
1440         ptr += size;
1441     }
1442     needed += size;
1443
1444     if(Level > 1) {
1445         DRIVER_INFO_2A *di2 = (DRIVER_INFO_2A *)pDriverInfo;
1446
1447         size = sizeof(dw);
1448         if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw,
1449                             &size) !=
1450            ERROR_SUCCESS)
1451             WARN("Can't get Version\n");
1452         else if(cbBuf)
1453             di2->cVersion = dw;
1454
1455         size = strlen("Wine") + 1;  /* FIXME */
1456         if(size <= cbBuf) {
1457             cbBuf -= size;
1458             strcpy(ptr, "Wine");
1459             di2->pEnvironment = ptr;
1460             ptr += size;
1461         } else 
1462             cbBuf = 0;
1463         needed += size;
1464
1465         WINSPOOL_GetStringFromRegA(hkeyDriver, "Driver", ptr, cbBuf, &size);
1466         if(size <= cbBuf) {
1467             di2->pDriverPath = ptr;
1468             ptr += size;
1469         } else
1470             cbBuf = 0;
1471         needed += size;
1472
1473         WINSPOOL_GetStringFromRegA(hkeyDriver, "Data File", ptr, cbBuf, &size);
1474         if(size <= cbBuf) {
1475             di2->pDataFile = ptr;
1476             ptr += size;
1477         } else
1478             cbBuf = 0;
1479         needed += size;
1480
1481         WINSPOOL_GetStringFromRegA(hkeyDriver, "Configuration File", ptr,
1482                                    cbBuf, &size);
1483         if(size <= cbBuf) {
1484             di2->pConfigFile = ptr;
1485             ptr += size;
1486         } else
1487             cbBuf = 0;
1488         needed += size;
1489     }
1490
1491     if(Level > 2) {
1492         DRIVER_INFO_3A *di3 = (DRIVER_INFO_3A *)pDriverInfo;
1493
1494         WINSPOOL_GetStringFromRegA(hkeyDriver, "Help File", ptr, cbBuf, &size);
1495         if(size <= cbBuf) {
1496             di3->pHelpFile = ptr;
1497             ptr += size;
1498         } else
1499             cbBuf = 0;
1500         needed += size;
1501
1502         WINSPOOL_GetStringFromRegA(hkeyDriver, "Dependent Files", ptr, cbBuf,
1503                                    &size);
1504         if(size <= cbBuf) {
1505             di3->pDependentFiles = ptr;
1506             ptr += size;
1507         } else
1508             cbBuf = 0;
1509         needed += size;
1510
1511         WINSPOOL_GetStringFromRegA(hkeyDriver, "Monitor", ptr, cbBuf, &size);
1512         if(size <= cbBuf) {
1513             di3->pMonitorName = ptr;
1514             ptr += size;
1515         } else
1516             cbBuf = 0;
1517         needed += size;
1518
1519         WINSPOOL_GetStringFromRegA(hkeyDriver, "DataType", ptr, cbBuf, &size);
1520         if(size <= cbBuf) {
1521             di3->pDefaultDataType = ptr;
1522             ptr += size;
1523         } else
1524             cbBuf = 0;
1525         needed += size;
1526     }
1527     RegCloseKey(hkeyDriver);
1528     RegCloseKey(hkeyDrivers);
1529
1530     if(pcbNeeded) *pcbNeeded = needed;
1531     if(cbBuf) return TRUE;
1532     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1533     return FALSE;
1534 }
1535
1536 /*****************************************************************************
1537  *          GetPrinterDriver32W  [WINSPOOL.193]
1538  */
1539 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1540                                   DWORD Level, LPBYTE pDriverInfo, 
1541                                   DWORD cbBuf, LPDWORD pcbNeeded)
1542 {
1543     FIXME("(%d,%p,%ld,%p,%ld,%p): stub\n",hPrinter,pEnvironment,
1544           Level,pDriverInfo,cbBuf, pcbNeeded);
1545     return FALSE;
1546 }
1547
1548 /*****************************************************************************
1549  *       GetPrinterDriverDirectoryA  [WINSPOOL.191]
1550  */
1551 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1552                                        DWORD Level, LPBYTE pDriverDirectory,
1553                                        DWORD cbBuf, LPDWORD pcbNeeded)
1554 {
1555     DWORD needed;
1556
1557     TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1558           pDriverDirectory, cbBuf, pcbNeeded);
1559     if(pName != NULL) {
1560         FIXME("pName = `%s' - unsupported\n", pName);
1561         SetLastError(ERROR_INVALID_PARAMETER);
1562         return FALSE;
1563     }
1564     if(pEnvironment != NULL) {
1565         FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1566         SetLastError(ERROR_INVALID_ENVIRONMENT);
1567         return FALSE;
1568     }
1569     if(Level != 1)  /* win95 ignores this so we just carry on */
1570         WARN("Level = %ld - assuming 1\n", Level);
1571     
1572     /* FIXME should read from registry */
1573     needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
1574     needed++;
1575     if(pcbNeeded)
1576         *pcbNeeded = needed;
1577     if(needed > cbBuf) {
1578         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1579         return FALSE;
1580     }
1581     return TRUE;
1582 }
1583
1584
1585 /*****************************************************************************
1586  *       GetPrinterDriverDirectoryW  [WINSPOOL.192]
1587  */
1588 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
1589                                        DWORD Level, LPBYTE pDriverDirectory,
1590                                        DWORD cbBuf, LPDWORD pcbNeeded)
1591 {
1592     LPSTR pNameA = NULL, pEnvironmentA = NULL;
1593     BOOL ret;
1594
1595     if(pName)
1596         pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
1597     if(pEnvironment)
1598         pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
1599     ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
1600                                       pDriverDirectory, cbBuf, pcbNeeded );
1601     if(pNameA)
1602         HeapFree( GetProcessHeap(), 0, pNameA );
1603     if(pEnvironmentA)
1604         HeapFree( GetProcessHeap(), 0, pEnvironment );
1605
1606     return ret;
1607 }
1608
1609 /*****************************************************************************
1610  *          AddPrinterDriver32A  [WINSPOOL.120]
1611  */
1612 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
1613 {
1614     DRIVER_INFO_3A di3;
1615     HKEY hkeyDrivers, hkeyName;
1616
1617     TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
1618
1619     if(level != 2 && level != 3) {
1620         SetLastError(ERROR_INVALID_LEVEL);
1621         return FALSE;
1622     }
1623     if(pName != NULL) {
1624         FIXME("pName= `%s' - unsupported\n", pName);
1625         SetLastError(ERROR_INVALID_PARAMETER);
1626         return FALSE;
1627     }
1628     if(!pDriverInfo) {
1629         WARN("pDriverInfo == NULL");
1630         SetLastError(ERROR_INVALID_PARAMETER);
1631         return FALSE;
1632     }
1633     
1634     if(level == 3)
1635         di3 = *(DRIVER_INFO_3A *)pDriverInfo;
1636     else {
1637         memset(&di3, 0, sizeof(di3));
1638         *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
1639     }
1640
1641     if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
1642        !di3.pDataFile) {
1643         SetLastError(ERROR_INVALID_PARAMETER);
1644         return FALSE;
1645     }
1646     if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
1647     if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
1648     if(!di3.pHelpFile) di3.pHelpFile = "";
1649     if(!di3.pMonitorName) di3.pMonitorName = "";
1650
1651     if(di3.pEnvironment) {
1652         FIXME("pEnvironment = `%s'\n", di3.pEnvironment);
1653         SetLastError(ERROR_INVALID_ENVIRONMENT);
1654         return FALSE;
1655     }
1656     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1657        ERROR_SUCCESS) {
1658         ERR("Can't create Drivers key\n");
1659         return FALSE;
1660     }
1661
1662     if(level == 2) { /* apparently can't overwrite with level2 */
1663         if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
1664             RegCloseKey(hkeyName);
1665             RegCloseKey(hkeyDrivers);
1666             WARN("Trying to create existing printer driver `%s'\n", di3.pName);
1667             SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1668             return FALSE;
1669         }
1670     }
1671     if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
1672         RegCloseKey(hkeyDrivers);
1673         ERR("Can't create Name key\n");
1674         return FALSE;
1675     }
1676     RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
1677                    0);
1678     RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
1679     RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
1680     RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion, 
1681                    sizeof(DWORD));
1682     RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
1683     RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
1684                    di3.pDependentFiles, 0);
1685     RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
1686     RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
1687     RegCloseKey(hkeyName);
1688     RegCloseKey(hkeyDrivers);
1689
1690     return TRUE;
1691 }
1692 /*****************************************************************************
1693  *          AddPrinterDriver32W  [WINSPOOL.121]
1694  */
1695 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level, 
1696                                    LPBYTE pDriverInfo)
1697 {
1698     FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
1699           level,pDriverInfo);
1700     return FALSE;
1701 }
1702
1703
1704 /*****************************************************************************
1705  *          PrinterProperties  [WINSPOOL.201]
1706  *
1707  *     Displays a dialog to set the properties of the printer.
1708  *
1709  * RETURNS 
1710  *     nonzero on succes or zero on faillure
1711  *
1712  * BUGS
1713  *         implemented as stub only
1714  */
1715 BOOL WINAPI PrinterProperties(HWND hWnd,      /* handle to parent window */
1716                               HANDLE hPrinter /* handle to printer object */
1717 ){
1718     FIXME("(%d,%d): stub\n", hWnd, hPrinter);
1719     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1720     return FALSE;
1721 }
1722
1723