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