Fix off by one error in WINSPOOL_GetOpenedPrinterA.
[wine.git] / dlls / winspool / info.c
blob67a97bf30fff4780c74e94b876c4103fb42c6e75
1 /*
2 * WINSPOOL functions
3 *
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 */
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include "winspool.h"
13 #include "winbase.h"
14 #include "winerror.h"
15 #include "winreg.h"
16 #include "debugtools.h"
17 #include "heap.h"
18 #include "commctrl.h"
20 DEFAULT_DEBUG_CHANNEL(winspool)
22 CRITICAL_SECTION PRINT32_RegistryBlocker;
24 typedef struct _OPENEDPRINTERA
26 LPSTR lpsPrinterName;
27 HANDLE hPrinter;
28 LPPRINTER_DEFAULTSA lpDefault;
29 } OPENEDPRINTERA, *LPOPENEDPRINTERA;
31 /* The OpenedPrinter Table dynamic array */
32 static HDPA pOpenedPrinterDPA = NULL;
34 extern HDPA (WINAPI* WINSPOOL_DPA_CreateEx) (INT, HANDLE);
35 extern LPVOID (WINAPI* WINSPOOL_DPA_GetPtr) (const HDPA, INT);
36 extern INT (WINAPI* WINSPOOL_DPA_InsertPtr) (const HDPA, INT, LPVOID);
38 static char Printers[] =
39 "System\\CurrentControlSet\\control\\Print\\Printers\\";
40 static char Drivers[] =
41 "System\\CurrentControlSet\\control\\Print\\Environments\\Wine\\Drivers\\";
43 /******************************************************************
44 * WINSPOOL_GetOpenedPrinterEntryA
45 * Get the first place empty in the opened printer table
47 static LPOPENEDPRINTERA WINSPOOL_GetOpenedPrinterEntryA()
49 int i;
50 LPOPENEDPRINTERA pOpenedPrinter;
53 * Create the opened printers' handle dynamic array.
55 if (!pOpenedPrinterDPA)
57 pOpenedPrinterDPA = WINSPOOL_DPA_CreateEx(10, GetProcessHeap());
58 for (i = 0; i < 10; i++)
60 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
61 HEAP_ZERO_MEMORY,
62 sizeof(OPENEDPRINTERA));
63 pOpenedPrinter->hPrinter = -1;
64 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
69 * Search for a handle not yet allocated.
71 for (i = 0; i < pOpenedPrinterDPA->nItemCount; i++)
73 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, i);
75 if (pOpenedPrinter->hPrinter == -1)
77 pOpenedPrinter->hPrinter = i + 1;
78 return pOpenedPrinter;
83 * Didn't find one, insert new element in the array.
85 if (i == pOpenedPrinterDPA->nItemCount)
87 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
88 HEAP_ZERO_MEMORY,
89 sizeof(OPENEDPRINTERA));
90 pOpenedPrinter->hPrinter = i + 1;
91 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
92 return pOpenedPrinter;
95 return NULL;
98 /******************************************************************
99 * WINSPOOL_GetOpenedPrinterA
100 * Get the pointer to the opened printer referred by the handle
102 static LPOPENEDPRINTERA WINSPOOL_GetOpenedPrinterA(int printerHandle)
104 LPOPENEDPRINTERA pOpenedPrinter;
106 if(!pOpenedPrinterDPA) return NULL;
107 if((printerHandle <=0) ||
108 (printerHandle > (pOpenedPrinterDPA->nItemCount - 1)))
109 return NULL;
111 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1);
113 return pOpenedPrinter;
116 /******************************************************************
117 * DeviceCapabilities32A [WINSPOOL.151]
120 INT WINAPI DeviceCapabilitiesA(LPCSTR pDeivce,LPCSTR pPort, WORD cap,
121 LPSTR pOutput, LPDEVMODEA lpdm)
123 return GDI_CallDeviceCapabilities16(pDeivce, pPort, cap, pOutput, lpdm);
128 /*****************************************************************************
129 * DeviceCapabilities32W
131 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
132 WORD fwCapability, LPWSTR pOutput,
133 const DEVMODEW *pDevMode)
135 FIXME("(%p,%p,%d,%p,%p): stub\n",
136 pDevice, pPort, fwCapability, pOutput, pDevMode);
137 return -1;
140 /******************************************************************
141 * DocumentProperties32A [WINSPOOL.155]
144 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
145 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
146 LPDEVMODEA pDevModeInput,DWORD fMode )
148 LPOPENEDPRINTERA lpOpenedPrinter;
149 LPSTR lpName = pDeviceName;
151 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
152 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
155 if(!pDeviceName) {
156 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
157 if(!lpOpenedPrinter) {
158 SetLastError(ERROR_INVALID_HANDLE);
159 return -1;
161 lpName = lpOpenedPrinter->lpsPrinterName;
164 return GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, NULL,
165 pDevModeInput, NULL, fMode);
170 /*****************************************************************************
171 * DocumentProperties32W
173 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
174 LPWSTR pDeviceName,
175 LPDEVMODEW pDevModeOutput,
176 LPDEVMODEW pDevModeInput, DWORD fMode)
178 FIXME("(%d,%d,%s,%p,%p,%ld): stub\n",
179 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
180 fMode);
181 return -1;
185 /******************************************************************
186 * OpenPrinter32A [WINSPOOL.196]
189 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
190 LPPRINTER_DEFAULTSA pDefault)
192 /* Not implemented: use the DesiredAccess of pDefault to set
193 the access rights to the printer */
195 LPOPENEDPRINTERA lpOpenedPrinter;
197 TRACE("(printerName: %s, pDefault %p\n", lpPrinterName, pDefault);
199 /* Get a place in the opened printer buffer*/
200 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntryA();
202 if((lpOpenedPrinter != NULL) && (lpPrinterName !=NULL) &&
203 (phPrinter != NULL))
205 /* Get the name of the printer */
206 lpOpenedPrinter->lpsPrinterName =
207 HeapAlloc(GetProcessHeap(), 0, lstrlenA(lpPrinterName));
208 lstrcpyA(lpOpenedPrinter->lpsPrinterName, lpPrinterName);
210 /* Get the unique handle of the printer*/
211 *phPrinter = lpOpenedPrinter->hPrinter;
213 if (pDefault != NULL)
215 /* Allocate enough memory for the lpDefault structure */
216 lpOpenedPrinter->lpDefault =
217 HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTER_DEFAULTSA));
218 lpOpenedPrinter->lpDefault->pDevMode =
219 HeapAlloc(GetProcessHeap(), 0, sizeof(DEVMODEA));
220 lpOpenedPrinter->lpDefault->pDatatype =
221 HeapAlloc(GetProcessHeap(), 0, lstrlenA(pDefault->pDatatype));
223 /*Copy the information from incoming parameter*/
224 memcpy(lpOpenedPrinter->lpDefault->pDevMode, pDefault->pDevMode,
225 sizeof(DEVMODEA));
226 lstrcpyA(lpOpenedPrinter->lpDefault->pDatatype,
227 pDefault->pDatatype);
228 lpOpenedPrinter->lpDefault->DesiredAccess =
229 pDefault->DesiredAccess;
232 return TRUE;
235 if(lpOpenedPrinter == NULL)
236 FIXME("Reach the OpenedPrinterTable maximum, augment this max.\n");
237 return FALSE;
240 /******************************************************************
241 * OpenPrinter32W [WINSPOOL.197]
244 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
245 LPPRINTER_DEFAULTSW pDefault)
247 FIXME("(%s,%p,%p):stub\n",debugstr_w(lpPrinterName), phPrinter,
248 pDefault);
249 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
250 return FALSE;
256 /******************************************************************
257 * ENUMPRINTERS_GetDWORDFromRegistryA internal
259 * Reads a DWORD from registry KeyName
261 * RETURNS
262 * value on OK or NULL on error
264 DWORD ENUMPRINTERS_GetDWORDFromRegistryA(
265 HKEY hPrinterSettings, /* handle to registry key */
266 LPSTR KeyName /* name key to retrieve string from*/
268 DWORD DataSize=8;
269 DWORD DataType;
270 BYTE Data[8];
271 DWORD Result=684;
273 if (RegQueryValueExA(hPrinterSettings, KeyName, NULL, &DataType,
274 Data, &DataSize)!=ERROR_SUCCESS)
275 FIXME("Query of register '%s' didn't succeed?\n", KeyName);
276 if (DataType == REG_DWORD_LITTLE_ENDIAN)
277 Result = Data[0] + (Data[1]<<8) + (Data[2]<<16) + (Data[3]<<24);
278 if (DataType == REG_DWORD_BIG_ENDIAN)
279 Result = Data[3] + (Data[2]<<8) + (Data[1]<<16) + (Data[0]<<24);
280 return(Result);
284 /******************************************************************
285 * ENUMPRINTERS_AddStringFromRegistryA internal
287 * Reads a string from registry KeyName and writes it at
288 * lpbPrinters[dwNextStringPos]. Store reference to string in Dest.
290 * RETURNS
291 * FALSE if there is still space left in the buffer.
293 BOOL ENUMPRINTERS_AddStringFromRegistryA(
294 HKEY hPrinterSettings, /* handle to registry key */
295 LPSTR KeyName, /* name key to retrieve string from*/
296 LPSTR* Dest, /* pointer to write string addres to */
297 LPBYTE lpbPrinters, /* buffer which receives info*/
298 LPDWORD dwNextStringPos,/* pos in buffer for next string */
299 DWORD dwBufSize, /* max size of buffer in bytes */
300 BOOL bCalcSpaceOnly /* TRUE if out-of-space in buffer */
302 DWORD DataSize=34;
303 DWORD DataType;
304 LPSTR Data = (LPSTR) malloc(DataSize*sizeof(char));
306 while(RegQueryValueExA(hPrinterSettings, KeyName, NULL, &DataType,
307 Data, &DataSize)==ERROR_MORE_DATA)
309 Data = (LPSTR) realloc(Data, DataSize+2);
312 if (DataType == REG_SZ)
314 if (bCalcSpaceOnly==FALSE)
315 *Dest = &lpbPrinters[*dwNextStringPos];
316 *dwNextStringPos += DataSize+1;
317 if (*dwNextStringPos > dwBufSize)
318 bCalcSpaceOnly=TRUE;
319 if (bCalcSpaceOnly==FALSE)
321 if (DataSize==0) /* DataSize = 0 means empty string, even though*/
322 *Dest[0]=0; /* the data itself needs not to be empty */
323 else
324 strcpy(*Dest, Data);
327 else
328 WARN("Expected string setting, got something else from registry");
330 if (Data)
331 free(Data);
332 return(bCalcSpaceOnly);
337 /******************************************************************
338 * ENUMPRINTERS_AddInfo2A internal
340 * Creates a PRINTER_INFO_2A structure at: lpbPrinters[dwNextStructPos]
341 * for printer PrinterNameKey.
342 * Note that there is no check whether the information really fits!
344 * RETURNS
345 * FALSE if there is still space left in the buffer.
347 * BUGS:
348 * This function should not only read the registry but also ask the driver
349 * for information.
351 BOOL ENUMPRINTERS_AddInfo2A(
352 LPSTR lpszPrinterName,/* name of printer to fill struct for*/
353 LPBYTE lpbPrinters, /* buffer which receives info*/
354 DWORD dwNextStructPos, /* pos in buffer for struct */
355 LPDWORD dwNextStringPos, /* pos in buffer for next string */
356 DWORD dwBufSize, /* max size of buffer in bytes */
357 BOOL bCalcSpaceOnly /* TRUE if out-of-space in buffer */
359 HKEY hPrinterSettings;
360 DWORD DevSize=0;
361 DWORD DataType;
362 LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
363 strlen(lpszPrinterName)+2);
364 LPPRINTER_INFO_2A lpPInfo2 = (LPPRINTER_INFO_2A) &lpbPrinters[dwNextStructPos];
366 /* open the registry to find the attributes, etc of the printer */
367 if (lpszPrinterSettings!=NULL)
369 strcpy(lpszPrinterSettings,Printers);
370 strcat(lpszPrinterSettings,lpszPrinterName);
372 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0,
373 KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
375 WARN("The registry did not contain my printer anymore?\n");
377 else
379 if (bCalcSpaceOnly==FALSE)
380 lpPInfo2->pServerName = NULL;
381 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
382 "Name", &(lpPInfo2->pPrinterName),
383 lpbPrinters, dwNextStringPos,
384 dwBufSize, bCalcSpaceOnly);
385 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
386 "Share Name", &(lpPInfo2->pShareName),
387 lpbPrinters, dwNextStringPos,
388 dwBufSize, bCalcSpaceOnly);
389 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
390 "Port", &(lpPInfo2->pPortName),
391 lpbPrinters, dwNextStringPos,
392 dwBufSize, bCalcSpaceOnly);
393 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
394 "Printer Driver", &(lpPInfo2->pDriverName),
395 lpbPrinters, dwNextStringPos,
396 dwBufSize, bCalcSpaceOnly);
397 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
398 "Description", &(lpPInfo2->pComment),
399 lpbPrinters, dwNextStringPos,
400 dwBufSize, bCalcSpaceOnly);
401 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
402 "Location", &(lpPInfo2->pLocation),
403 lpbPrinters, dwNextStringPos,
404 dwBufSize, bCalcSpaceOnly);
406 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
407 "Separator File", &(lpPInfo2->pSepFile),
408 lpbPrinters, dwNextStringPos,
409 dwBufSize, bCalcSpaceOnly);
410 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
411 "Print Processor", &(lpPInfo2->pPrintProcessor),
412 lpbPrinters, dwNextStringPos,
413 dwBufSize, bCalcSpaceOnly);
414 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
415 "Datatype", &(lpPInfo2->pDatatype),
416 lpbPrinters, dwNextStringPos,
417 dwBufSize, bCalcSpaceOnly);
418 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
419 "Parameters", &(lpPInfo2->pParameters),
420 lpbPrinters, dwNextStringPos,
421 dwBufSize, bCalcSpaceOnly);
422 if (bCalcSpaceOnly == FALSE)
424 lpPInfo2->pSecurityDescriptor = NULL; /* EnumPrinters doesn't return this*/
426 /* FIXME: Attributes gets LOCAL as no REMOTE exists*/
427 lpPInfo2->Attributes = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
428 "Attributes") +PRINTER_ATTRIBUTE_LOCAL;
429 lpPInfo2->Priority = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
430 "Priority");
431 lpPInfo2->DefaultPriority = ENUMPRINTERS_GetDWORDFromRegistryA(
432 hPrinterSettings, "Default Priority");
433 lpPInfo2->StartTime = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
434 "StartTime");
435 lpPInfo2->UntilTime = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
436 "UntilTime");
437 lpPInfo2->Status = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
438 "Status");
439 lpPInfo2->cJobs = 0; /* FIXME: according to MSDN, this does not
440 * reflect the TotalJobs Key ??? */
441 lpPInfo2->AveragePPM = 0; /* FIXME: according to MSDN, this does not
442 * reflect the TotalPages Key ??? */
444 /* and read the devModes structure... */
445 RegQueryValueExA(hPrinterSettings, "pDevMode", NULL, &DataType,
446 NULL, &DevSize); /* should return ERROR_MORE_DATA */
447 lpPInfo2->pDevMode = (LPDEVMODEA) &lpbPrinters[*dwNextStringPos];
448 *dwNextStringPos += DevSize + 1;
450 if (*dwNextStringPos > dwBufSize)
451 bCalcSpaceOnly=TRUE;
452 if (bCalcSpaceOnly==FALSE)
453 RegQueryValueExA(hPrinterSettings, "pDevMode", NULL, &DataType,
454 (LPBYTE)lpPInfo2->pDevMode, &DevSize);
457 if (lpszPrinterSettings)
458 free(lpszPrinterSettings);
460 return(bCalcSpaceOnly);
463 /******************************************************************
464 * ENUMPRINTERS_AddInfo4A internal
466 * Creates a PRINTER_INFO_4A structure at: lpbPrinters[dwNextStructPos]
467 * for printer PrinterNameKey.
468 * Note that there is no check whether the information really fits!
470 * RETURNS
471 * FALSE if there is still space left in the buffer.
473 * BUGS:
474 * This function should not exist in Win95 mode, but does anyway.
476 BOOL ENUMPRINTERS_AddInfo4A(
477 LPSTR lpszPrinterName,/* name of printer to fill struct for*/
478 LPBYTE lpbPrinters, /* buffer which receives info*/
479 DWORD dwNextStructPos, /* pos in buffer for struct */
480 LPDWORD dwNextStringPos, /* pos in buffer for next string */
481 DWORD dwBufSize, /* max size of buffer in bytes */
482 BOOL bCalcSpaceOnly /* TRUE if out-of-space in buffer */
484 HKEY hPrinterSettings;
485 LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
486 strlen(lpszPrinterName)+2);
487 LPPRINTER_INFO_4A lpPInfo4 = (LPPRINTER_INFO_4A) &lpbPrinters[dwNextStructPos];
489 /* open the registry to find the attributes of the printer */
490 if (lpszPrinterSettings!=NULL)
492 strcpy(lpszPrinterSettings,Printers);
493 strcat(lpszPrinterSettings,lpszPrinterName);
495 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0,
496 KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
498 WARN("The registry did not contain my printer anymore?\n");
500 else
502 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
503 "Name", &(lpPInfo4->pPrinterName),
504 lpbPrinters, dwNextStringPos,
505 dwBufSize, bCalcSpaceOnly);
506 /* FIXME: Attributes gets LOCAL as no REMOTE exists*/
507 if (bCalcSpaceOnly==FALSE)
508 lpPInfo4->Attributes = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
509 "Attributes") +PRINTER_ATTRIBUTE_LOCAL;
511 if (lpszPrinterSettings)
512 free(lpszPrinterSettings);
514 return(bCalcSpaceOnly);
517 /******************************************************************
518 * ENUMPRINTERS_AddInfo5A internal
520 * Creates a PRINTER_INFO_5A structure at: lpbPrinters[dwNextStructPos]
521 * for printer PrinterNameKey.
522 * Settings are read from the registry.
523 * Note that there is no check whether the information really fits!
524 * RETURNS
525 * FALSE if there is still space left in the buffer.
527 BOOL ENUMPRINTERS_AddInfo5A(
528 LPSTR lpszPrinterName,/* name of printer to fill struct for*/
529 LPBYTE lpbPrinters, /* buffer which receives info*/
530 DWORD dwNextStructPos, /* pos in buffer for struct */
531 LPDWORD dwNextStringPos, /* pos in buffer for next string */
532 DWORD dwBufSize, /* max size of buffer in bytes */
533 BOOL bCalcSpaceOnly /* TRUE if out-of-space in buffer */
535 HKEY hPrinterSettings;
536 LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
537 strlen(lpszPrinterName)+2);
538 LPPRINTER_INFO_5A lpPInfo5 = (LPPRINTER_INFO_5A) &lpbPrinters[dwNextStructPos];
540 /* open the registry to find the attributes, etc of the printer */
541 if (lpszPrinterSettings!=NULL)
543 strcpy(lpszPrinterSettings,Printers);
544 strcat(lpszPrinterSettings,lpszPrinterName);
546 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0,
547 KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
549 WARN("The registry did not contain my printer anymore?\n");
551 else
553 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
554 "Name", &(lpPInfo5->pPrinterName),
555 lpbPrinters, dwNextStringPos,
556 dwBufSize, bCalcSpaceOnly);
557 bCalcSpaceOnly = ENUMPRINTERS_AddStringFromRegistryA(hPrinterSettings,
558 "Port", &(lpPInfo5->pPortName), lpbPrinters,
559 dwNextStringPos, dwBufSize, bCalcSpaceOnly);
560 /* FIXME: Attributes gets LOCAL as no REMOTE exists*/
561 if (bCalcSpaceOnly == FALSE)
563 lpPInfo5->Attributes = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
564 "Attributes") +PRINTER_ATTRIBUTE_LOCAL;
565 lpPInfo5->DeviceNotSelectedTimeOut
566 = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
567 "txTimeout");
568 lpPInfo5->TransmissionRetryTimeout
569 = ENUMPRINTERS_GetDWORDFromRegistryA(hPrinterSettings,
570 "dnsTimeout");
574 if (lpszPrinterSettings)
575 free(lpszPrinterSettings);
577 return(bCalcSpaceOnly);
581 /******************************************************************
582 * EnumPrintersA [WINSPOOL.174]
584 * Enumerates the available printers, print servers and print
585 * providers, depending on the specified flags, name and level.
587 * RETURNS:
589 * If level is set to 1:
590 * Not implemented yet!
591 * Returns TRUE with an empty list.
593 * If level is set to 2:
594 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
595 * Returns an array of PRINTER_INFO_2 data structures in the
596 * lpbPrinters buffer. Note that according to MSDN also an
597 * OpenPrinter should be performed on every remote printer.
599 * If level is set to 4 (officially WinNT only):
600 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
601 * Fast: Only the registry is queried to retrieve printer names,
602 * no connection to the driver is made.
603 * Returns an array of PRINTER_INFO_4 data structures in the
604 * lpbPrinters buffer.
606 * If level is set to 5 (officially WinNT4/Win9x only):
607 * Fast: Only the registry is queried to retrieve printer names,
608 * no connection to the driver is made.
609 * Returns an array of PRINTER_INFO_5 data structures in the
610 * lpbPrinters buffer.
612 * If level set to 3 or 6+:
613 * returns zero (faillure!)
615 * Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
616 * for information.
618 * BUGS:
619 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
620 * - Only levels 2, 4 and 5 are implemented at the moment.
621 * - 16-bit printer drivers are not enumerated.
622 * - Returned amount of bytes used/needed does not match the real Windoze
623 * implementation (as in this implementation, all strings are part
624 * of the buffer, whereas Win32 keeps them somewhere else)
625 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
627 * NOTE:
628 * - In a regular Wine installation, no registry settings for printers
629 * exist, which makes this function return an empty list.
631 BOOL WINAPI EnumPrintersA(
632 DWORD dwType, /* Types of print objects to enumerate */
633 LPSTR lpszName, /* name of objects to enumerate */
634 DWORD dwLevel, /* type of printer info structure */
635 LPBYTE lpbPrinters, /* buffer which receives info */
636 DWORD cbBuf, /* max size of buffer in bytes */
637 LPDWORD lpdwNeeded, /* pointer to var: # bytes used/needed */
638 LPDWORD lpdwReturned /* number of entries returned */
641 HKEY hPrinterListKey;
642 DWORD dwIndex=0;
643 char PrinterName[255];
644 DWORD PrinterNameLength=255;
645 FILETIME FileTime;
646 DWORD dwNextStringPos; /* position of next space for a string in the buffer*/
647 DWORD dwStructPrinterInfoSize; /* size of a Printer_Info_X structure */
648 BOOL bCalcSpaceOnly=FALSE;/*if TRUE: don't store data, just calculate space*/
650 TRACE("entered.\n");
652 /* test whether we're requested to really fill in. If so,
653 * zero out the data area, and initialise some returns to zero,
654 * to prevent problems
656 if (lpbPrinters==NULL || cbBuf==0)
657 bCalcSpaceOnly=TRUE;
658 else
660 int i;
661 for (i=0; i<cbBuf; i++)
662 lpbPrinters[i]=0;
664 *lpdwReturned=0;
665 *lpdwNeeded = 0;
667 /* check for valid Flags */
668 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME)))
670 FIXME("dwType = %08lx\n", dwType);
671 SetLastError(ERROR_INVALID_FLAGS);
672 return(0);
674 switch(dwLevel)
676 case 1:
677 return(TRUE);
678 case 2:
679 case 4:
680 case 5:
681 break;
682 default:
683 SetLastError(ERROR_INVALID_PARAMETER);
684 return(FALSE);
687 /* Enter critical section to prevent AddPrinters() et al. to
688 * modify whilst we're reading in the registry
690 InitializeCriticalSection(&PRINT32_RegistryBlocker);
691 EnterCriticalSection(&PRINT32_RegistryBlocker);
693 /* get a pointer to a list of all printer names in the registry */
694 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Printers, 0, KEY_READ,
695 &hPrinterListKey) !=ERROR_SUCCESS)
697 /* Oh no! An empty list of printers!
698 * (which is a valid configuration anyway)
700 TRACE("No entries in the Printers part of the registry\n");
703 /* count the number of entries and check if it fits in the buffer
705 while(RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
706 NULL, NULL, NULL, &FileTime)==ERROR_SUCCESS)
708 PrinterNameLength=255;
709 dwIndex++;
711 *lpdwReturned = dwIndex;
712 switch(dwLevel)
714 case 1:
715 dwStructPrinterInfoSize = sizeof(PRINTER_INFO_1A);
716 break;
717 case 2:
718 dwStructPrinterInfoSize = sizeof(PRINTER_INFO_2A);
719 break;
720 case 4:
721 dwStructPrinterInfoSize = sizeof(PRINTER_INFO_4A);
722 break;
723 case 5:
724 dwStructPrinterInfoSize = sizeof(PRINTER_INFO_5A);
725 break;
726 default:
727 dwStructPrinterInfoSize = 0;
728 break;
730 if (dwIndex*dwStructPrinterInfoSize+1 > cbBuf)
731 bCalcSpaceOnly = TRUE;
733 /* the strings which contain e.g. PrinterName, PortName, etc,
734 * are also stored in lpbPrinters, but after the regular structs.
735 * dwNextStringPos will always point to the next free place for a
736 * string.
738 dwNextStringPos=(dwIndex+1)*dwStructPrinterInfoSize;
740 /* check each entry: if OK, add to list in corresponding INFO .
742 for(dwIndex=0; dwIndex < *lpdwReturned; dwIndex++)
744 PrinterNameLength=255;
745 if (RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
746 NULL, NULL, NULL, &FileTime)!=ERROR_SUCCESS)
747 break; /* exit for loop*/
749 /* check whether this printer is allowed in the list
750 * by comparing name to lpszName
752 if (dwType & PRINTER_ENUM_NAME)
753 if (strcmp(PrinterName,lpszName)!=0)
754 continue;
756 switch(dwLevel)
758 case 1:
759 /* FIXME: unimplemented */
760 break;
761 case 2:
762 bCalcSpaceOnly = ENUMPRINTERS_AddInfo2A(PrinterName, lpbPrinters,
763 dwIndex*dwStructPrinterInfoSize,
764 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
765 break;
766 case 4:
767 bCalcSpaceOnly = ENUMPRINTERS_AddInfo4A(PrinterName, lpbPrinters,
768 dwIndex*dwStructPrinterInfoSize,
769 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
770 break;
771 case 5:
772 bCalcSpaceOnly = ENUMPRINTERS_AddInfo5A(PrinterName, lpbPrinters,
773 dwIndex*dwStructPrinterInfoSize,
774 &dwNextStringPos, cbBuf, bCalcSpaceOnly);
775 break;
778 RegCloseKey(hPrinterListKey);
779 *lpdwNeeded = dwNextStringPos;
781 if (bCalcSpaceOnly==TRUE)
783 if (lpbPrinters!=NULL)
785 int i;
786 for (i=0; i<cbBuf; i++)
787 lpbPrinters[i]=0;
789 *lpdwReturned=0;
791 LeaveCriticalSection(&PRINT32_RegistryBlocker);
792 return(TRUE);
795 /******************************************************************
796 * EnumPrinters32W [WINSPOOL.175]
799 BOOL WINAPI EnumPrintersW(DWORD dwType, LPWSTR lpszName,
800 DWORD dwLevel, LPBYTE lpbPrinters,
801 DWORD cbBuf, LPDWORD lpdwNeeded,
802 LPDWORD lpdwReturned)
804 FIXME("Nearly empty stub\n");
805 *lpdwReturned=0;
806 *lpdwNeeded = 0;
807 return TRUE;
810 /******************************************************************
811 * AddMonitor32A [WINSPOOL.107]
814 BOOL WINAPI AddMonitorA(LPCSTR pName, DWORD Level, LPBYTE pMonitors)
816 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
817 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
818 return FALSE;
821 /******************************************************************
822 * DeletePrinterDriver32A [WINSPOOL.146]
825 BOOL WINAPI
826 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
828 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
829 debugstr_a(pDriverName));
830 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
831 return FALSE;
835 /******************************************************************
836 * DeleteMonitor32A [WINSPOOL.135]
839 BOOL WINAPI
840 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
842 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
843 debugstr_a(pMonitorName));
844 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
845 return FALSE;
849 /******************************************************************
850 * DeletePort32A [WINSPOOL.137]
853 BOOL WINAPI
854 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
856 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
857 debugstr_a(pPortName));
858 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
859 return FALSE;
862 /******************************************************************************
863 * SetPrinter32W [WINSPOOL.214]
865 BOOL WINAPI
866 SetPrinterW(
867 HANDLE hPrinter,
868 DWORD Level,
869 LPBYTE pPrinter,
870 DWORD Command) {
872 FIXME("():stub\n");
873 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
874 return FALSE;
877 /******************************************************************************
878 * WritePrinter32 [WINSPOOL.223]
880 BOOL WINAPI
881 WritePrinter(
882 HANDLE hPrinter,
883 LPVOID pBuf,
884 DWORD cbBuf,
885 LPDWORD pcWritten) {
887 FIXME("():stub\n");
888 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
889 return FALSE;
892 /*****************************************************************************
893 * AddForm32A [WINSPOOL.103]
895 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
897 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
898 return 1;
901 /*****************************************************************************
902 * AddForm32W [WINSPOOL.104]
904 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
906 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
907 return 1;
910 /*****************************************************************************
911 * AddJob32A [WINSPOOL.105]
913 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
914 DWORD cbBuf, LPDWORD pcbNeeded)
916 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
917 pcbNeeded);
918 return 1;
921 /*****************************************************************************
922 * AddJob32W [WINSPOOL.106]
924 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
925 LPDWORD pcbNeeded)
927 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
928 pcbNeeded);
929 return 1;
932 /*****************************************************************************
933 * AddPrinter32A [WINSPOOL.117]
935 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
937 PRINTER_INFO_2A *pi = (PRINTER_INFO_2A *) pPrinter;
939 HANDLE retval;
940 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
942 TRACE("(%s,%ld,%p)\n", pName, Level, pPrinter);
944 if(pName != NULL) {
945 FIXME("pName = `%s' - unsupported\n", pName);
946 SetLastError(ERROR_INVALID_PARAMETER);
947 return 0;
949 if(Level != 2) {
950 WARN("Level = %ld\n", Level);
951 SetLastError(ERROR_INVALID_LEVEL);
952 return 0;
954 if(!pPrinter) {
955 SetLastError(ERROR_INVALID_PARAMETER);
956 return 0;
958 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
959 ERROR_SUCCESS) {
960 ERR("Can't create Printers key\n");
961 return 0;
963 if(RegOpenKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
964 ERROR_SUCCESS) {
965 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
966 RegCloseKey(hkeyPrinter);
967 RegCloseKey(hkeyPrinters);
968 return 0;
970 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
971 ERROR_SUCCESS) {
972 ERR("Can't create Drivers key\n");
973 RegCloseKey(hkeyPrinters);
974 return 0;
976 if(RegOpenKeyA(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
977 ERROR_SUCCESS) {
978 WARN("Can't find driver `%s'\n", pi->pDriverName);
979 RegCloseKey(hkeyPrinters);
980 RegCloseKey(hkeyDrivers);
981 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
982 return 0;
984 RegCloseKey(hkeyDriver);
985 RegCloseKey(hkeyDrivers);
986 if(strcasecmp(pi->pPrintProcessor, "WinPrint")) { /* FIXME */
987 WARN("Can't find processor `%s'\n", pi->pPrintProcessor);
988 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
989 RegCloseKey(hkeyPrinters);
990 return 0;
992 if(RegCreateKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
993 ERROR_SUCCESS) {
994 WARN("Can't create printer `%s'\n", pi->pPrinterName);
995 SetLastError(ERROR_INVALID_PRINTER_NAME);
996 RegCloseKey(hkeyPrinters);
997 return 0;
999 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1000 (LPSTR)&pi->Attributes, sizeof(DWORD));
1001 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1002 (LPSTR)&pi->pDevMode,
1003 pi->pDevMode ? pi->pDevMode->dmSize : 0);
1004 RegSetValueExA(hkeyPrinter, "Description", 0, REG_SZ, pi->pComment, 0);
1005 RegSetValueExA(hkeyPrinter, "Location", 0, REG_SZ, pi->pLocation, 0);
1006 RegSetValueExA(hkeyPrinter, "Name", 0, REG_SZ, pi->pPrinterName, 0);
1007 RegSetValueExA(hkeyPrinter, "Parameters", 0, REG_SZ, pi->pParameters, 0);
1008 RegSetValueExA(hkeyPrinter, "Port", 0, REG_SZ, pi->pPortName, 0);
1009 RegSetValueExA(hkeyPrinter, "Print Processor", 0, REG_SZ,
1010 pi->pPrintProcessor, 0);
1011 RegSetValueExA(hkeyPrinter, "Printer Driver", 0, REG_SZ, pi->pDriverName,
1013 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1014 (LPSTR)&pi->Priority, sizeof(DWORD));
1015 RegSetValueExA(hkeyPrinter, "Separator File", 0, REG_SZ, pi->pSepFile, 0);
1016 RegSetValueExA(hkeyPrinter, "Share Name", 0, REG_SZ, pi->pShareName, 0);
1017 RegSetValueExA(hkeyPrinter, "Start Time", 0, REG_DWORD,
1018 (LPSTR)&pi->StartTime, sizeof(DWORD));
1019 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1020 (LPSTR)&pi->Status, sizeof(DWORD));
1021 RegSetValueExA(hkeyPrinter, "Until Time", 0, REG_DWORD,
1022 (LPSTR)&pi->UntilTime, sizeof(DWORD));
1024 RegCloseKey(hkeyPrinter);
1025 RegCloseKey(hkeyPrinters);
1026 if(!OpenPrinterA(pi->pPrinterName, &retval, NULL)) {
1027 ERR("OpenPrinter failing\n");
1028 return 0;
1030 return retval;
1033 /*****************************************************************************
1034 * AddPrinter32W [WINSPOOL.122]
1036 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1038 FIXME("(%p,%ld,%p): stub\n", pName, Level, pPrinter);
1039 return 0;
1043 /*****************************************************************************
1044 * ClosePrinter32 [WINSPOOL.126]
1046 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1048 LPOPENEDPRINTERA lpOpenedPrinter;
1050 TRACE("Handle %d\n", hPrinter);
1052 if (!pOpenedPrinterDPA)
1053 return FALSE;
1055 if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1)))
1057 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1058 HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
1059 lpOpenedPrinter->lpsPrinterName = NULL;
1061 /* Free the memory of lpDefault if it has been initialized*/
1062 if(lpOpenedPrinter->lpDefault != NULL)
1064 HeapFree(GetProcessHeap(), 0,
1065 lpOpenedPrinter->lpDefault->pDevMode);
1066 HeapFree(GetProcessHeap(), 0,
1067 lpOpenedPrinter->lpDefault->pDatatype);
1068 HeapFree(GetProcessHeap(), 0,
1069 lpOpenedPrinter->lpDefault);
1070 lpOpenedPrinter->lpDefault = NULL;
1073 lpOpenedPrinter->hPrinter = -1;
1075 return TRUE;
1077 return FALSE;
1080 /*****************************************************************************
1081 * DeleteForm32A [WINSPOOL.133]
1083 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1085 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1086 return 1;
1089 /*****************************************************************************
1090 * DeleteForm32W [WINSPOOL.134]
1092 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1094 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1095 return 1;
1098 /*****************************************************************************
1099 * DeletePrinter32 [WINSPOOL.143]
1101 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1103 FIXME("(%d): stub\n", hPrinter);
1104 return 1;
1107 /*****************************************************************************
1108 * SetPrinter32A [WINSPOOL.211]
1110 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1111 DWORD Command)
1113 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1114 return FALSE;
1117 /*****************************************************************************
1118 * SetJob32A [WINSPOOL.209]
1120 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1121 LPBYTE pJob, DWORD Command)
1123 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1124 Command);
1125 return FALSE;
1128 /*****************************************************************************
1129 * SetJob32W [WINSPOOL.210]
1131 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1132 LPBYTE pJob, DWORD Command)
1134 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1135 Command);
1136 return FALSE;
1139 /*****************************************************************************
1140 * GetForm32A [WINSPOOL.181]
1142 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1143 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1145 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1146 Level,pForm,cbBuf,pcbNeeded);
1147 return FALSE;
1150 /*****************************************************************************
1151 * GetForm32W [WINSPOOL.182]
1153 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1154 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1156 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1157 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1158 return FALSE;
1161 /*****************************************************************************
1162 * SetForm32A [WINSPOOL.207]
1164 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1165 LPBYTE pForm)
1167 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1168 return FALSE;
1171 /*****************************************************************************
1172 * SetForm32W [WINSPOOL.208]
1174 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1175 LPBYTE pForm)
1177 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1178 return FALSE;
1181 /*****************************************************************************
1182 * ReadPrinter32 [WINSPOOL.202]
1184 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1185 LPDWORD pNoBytesRead)
1187 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1188 return FALSE;
1191 /*****************************************************************************
1192 * ResetPrinter32A [WINSPOOL.203]
1194 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1196 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1197 return FALSE;
1200 /*****************************************************************************
1201 * ResetPrinter32W [WINSPOOL.204]
1203 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1205 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1206 return FALSE;
1210 /*****************************************************************************
1211 * WINSPOOL_GetStringFromRegA
1213 * Get ValueName from hkey storing result in str. buflen is space left in str
1215 static BOOL WINSPOOL_GetStringFromRegA(HKEY hkey, LPCSTR ValueName, LPSTR ptr,
1216 DWORD buflen, DWORD *needed)
1218 DWORD sz = buflen, type;
1219 LONG ret;
1221 ret = RegQueryValueExA(hkey, ValueName, 0, &type, ptr, &sz);
1223 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1224 ERR("Got ret = %ld\n", ret);
1225 return FALSE;
1227 *needed = sz;
1228 return TRUE;
1232 /*****************************************************************************
1233 * GetPrinter32A [WINSPOOL.187]
1235 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1236 DWORD cbBuf, LPDWORD pcbNeeded)
1238 OPENEDPRINTERA *lpOpenedPrinter;
1239 DWORD size, needed = 0;
1240 LPBYTE ptr = NULL;
1241 HKEY hkeyPrinter, hkeyPrinters;
1243 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1245 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1246 if(!lpOpenedPrinter) {
1247 SetLastError(ERROR_INVALID_HANDLE);
1248 return FALSE;
1250 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1251 ERROR_SUCCESS) {
1252 ERR("Can't create Printers key\n");
1253 return FALSE;
1255 if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1256 != ERROR_SUCCESS) {
1257 ERR("Can't find opened printer `%s' in registry\n",
1258 lpOpenedPrinter->lpsPrinterName);
1259 RegCloseKey(hkeyPrinters);
1260 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1261 return FALSE;
1264 switch(Level) {
1265 case 2:
1267 PRINTER_INFO_2A *pi2 = (PRINTER_INFO_2A *)pPrinter;
1269 size = sizeof(PRINTER_INFO_2A);
1270 if(size <= cbBuf) {
1271 ptr = pPrinter + size;
1272 cbBuf -= size;
1273 memset(pPrinter, 0, size);
1274 } else
1275 cbBuf = 0;
1276 needed = size;
1278 WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
1279 if(cbBuf && size <= cbBuf) {
1280 pi2->pPrinterName = ptr;
1281 ptr += size;
1282 } else
1283 cbBuf = 0;
1284 needed += size;
1286 WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
1287 if(cbBuf && size <= cbBuf) {
1288 pi2->pPortName = ptr;
1289 ptr += size;
1290 } else
1291 cbBuf = 0;
1292 needed += size;
1294 WINSPOOL_GetStringFromRegA(hkeyPrinter, "Printer Driver", ptr, cbBuf,
1295 &size);
1296 if(cbBuf && size <= cbBuf) {
1297 pi2->pDriverName = ptr;
1298 ptr += size;
1299 } else
1300 cbBuf = 0;
1301 needed += size;
1303 WINSPOOL_GetStringFromRegA(hkeyPrinter, "Default DevMode", ptr, cbBuf,
1304 &size);
1305 if(cbBuf && size <= cbBuf) {
1306 pi2->pDevMode = (LPDEVMODEA)ptr;
1307 ptr += size;
1308 } else
1309 cbBuf = 0;
1310 needed += size;
1312 WINSPOOL_GetStringFromRegA(hkeyPrinter, "Print Processor", ptr, cbBuf,
1313 &size);
1314 if(cbBuf && size <= cbBuf) {
1315 pi2->pPrintProcessor = ptr;
1316 ptr += size;
1317 } else
1318 cbBuf = 0;
1319 needed += size;
1321 break;
1324 case 5:
1326 PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A *)pPrinter;
1328 size = sizeof(PRINTER_INFO_5A);
1329 if(size <= cbBuf) {
1330 ptr = pPrinter + size;
1331 cbBuf -= size;
1332 memset(pPrinter, 0, size);
1333 } else
1334 cbBuf = 0;
1335 needed = size;
1337 WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
1338 if(cbBuf && size <= cbBuf) {
1339 pi5->pPrinterName = ptr;
1340 ptr += size;
1341 } else
1342 cbBuf = 0;
1343 needed += size;
1345 WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
1346 if(cbBuf && size <= cbBuf) {
1347 pi5->pPortName = ptr;
1348 ptr += size;
1349 } else
1350 cbBuf = 0;
1351 needed += size;
1353 break;
1356 default:
1357 FIXME("Unimplemented level %ld\n", Level);
1358 SetLastError(ERROR_INVALID_LEVEL);
1359 RegCloseKey(hkeyPrinters);
1360 RegCloseKey(hkeyPrinter);
1361 return FALSE;
1364 RegCloseKey(hkeyPrinter);
1365 RegCloseKey(hkeyPrinters);
1367 if(pcbNeeded) *pcbNeeded = needed;
1368 if(cbBuf) return TRUE;
1369 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1370 return FALSE;
1374 /*****************************************************************************
1375 * GetPrinter32W [WINSPOOL.194]
1377 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1378 DWORD cbBuf, LPDWORD pcbNeeded)
1380 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pPrinter,
1381 cbBuf, pcbNeeded);
1382 return FALSE;
1386 /*****************************************************************************
1387 * GetPrinterDriver32A [WINSPOOL.190]
1389 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1390 DWORD Level, LPBYTE pDriverInfo,
1391 DWORD cbBuf, LPDWORD pcbNeeded)
1393 OPENEDPRINTERA *lpOpenedPrinter;
1394 char DriverName[100];
1395 DWORD ret, type, size, dw, needed = 0;
1396 LPBYTE ptr = NULL;
1397 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1399 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,pEnvironment,
1400 Level,pDriverInfo,cbBuf, pcbNeeded);
1402 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
1403 if(!lpOpenedPrinter) {
1404 SetLastError(ERROR_INVALID_HANDLE);
1405 return FALSE;
1407 if(pEnvironment) {
1408 FIXME("pEnvironment = `%s'\n", pEnvironment);
1409 SetLastError(ERROR_INVALID_ENVIRONMENT);
1410 return FALSE;
1412 if(Level < 1 || Level > 3) {
1413 SetLastError(ERROR_INVALID_LEVEL);
1414 return FALSE;
1416 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1417 ERROR_SUCCESS) {
1418 ERR("Can't create Printers key\n");
1419 return FALSE;
1421 if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1422 != ERROR_SUCCESS) {
1423 ERR("Can't find opened printer `%s' in registry\n",
1424 lpOpenedPrinter->lpsPrinterName);
1425 RegCloseKey(hkeyPrinters);
1426 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1427 return FALSE;
1429 size = sizeof(DriverName);
1430 ret = RegQueryValueExA(hkeyPrinter, "Printer Driver", 0, &type, DriverName,
1431 &size);
1432 RegCloseKey(hkeyPrinter);
1433 RegCloseKey(hkeyPrinters);
1434 if(ret != ERROR_SUCCESS) {
1435 ERR("Can't get DriverName for printer `%s'\n",
1436 lpOpenedPrinter->lpsPrinterName);
1437 return FALSE;
1439 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1440 ERROR_SUCCESS) {
1441 ERR("Can't create Drivers key\n");
1442 return FALSE;
1444 if(RegOpenKeyA(hkeyDrivers, DriverName, &hkeyDriver)
1445 != ERROR_SUCCESS) {
1446 ERR("Can't find driver `%s' in registry\n", DriverName);
1447 RegCloseKey(hkeyDrivers);
1448 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1449 return FALSE;
1452 switch(Level) {
1453 case 1:
1454 size = sizeof(DRIVER_INFO_1A);
1455 break;
1456 case 2:
1457 size = sizeof(DRIVER_INFO_2A);
1458 break;
1459 case 3:
1460 size = sizeof(DRIVER_INFO_3A);
1461 break;
1462 default:
1463 ERR("Invalid level\n");
1464 return FALSE;
1467 if(size <= cbBuf) {
1468 ptr = pDriverInfo + size;
1469 cbBuf -= size;
1470 } else
1471 cbBuf = 0;
1472 needed = size;
1474 size = strlen(DriverName) + 1;
1475 if(size <= cbBuf) {
1476 cbBuf -= size;
1477 strcpy(ptr, DriverName);
1478 if(Level == 1)
1479 ((DRIVER_INFO_1A *)pDriverInfo)->pName = ptr;
1480 else
1481 ((DRIVER_INFO_2A *)pDriverInfo)->pName = ptr;
1482 ptr += size;
1484 needed += size;
1486 if(Level > 1) {
1487 DRIVER_INFO_2A *di2 = (DRIVER_INFO_2A *)pDriverInfo;
1489 size = sizeof(dw);
1490 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw,
1491 &size) !=
1492 ERROR_SUCCESS)
1493 WARN("Can't get Version\n");
1494 else if(cbBuf)
1495 di2->cVersion = dw;
1497 size = strlen("Wine") + 1; /* FIXME */
1498 if(size <= cbBuf) {
1499 cbBuf -= size;
1500 strcpy(ptr, "Wine");
1501 di2->pEnvironment = ptr;
1502 ptr += size;
1503 } else
1504 cbBuf = 0;
1505 needed += size;
1507 WINSPOOL_GetStringFromRegA(hkeyDriver, "Driver", ptr, cbBuf, &size);
1508 if(cbBuf && size <= cbBuf) {
1509 di2->pDriverPath = ptr;
1510 ptr += size;
1511 } else
1512 cbBuf = 0;
1513 needed += size;
1515 WINSPOOL_GetStringFromRegA(hkeyDriver, "Data File", ptr, cbBuf, &size);
1516 if(cbBuf && size <= cbBuf) {
1517 di2->pDataFile = ptr;
1518 ptr += size;
1519 } else
1520 cbBuf = 0;
1521 needed += size;
1523 WINSPOOL_GetStringFromRegA(hkeyDriver, "Configuration File", ptr,
1524 cbBuf, &size);
1525 if(cbBuf && size <= cbBuf) {
1526 di2->pConfigFile = ptr;
1527 ptr += size;
1528 } else
1529 cbBuf = 0;
1530 needed += size;
1533 if(Level > 2) {
1534 DRIVER_INFO_3A *di3 = (DRIVER_INFO_3A *)pDriverInfo;
1536 WINSPOOL_GetStringFromRegA(hkeyDriver, "Help File", ptr, cbBuf, &size);
1537 if(cbBuf && size <= cbBuf) {
1538 di3->pHelpFile = ptr;
1539 ptr += size;
1540 } else
1541 cbBuf = 0;
1542 needed += size;
1544 WINSPOOL_GetStringFromRegA(hkeyDriver, "Dependent Files", ptr, cbBuf,
1545 &size);
1546 if(cbBuf && size <= cbBuf) {
1547 di3->pDependentFiles = ptr;
1548 ptr += size;
1549 } else
1550 cbBuf = 0;
1551 needed += size;
1553 WINSPOOL_GetStringFromRegA(hkeyDriver, "Monitor", ptr, cbBuf, &size);
1554 if(cbBuf && size <= cbBuf) {
1555 di3->pMonitorName = ptr;
1556 ptr += size;
1557 } else
1558 cbBuf = 0;
1559 needed += size;
1561 WINSPOOL_GetStringFromRegA(hkeyDriver, "DataType", ptr, cbBuf, &size);
1562 if(cbBuf && size <= cbBuf) {
1563 di3->pDefaultDataType = ptr;
1564 ptr += size;
1565 } else
1566 cbBuf = 0;
1567 needed += size;
1569 RegCloseKey(hkeyDriver);
1570 RegCloseKey(hkeyDrivers);
1572 if(pcbNeeded) *pcbNeeded = needed;
1573 if(cbBuf) return TRUE;
1574 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1575 return FALSE;
1578 /*****************************************************************************
1579 * GetPrinterDriver32W [WINSPOOL.193]
1581 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1582 DWORD Level, LPBYTE pDriverInfo,
1583 DWORD cbBuf, LPDWORD pcbNeeded)
1585 FIXME("(%d,%p,%ld,%p,%ld,%p): stub\n",hPrinter,pEnvironment,
1586 Level,pDriverInfo,cbBuf, pcbNeeded);
1587 return FALSE;
1590 /*****************************************************************************
1591 * GetPrinterDriverDirectoryA [WINSPOOL.191]
1593 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1594 DWORD Level, LPBYTE pDriverDirectory,
1595 DWORD cbBuf, LPDWORD pcbNeeded)
1597 DWORD needed;
1599 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1600 pDriverDirectory, cbBuf, pcbNeeded);
1601 if(pName != NULL) {
1602 FIXME("pName = `%s' - unsupported\n", pName);
1603 SetLastError(ERROR_INVALID_PARAMETER);
1604 return FALSE;
1606 if(pEnvironment != NULL) {
1607 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1608 SetLastError(ERROR_INVALID_ENVIRONMENT);
1609 return FALSE;
1611 if(Level != 1) /* win95 ignores this so we just carry on */
1612 WARN("Level = %ld - assuming 1\n", Level);
1614 /* FIXME should read from registry */
1615 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
1616 needed++;
1617 if(pcbNeeded)
1618 *pcbNeeded = needed;
1619 if(needed > cbBuf) {
1620 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1621 return FALSE;
1623 return TRUE;
1627 /*****************************************************************************
1628 * GetPrinterDriverDirectoryW [WINSPOOL.192]
1630 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
1631 DWORD Level, LPBYTE pDriverDirectory,
1632 DWORD cbBuf, LPDWORD pcbNeeded)
1634 LPSTR pNameA = NULL, pEnvironmentA = NULL;
1635 BOOL ret;
1637 if(pName)
1638 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
1639 if(pEnvironment)
1640 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
1641 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
1642 pDriverDirectory, cbBuf, pcbNeeded );
1643 if(pNameA)
1644 HeapFree( GetProcessHeap(), 0, pNameA );
1645 if(pEnvironmentA)
1646 HeapFree( GetProcessHeap(), 0, pEnvironment );
1648 return ret;
1651 /*****************************************************************************
1652 * AddPrinterDriver32A [WINSPOOL.120]
1654 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
1656 DRIVER_INFO_3A di3;
1657 HKEY hkeyDrivers, hkeyName;
1659 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
1661 if(level != 2 && level != 3) {
1662 SetLastError(ERROR_INVALID_LEVEL);
1663 return FALSE;
1665 if(pName != NULL) {
1666 FIXME("pName= `%s' - unsupported\n", pName);
1667 SetLastError(ERROR_INVALID_PARAMETER);
1668 return FALSE;
1670 if(!pDriverInfo) {
1671 WARN("pDriverInfo == NULL");
1672 SetLastError(ERROR_INVALID_PARAMETER);
1673 return FALSE;
1676 if(level == 3)
1677 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
1678 else {
1679 memset(&di3, 0, sizeof(di3));
1680 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
1683 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
1684 !di3.pDataFile) {
1685 SetLastError(ERROR_INVALID_PARAMETER);
1686 return FALSE;
1688 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
1689 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
1690 if(!di3.pHelpFile) di3.pHelpFile = "";
1691 if(!di3.pMonitorName) di3.pMonitorName = "";
1693 if(di3.pEnvironment) {
1694 FIXME("pEnvironment = `%s'\n", di3.pEnvironment);
1695 SetLastError(ERROR_INVALID_ENVIRONMENT);
1696 return FALSE;
1698 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1699 ERROR_SUCCESS) {
1700 ERR("Can't create Drivers key\n");
1701 return FALSE;
1704 if(level == 2) { /* apparently can't overwrite with level2 */
1705 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
1706 RegCloseKey(hkeyName);
1707 RegCloseKey(hkeyDrivers);
1708 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
1709 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1710 return FALSE;
1713 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
1714 RegCloseKey(hkeyDrivers);
1715 ERR("Can't create Name key\n");
1716 return FALSE;
1718 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
1720 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
1721 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
1722 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
1723 sizeof(DWORD));
1724 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
1725 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
1726 di3.pDependentFiles, 0);
1727 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
1728 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
1729 RegCloseKey(hkeyName);
1730 RegCloseKey(hkeyDrivers);
1732 return TRUE;
1734 /*****************************************************************************
1735 * AddPrinterDriver32W [WINSPOOL.121]
1737 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
1738 LPBYTE pDriverInfo)
1740 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
1741 level,pDriverInfo);
1742 return FALSE;
1746 /*****************************************************************************
1747 * PrinterProperties [WINSPOOL.201]
1749 * Displays a dialog to set the properties of the printer.
1751 * RETURNS
1752 * nonzero on succes or zero on faillure
1754 * BUGS
1755 * implemented as stub only
1757 BOOL WINAPI PrinterProperties(HWND hWnd, /* handle to parent window */
1758 HANDLE hPrinter /* handle to printer object */
1760 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
1761 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1762 return FALSE;
1765 /*****************************************************************************
1766 * EnumJobsA [WINSPOOL.162]
1769 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
1770 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
1771 LPDWORD pcReturned)
1773 FIXME("stub\n");
1774 if(pcbNeeded) *pcbNeeded = 0;
1775 if(pcReturned) *pcReturned = 0;
1776 return TRUE;
1780 /*****************************************************************************
1781 * EnumJobsW [WINSPOOL.163]
1784 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
1785 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
1786 LPDWORD pcReturned)
1788 FIXME("stub\n");
1789 if(pcbNeeded) *pcbNeeded = 0;
1790 if(pcReturned) *pcReturned = 0;
1791 return TRUE;