4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/port.h"
33 #ifdef HAVE_CUPS_CUPS_H
34 # include <cups/cups.h>
36 # define CUPS_SONAME "libcups.so"
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "wine/library.h"
49 #include "wine/windef16.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
57 static LPWSTR *printer_array;
58 static int nb_printers;
60 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
61 WORD fwCapability, LPSTR lpszOutput,
63 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
64 LPSTR lpszDevice, LPSTR lpszPort,
65 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
68 static char Printers[] =
69 "System\\CurrentControlSet\\control\\Print\\Printers\\";
70 static char Drivers[] =
71 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
73 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
75 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
76 'i','o','n',' ','F','i','l','e',0};
77 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
78 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
79 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
81 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
83 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
84 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
85 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
86 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
87 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
88 static WCHAR NameW[] = {'N','a','m','e',0};
89 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
90 static WCHAR PortW[] = {'P','o','r','t',0};
91 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
93 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
95 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
96 'v','e','r','D','a','t','a',0};
97 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
99 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
100 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
102 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
103 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
104 DWORD Level, LPBYTE pDriverInfo,
105 DWORD cbBuf, LPDWORD pcbNeeded,
108 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
111 /* If forcing, or no profile string entry for device yet, set the entry
113 * The always change entry if not WINEPS yet is discussable.
116 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
118 !strstr(qbuf,"WINEPS")
120 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
122 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
123 WriteProfileStringA("windows","device",buf);
124 HeapFree(GetProcessHeap(),0,buf);
128 #ifdef HAVE_CUPS_CUPS_H
130 CUPS_LoadPrinters(void) {
131 typeof(cupsGetPrinters) *pcupsGetPrinters = NULL;
132 typeof(cupsGetDefault) *pcupsGetDefault = NULL;
133 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
135 int i,nrofdests,hadprinter = FALSE;
136 PRINTER_INFO_2A pinfo2a;
138 void *cupshandle = NULL;
140 cupshandle = wine_dlopen(CUPS_SONAME, RTLD_NOW, NULL, 0);
145 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
146 if (!p##x) return FALSE;
148 DYNCUPS(cupsGetDefault);
150 DYNCUPS(cupsGetPrinters);
153 def = pcupsGetDefault();
155 if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
158 nrofdests = pcupsGetPrinters(&printers);
159 for (i=0;i<nrofdests;i++) {
160 const char *ppd = pcupsGetPPD(printers[i]);
164 WARN("No ppd file for %s.\n",printers[i]);
165 /* If this was going to be the default printer,
166 * forget it and use another one.
168 if (def && !strcmp(def,printers[i]))
176 if (def && !strcmp(def,printers[i]))
177 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
179 /* The default printer has no PPD file, just use the first one
183 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
186 memset(&pinfo2a,0,sizeof(pinfo2a));
187 pinfo2a.pPrinterName = printers[i];
188 pinfo2a.pDatatype = "RAW";
189 pinfo2a.pPrintProcessor = "WinPrint";
190 pinfo2a.pDriverName = "PS Driver";
191 pinfo2a.pComment = "WINEPS Printer using CUPS";
192 pinfo2a.pLocation = "<physical location of printer>";
193 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
194 sprintf(port,"LPR:%s",printers[i]);
195 pinfo2a.pPortName = port;
196 pinfo2a.pParameters = "<parameters?>";
197 pinfo2a.pShareName = "<share name?>";
198 pinfo2a.pSepFile = "<sep file?>";
200 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
201 sprintf(devline,"WINEPS,%s",port);
202 WriteProfileStringA("devices",printers[i],devline);
203 HeapFree(GetProcessHeap(),0,devline);
205 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
206 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
207 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
209 HeapFree(GetProcessHeap(),0,port);
211 wine_dlclose(cupshandle, NULL, 0);
217 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
218 PRINTER_INFO_2A pinfo2a;
219 char *s,*name,*prettyname,*devname;
223 while (isspace(*pent)) pent++;
224 s = strchr(pent,':');
225 if (!s) return FALSE;
231 /* Determine whether this is a postscript printer. */
233 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
234 if (strstr(name,"ps") ||
235 strstr(name,"pd") || /* postscript double page */
236 strstr(name,"postscript") ||
237 strstr(name,"PostScript")
239 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
242 /* 2. Check if this is a remote printer. These usually are postscript
245 if (strstr(pent,":rm")) {
247 TRACE("%s is remote, assuming postscript.\n",name);
249 /* 3. Check if we have an input filter program. If we have one, it
250 * most likely is one capable of converting postscript.
251 * (Could probably check for occurrence of 'gs' or 'ghostscript'
252 * in the if file itself.)
254 if (strstr(pent,":if=/")) {
256 TRACE("%s has inputfilter program, assuming postscript.\n",name);
259 /* If it is not a postscript printer, we cannot use it. */
264 /* Get longest name, usually the one at the right for later display. */
265 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
266 s=strchr(name,'|');if (s) *s='\0';
268 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
269 * if it is too long, we use it as comment below. */
270 devname = prettyname;
271 if (strlen(devname)>=CCHDEVICENAME-1)
273 if (strlen(devname)>=CCHDEVICENAME-1)
276 if (isfirst) /* set first entry as default */
277 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
279 memset(&pinfo2a,0,sizeof(pinfo2a));
280 pinfo2a.pPrinterName = devname;
281 pinfo2a.pDatatype = "RAW";
282 pinfo2a.pPrintProcessor = "WinPrint";
283 pinfo2a.pDriverName = "PS Driver";
284 pinfo2a.pComment = "WINEPS Printer using LPR";
285 pinfo2a.pLocation = prettyname;
286 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
287 sprintf(port,"LPR:%s",name);
288 pinfo2a.pPortName = port;
289 pinfo2a.pParameters = "<parameters?>";
290 pinfo2a.pShareName = "<share name?>";
291 pinfo2a.pSepFile = "<sep file?>";
293 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
294 sprintf(devline,"WINEPS,%s",port);
295 WriteProfileStringA("devices",devname,devline);
296 HeapFree(GetProcessHeap(),0,devline);
298 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
299 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
300 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
302 HeapFree(GetProcessHeap(),0,port);
307 PRINTCAP_LoadPrinters(void) {
308 BOOL hadprinter = FALSE, isfirst = TRUE;
312 f = fopen("/etc/printcap","r");
316 while (fgets(buf,sizeof(buf),f)) {
320 s=strchr(buf,'\n'); if (s) *s='\0';
321 if ((buf[0]=='#') || (buf[0]=='\0'))
325 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
328 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
332 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
333 pent[strlen(pent)-1] = '\0';
336 } while (fgets(buf,sizeof(buf),f));
338 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
340 if (pent) HeapFree(GetProcessHeap(),0,pent);
348 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
350 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
351 lstrlenW(value) * sizeof(WCHAR));
355 WINSPOOL_LoadSystemPrinters() {
358 di3a.cVersion = 0x400;
359 di3a.pName = "PS Driver";
360 di3a.pEnvironment = NULL; /* NULL means auto */
361 di3a.pDriverPath = "wineps16";
362 di3a.pDataFile = "<datafile?>";
363 di3a.pConfigFile = "wineps16";
364 di3a.pHelpFile = "<helpfile?>";
365 di3a.pDependentFiles = "<dependend files?>";
366 di3a.pMonitorName = "<monitor name?>";
367 di3a.pDefaultDataType = "RAW";
369 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
370 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
373 #ifdef HAVE_CUPS_CUPS_H
374 /* If we have any CUPS based printers, skip looking for printcap printers */
375 if (CUPS_LoadPrinters())
379 /* Check for [ppd] section in config file before parsing /etc/printcap */
381 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
382 &hkPPD) == ERROR_SUCCESS)
385 PRINTCAP_LoadPrinters();
390 /******************************************************************
391 * WINSPOOL_GetOpenedPrinterEntry
392 * Get the first place empty in the opened printer table
394 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
398 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
400 if (i >= nb_printers)
402 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
403 (nb_printers + 16) * sizeof(*new_array) );
404 if (!new_array) return 0;
405 printer_array = new_array;
409 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
411 strcpyW( printer_array[i], name );
412 return (HANDLE)(i + 1);
417 /******************************************************************
418 * WINSPOOL_GetOpenedPrinter
419 * Get the pointer to the opened printer referred by the handle
421 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
423 int idx = (int)printerHandle;
424 if ((idx <= 0) || (idx > nb_printers))
426 SetLastError(ERROR_INVALID_HANDLE);
429 return printer_array[idx - 1];
432 /******************************************************************
433 * WINSPOOL_GetOpenedPrinterRegKey
436 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
438 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
442 if(!name) return ERROR_INVALID_HANDLE;
444 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
448 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
450 ERR("Can't find opened printer %s in registry\n",
452 RegCloseKey(hkeyPrinters);
453 return ERROR_INVALID_PRINTER_NAME; /* ? */
455 RegCloseKey(hkeyPrinters);
456 return ERROR_SUCCESS;
459 /***********************************************************
462 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
465 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
468 Formname = (dmA->dmSize > off_formname);
469 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
470 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
473 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
474 dmA->dmSize - CCHDEVICENAME);
476 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
477 off_formname - CCHDEVICENAME);
478 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
480 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
481 (off_formname + CCHFORMNAME));
484 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
489 /***********************************************************
491 * Creates a unicode copy of supplied devmode on heap
493 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
498 ptrdiff_t off_formname;
501 if(!dmA) return NULL;
503 off_formname = (char *)dmA->dmFormName - (char *)dmA;
504 Formname = (dmA->dmSize > off_formname);
505 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
506 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
507 return DEVMODEcpyAtoW(dmW, dmA);
510 /***********************************************************
512 * Creates an ascii copy of supplied devmode on heap
514 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
519 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
521 if(!dmW) return NULL;
522 Formname = (dmW->dmSize > off_formname);
523 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
524 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
525 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
526 CCHDEVICENAME, NULL, NULL);
528 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
529 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
531 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
532 off_formname - CCHDEVICENAME * sizeof(WCHAR));
533 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
534 CCHFORMNAME, NULL, NULL);
535 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
536 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
539 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
544 /***********************************************************
546 * Creates a unicode copy of PRINTER_INFO_2A on heap
548 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
550 LPPRINTER_INFO_2W piW;
551 UNICODE_STRING usBuffer;
553 if(!piA) return NULL;
554 piW = HeapAlloc(heap, 0, sizeof(*piW));
555 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
557 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pServerName);
558 piW->pServerName = usBuffer.Buffer;
559 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pPrinterName);
560 piW->pPrinterName = usBuffer.Buffer;
561 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pShareName);
562 piW->pShareName = usBuffer.Buffer;
563 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pPortName);
564 piW->pPortName = usBuffer.Buffer;
565 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pDriverName);
566 piW->pDriverName = usBuffer.Buffer;
567 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pComment);
568 piW->pComment = usBuffer.Buffer;
569 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pLocation);
570 piW->pLocation = usBuffer.Buffer;
571 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
572 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pSepFile);
573 piW->pSepFile = usBuffer.Buffer;
574 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pPrintProcessor);
575 piW->pPrintProcessor = usBuffer.Buffer;
576 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pDatatype);
577 piW->pDatatype = usBuffer.Buffer;
578 RtlCreateUnicodeStringFromAsciiz(&usBuffer,piA->pParameters);
579 piW->pParameters = usBuffer.Buffer;
583 /***********************************************************
584 * FREE_PRINTER_INFO_2W
585 * Free PRINTER_INFO_2W and all strings
587 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
591 HeapFree(heap,0,piW->pServerName);
592 HeapFree(heap,0,piW->pPrinterName);
593 HeapFree(heap,0,piW->pShareName);
594 HeapFree(heap,0,piW->pPortName);
595 HeapFree(heap,0,piW->pDriverName);
596 HeapFree(heap,0,piW->pComment);
597 HeapFree(heap,0,piW->pLocation);
598 HeapFree(heap,0,piW->pDevMode);
599 HeapFree(heap,0,piW->pSepFile);
600 HeapFree(heap,0,piW->pPrintProcessor);
601 HeapFree(heap,0,piW->pDatatype);
602 HeapFree(heap,0,piW->pParameters);
603 HeapFree(heap,0,piW);
607 /******************************************************************
608 * DeviceCapabilities [WINSPOOL.@]
609 * DeviceCapabilitiesA [WINSPOOL.@]
612 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
613 LPSTR pOutput, LPDEVMODEA lpdm)
617 if (!GDI_CallDeviceCapabilities16)
619 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
621 if (!GDI_CallDeviceCapabilities16) return -1;
623 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
625 /* If DC_PAPERSIZE map POINT16s to POINTs */
626 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
627 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
628 POINT *pt = (POINT *)pOutput;
630 memcpy(tmp, pOutput, ret * sizeof(POINT16));
631 for(i = 0; i < ret; i++, pt++)
636 HeapFree( GetProcessHeap(), 0, tmp );
642 /*****************************************************************************
643 * DeviceCapabilitiesW [WINSPOOL.@]
645 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
648 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
649 WORD fwCapability, LPWSTR pOutput,
650 const DEVMODEW *pDevMode)
652 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
653 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
654 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
657 if(pOutput && (fwCapability == DC_BINNAMES ||
658 fwCapability == DC_FILEDEPENDENCIES ||
659 fwCapability == DC_PAPERNAMES)) {
660 /* These need A -> W translation */
663 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
667 switch(fwCapability) {
672 case DC_FILEDEPENDENCIES:
676 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
677 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
679 for(i = 0; i < ret; i++)
680 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
681 pOutput + (i * size), size);
682 HeapFree(GetProcessHeap(), 0, pOutputA);
684 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
685 (LPSTR)pOutput, dmA);
687 HeapFree(GetProcessHeap(),0,pPortA);
688 HeapFree(GetProcessHeap(),0,pDeviceA);
689 HeapFree(GetProcessHeap(),0,dmA);
693 /******************************************************************
694 * DocumentPropertiesA [WINSPOOL.@]
697 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
698 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
699 LPDEVMODEA pDevModeInput,DWORD fMode )
701 LPSTR lpName = pDeviceName;
704 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
705 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
709 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
711 ERR("no name from hPrinter?\n");
714 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
717 if (!GDI_CallExtDeviceMode16)
719 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
721 if (!GDI_CallExtDeviceMode16) {
722 ERR("No CallExtDeviceMode16?\n");
726 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
727 pDevModeInput, NULL, fMode);
730 HeapFree(GetProcessHeap(),0,lpName);
735 /*****************************************************************************
736 * DocumentPropertiesW (WINSPOOL.@)
738 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
740 LPDEVMODEW pDevModeOutput,
741 LPDEVMODEW pDevModeInput, DWORD fMode)
744 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
745 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
746 LPDEVMODEA pDevModeOutputA = NULL;
749 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
750 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
753 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
754 if(ret < 0) return ret;
755 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
757 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
758 pDevModeInputA, fMode);
760 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
761 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
763 if(fMode == 0 && ret > 0)
764 ret += (CCHDEVICENAME + CCHFORMNAME);
765 HeapFree(GetProcessHeap(),0,pDevModeInputA);
766 HeapFree(GetProcessHeap(),0,pDeviceNameA);
770 /******************************************************************
771 * OpenPrinterA [WINSPOOL.@]
774 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
775 LPPRINTER_DEFAULTSA pDefault)
777 UNICODE_STRING lpPrinterNameW;
778 UNICODE_STRING usBuffer;
779 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
782 RtlCreateUnicodeStringFromAsciiz(&lpPrinterNameW,lpPrinterName);
785 RtlCreateUnicodeStringFromAsciiz(&usBuffer,pDefault->pDatatype);
786 DefaultW.pDatatype = usBuffer.Buffer;
787 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
789 DefaultW.DesiredAccess = pDefault->DesiredAccess;
790 pDefaultW = &DefaultW;
792 ret = OpenPrinterW(lpPrinterNameW.Buffer, phPrinter, pDefaultW);
794 RtlFreeUnicodeString(&usBuffer);
795 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
797 RtlFreeUnicodeString(&lpPrinterNameW);
801 /******************************************************************
802 * OpenPrinterW [WINSPOOL.@]
805 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
806 LPPRINTER_DEFAULTSW pDefault)
808 HKEY hkeyPrinters, hkeyPrinter;
810 if (!lpPrinterName) {
811 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
812 SetLastError(ERROR_INVALID_PARAMETER);
816 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
819 /* Check Printer exists */
820 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
822 ERR("Can't create Printers key\n");
823 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
827 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
828 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
830 TRACE("Can't find printer %s in registry\n",
831 debugstr_w(lpPrinterName));
832 RegCloseKey(hkeyPrinters);
833 SetLastError(ERROR_INVALID_PRINTER_NAME);
836 RegCloseKey(hkeyPrinter);
837 RegCloseKey(hkeyPrinters);
839 if(!phPrinter) /* This seems to be what win95 does anyway */
842 /* Get the unique handle of the printer*/
843 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
845 if (pDefault != NULL)
846 FIXME("Not handling pDefault\n");
851 /******************************************************************
852 * AddMonitorA [WINSPOOL.@]
855 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
857 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
858 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
862 /******************************************************************
863 * DeletePrinterDriverA [WINSPOOL.@]
867 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
869 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
870 debugstr_a(pDriverName));
871 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
876 /******************************************************************
877 * DeleteMonitorA [WINSPOOL.@]
881 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
883 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
884 debugstr_a(pMonitorName));
885 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
890 /******************************************************************
891 * DeletePortA [WINSPOOL.@]
895 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
897 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
898 debugstr_a(pPortName));
899 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
903 /******************************************************************************
904 * SetPrinterW [WINSPOOL.@]
914 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
918 /******************************************************************************
919 * WritePrinter [WINSPOOL.@]
929 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
933 /*****************************************************************************
934 * AddFormA [WINSPOOL.@]
936 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
938 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
942 /*****************************************************************************
943 * AddFormW [WINSPOOL.@]
945 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
947 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
951 /*****************************************************************************
952 * AddJobA [WINSPOOL.@]
954 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
955 DWORD cbBuf, LPDWORD pcbNeeded)
957 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
962 /*****************************************************************************
963 * AddJobW [WINSPOOL.@]
965 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
968 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
973 /*****************************************************************************
974 * WINSPOOL_OpenDriverReg [internal]
976 * opens the registry for the printer drivers depending on the given input
977 * variable pEnvironment
980 * the opened hkey on success
983 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
985 LPSTR lpKey, p = NULL;
988 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
991 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
995 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
997 if(!GetVersionExA( &ver))
1000 switch (ver.dwPlatformId) {
1001 case VER_PLATFORM_WIN32s:
1002 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1005 case VER_PLATFORM_WIN32_NT:
1006 p = "Windows NT x86";
1012 TRACE("set environment to %s\n", p);
1015 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1016 strlen(p) + strlen(Drivers));
1017 sprintf( lpKey, Drivers, p);
1019 TRACE("%s\n", lpKey);
1021 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1025 if(pEnvironment && unicode)
1026 HeapFree( GetProcessHeap(), 0, p);
1027 HeapFree( GetProcessHeap(), 0, lpKey);
1032 /*****************************************************************************
1033 * AddPrinterW [WINSPOOL.@]
1035 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1037 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1041 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1044 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1047 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1048 SetLastError(ERROR_INVALID_PARAMETER);
1052 ERR("Level = %ld, unsupported!\n", Level);
1053 SetLastError(ERROR_INVALID_LEVEL);
1056 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1057 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1058 debugstr_w(pi->pPrinterName)
1060 SetLastError(ERROR_INVALID_LEVEL);
1064 SetLastError(ERROR_INVALID_PARAMETER);
1067 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1069 ERR("Can't create Printers key\n");
1072 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1073 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1074 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1075 RegCloseKey(hkeyPrinter);
1076 RegCloseKey(hkeyPrinters);
1079 RegCloseKey(hkeyPrinter);
1081 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1083 ERR("Can't create Drivers key\n");
1084 RegCloseKey(hkeyPrinters);
1087 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1089 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1090 RegCloseKey(hkeyPrinters);
1091 RegCloseKey(hkeyDrivers);
1092 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1095 RegCloseKey(hkeyDriver);
1096 RegCloseKey(hkeyDrivers);
1098 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1099 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1100 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1101 RegCloseKey(hkeyPrinters);
1105 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1107 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1108 SetLastError(ERROR_INVALID_PRINTER_NAME);
1109 RegCloseKey(hkeyPrinters);
1112 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1113 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1114 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1116 /* See if we can load the driver. We may need the devmode structure anyway
1119 * Note that DocumentPropertiesW will briefly try to open the printer we
1120 * just create to find a DEVMODEA struct (it will use the WINEPS default
1121 * one in case it is not there, so we are ok).
1123 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1125 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1126 size = sizeof(DEVMODEW);
1131 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1133 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1134 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1135 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1138 /* set devmode to printer name */
1139 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1142 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1143 and we support these drivers. NT writes DEVMODEW so somehow
1144 we'll need to distinguish between these when we support NT
1146 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1147 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1148 dmA->dmSize + dmA->dmDriverExtra);
1149 HeapFree(GetProcessHeap(), 0, dmA);
1151 HeapFree(GetProcessHeap(), 0, dmW);
1152 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1153 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1154 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1155 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1157 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1158 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1159 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1160 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1161 (LPBYTE)&pi->Priority, sizeof(DWORD));
1162 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1163 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1164 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1165 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1166 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1167 (LPBYTE)&pi->Status, sizeof(DWORD));
1168 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1169 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1171 RegCloseKey(hkeyPrinter);
1172 RegCloseKey(hkeyPrinters);
1173 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1174 ERR("OpenPrinter failing\n");
1180 /*****************************************************************************
1181 * AddPrinterA [WINSPOOL.@]
1183 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1185 UNICODE_STRING pNameW;
1186 PRINTER_INFO_2W *piW;
1187 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1190 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1192 ERR("Level = %ld, unsupported!\n", Level);
1193 SetLastError(ERROR_INVALID_LEVEL);
1196 RtlCreateUnicodeStringFromAsciiz(&pNameW,pName);
1197 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1199 ret = AddPrinterW(pNameW.Buffer, Level, (LPBYTE)piW);
1201 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1202 RtlFreeUnicodeString(&pNameW);
1207 /*****************************************************************************
1208 * ClosePrinter [WINSPOOL.@]
1210 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1212 int i = (int)hPrinter;
1214 TRACE("Handle %p\n", hPrinter);
1216 if ((i <= 0) || (i > nb_printers)) return FALSE;
1217 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1218 printer_array[i - 1] = NULL;
1222 /*****************************************************************************
1223 * DeleteFormA [WINSPOOL.@]
1225 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1227 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1231 /*****************************************************************************
1232 * DeleteFormW [WINSPOOL.@]
1234 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1236 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1240 /*****************************************************************************
1241 * DeletePrinter [WINSPOOL.@]
1243 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1245 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1248 if(!lpNameW) return FALSE;
1249 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1251 ERR("Can't open Printers key\n");
1255 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1256 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1257 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1258 RegCloseKey(hkeyPrinters);
1262 ClosePrinter(hPrinter);
1266 /*****************************************************************************
1267 * SetPrinterA [WINSPOOL.@]
1269 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1272 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1276 /*****************************************************************************
1277 * SetJobA [WINSPOOL.@]
1279 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1280 LPBYTE pJob, DWORD Command)
1282 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1287 /*****************************************************************************
1288 * SetJobW [WINSPOOL.@]
1290 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1291 LPBYTE pJob, DWORD Command)
1293 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1298 /*****************************************************************************
1299 * EndDocPrinter [WINSPOOL.@]
1301 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1303 FIXME("(hPrinter=%p): stub\n", hPrinter);
1307 /*****************************************************************************
1308 * EndPagePrinter [WINSPOOL.@]
1310 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1312 FIXME("(hPrinter=%p): stub\n", hPrinter);
1316 /*****************************************************************************
1317 * StartDocPrinterA [WINSPOOL.@]
1319 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1321 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1325 /*****************************************************************************
1326 * StartDocPrinterW [WINSPOOL.@]
1328 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1330 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1334 /*****************************************************************************
1335 * StartPagePrinter [WINSPOOL.@]
1337 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1339 FIXME("(hPrinter=%p): stub\n", hPrinter);
1343 /*****************************************************************************
1344 * GetFormA [WINSPOOL.@]
1346 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1347 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1349 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1350 Level,pForm,cbBuf,pcbNeeded);
1354 /*****************************************************************************
1355 * GetFormW [WINSPOOL.@]
1357 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1358 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1360 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1361 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1365 /*****************************************************************************
1366 * SetFormA [WINSPOOL.@]
1368 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1371 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1375 /*****************************************************************************
1376 * SetFormW [WINSPOOL.@]
1378 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1381 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1385 /*****************************************************************************
1386 * ReadPrinter [WINSPOOL.@]
1388 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1389 LPDWORD pNoBytesRead)
1391 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1395 /*****************************************************************************
1396 * ResetPrinterA [WINSPOOL.@]
1398 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1400 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1404 /*****************************************************************************
1405 * ResetPrinterW [WINSPOOL.@]
1407 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1409 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1413 /*****************************************************************************
1414 * WINSPOOL_GetDWORDFromReg
1416 * Return DWORD associated with ValueName from hkey.
1418 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1420 DWORD sz = sizeof(DWORD), type, value = 0;
1423 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1425 if(ret != ERROR_SUCCESS) {
1426 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1429 if(type != REG_DWORD) {
1430 ERR("Got type %ld\n", type);
1436 /*****************************************************************************
1437 * WINSPOOL_GetStringFromReg
1439 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1440 * String is stored either as unicode or ascii.
1441 * Bit of a hack here to get the ValueName if we want ascii.
1443 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1444 DWORD buflen, DWORD *needed,
1447 DWORD sz = buflen, type;
1451 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1453 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1454 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1455 HeapFree(GetProcessHeap(),0,ValueNameA);
1457 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1458 WARN("Got ret = %ld\n", ret);
1466 /*****************************************************************************
1467 * WINSPOOL_GetDefaultDevMode
1469 * Get a default DevMode values for wineps.
1473 static void WINSPOOL_GetDefaultDevMode(
1475 DWORD buflen, DWORD *needed,
1480 /* fill default DEVMODE - should be read from ppd... */
1481 ZeroMemory( &dm, sizeof(dm) );
1482 strcpy(dm.dmDeviceName,"wineps");
1483 dm.dmSpecVersion = DM_SPECVERSION;
1484 dm.dmDriverVersion = 1;
1485 dm.dmSize = sizeof(DEVMODEA);
1486 dm.dmDriverExtra = 0;
1488 DM_ORIENTATION | DM_PAPERSIZE |
1489 DM_PAPERLENGTH | DM_PAPERWIDTH |
1492 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1493 DM_YRESOLUTION | DM_TTOPTION;
1495 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1496 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1497 dm.u1.s1.dmPaperLength = 2970;
1498 dm.u1.s1.dmPaperWidth = 2100;
1502 dm.dmDefaultSource = DMBIN_AUTO;
1503 dm.dmPrintQuality = DMRES_MEDIUM;
1506 dm.dmYResolution = 300; /* 300dpi */
1507 dm.dmTTOption = DMTT_BITMAP;
1510 /* dm.dmLogPixels */
1511 /* dm.dmBitsPerPel */
1512 /* dm.dmPelsWidth */
1513 /* dm.dmPelsHeight */
1514 /* dm.dmDisplayFlags */
1515 /* dm.dmDisplayFrequency */
1516 /* dm.dmICMMethod */
1517 /* dm.dmICMIntent */
1518 /* dm.dmMediaType */
1519 /* dm.dmDitherType */
1520 /* dm.dmReserved1 */
1521 /* dm.dmReserved2 */
1522 /* dm.dmPanningWidth */
1523 /* dm.dmPanningHeight */
1526 if(buflen >= sizeof(DEVMODEW)) {
1527 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1528 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1529 HeapFree(GetProcessHeap(),0,pdmW);
1531 *needed = sizeof(DEVMODEW);
1535 if(buflen >= sizeof(DEVMODEA)) {
1536 memcpy(ptr, &dm, sizeof(DEVMODEA));
1538 *needed = sizeof(DEVMODEA);
1542 /*****************************************************************************
1543 * WINSPOOL_GetDevModeFromReg
1545 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1546 * DevMode is stored either as unicode or ascii.
1548 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1550 DWORD buflen, DWORD *needed,
1553 DWORD sz = buflen, type;
1556 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1557 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1558 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1559 if (sz < sizeof(DEVMODEA))
1561 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1564 /* ensures that dmSize is not erratically bogus if registry is invalid */
1565 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1566 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1568 sz += (CCHDEVICENAME + CCHFORMNAME);
1570 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1571 memcpy(ptr, dmW, sz);
1572 HeapFree(GetProcessHeap(),0,dmW);
1579 /*********************************************************************
1580 * WINSPOOL_GetPrinter_2
1582 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1583 * The strings are either stored as unicode or ascii.
1585 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1586 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1589 DWORD size, left = cbBuf;
1590 BOOL space = (cbBuf > 0);
1595 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1597 if(space && size <= left) {
1598 pi2->pPrinterName = (LPWSTR)ptr;
1605 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1607 if(space && size <= left) {
1608 pi2->pShareName = (LPWSTR)ptr;
1615 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1617 if(space && size <= left) {
1618 pi2->pPortName = (LPWSTR)ptr;
1625 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1627 if(space && size <= left) {
1628 pi2->pDriverName = (LPWSTR)ptr;
1635 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1637 if(space && size <= left) {
1638 pi2->pComment = (LPWSTR)ptr;
1645 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1647 if(space && size <= left) {
1648 pi2->pLocation = (LPWSTR)ptr;
1655 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1657 if(space && size <= left) {
1658 pi2->pDevMode = (LPDEVMODEW)ptr;
1667 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1668 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1669 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1670 if(space && size <= left) {
1671 pi2->pDevMode = (LPDEVMODEW)ptr;
1678 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1680 if(space && size <= left) {
1681 pi2->pSepFile = (LPWSTR)ptr;
1688 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1690 if(space && size <= left) {
1691 pi2->pPrintProcessor = (LPWSTR)ptr;
1698 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1700 if(space && size <= left) {
1701 pi2->pDatatype = (LPWSTR)ptr;
1708 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1710 if(space && size <= left) {
1711 pi2->pParameters = (LPWSTR)ptr;
1719 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1720 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1721 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1722 "Default Priority");
1723 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1724 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1727 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1728 memset(pi2, 0, sizeof(*pi2));
1733 /*********************************************************************
1734 * WINSPOOL_GetPrinter_4
1736 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1738 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1739 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1742 DWORD size, left = cbBuf;
1743 BOOL space = (cbBuf > 0);
1748 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1750 if(space && size <= left) {
1751 pi4->pPrinterName = (LPWSTR)ptr;
1759 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1762 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1763 memset(pi4, 0, sizeof(*pi4));
1768 /*********************************************************************
1769 * WINSPOOL_GetPrinter_5
1771 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1773 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1774 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1777 DWORD size, left = cbBuf;
1778 BOOL space = (cbBuf > 0);
1783 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1785 if(space && size <= left) {
1786 pi5->pPrinterName = (LPWSTR)ptr;
1793 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1795 if(space && size <= left) {
1796 pi5->pPortName = (LPWSTR)ptr;
1804 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1805 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1807 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1811 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1812 memset(pi5, 0, sizeof(*pi5));
1817 /*****************************************************************************
1818 * WINSPOOL_GetPrinter
1820 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1821 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1822 * just a collection of pointers to strings.
1824 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1825 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1828 DWORD size, needed = 0;
1830 HKEY hkeyPrinter, hkeyPrinters;
1833 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1835 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1837 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1839 ERR("Can't create Printers key\n");
1842 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1844 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1845 RegCloseKey(hkeyPrinters);
1846 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1853 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1855 size = sizeof(PRINTER_INFO_2W);
1857 ptr = pPrinter + size;
1859 memset(pPrinter, 0, size);
1864 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1872 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1874 size = sizeof(PRINTER_INFO_4W);
1876 ptr = pPrinter + size;
1878 memset(pPrinter, 0, size);
1883 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1892 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1894 size = sizeof(PRINTER_INFO_5W);
1896 ptr = pPrinter + size;
1898 memset(pPrinter, 0, size);
1904 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1911 FIXME("Unimplemented level %ld\n", Level);
1912 SetLastError(ERROR_INVALID_LEVEL);
1913 RegCloseKey(hkeyPrinters);
1914 RegCloseKey(hkeyPrinter);
1918 RegCloseKey(hkeyPrinter);
1919 RegCloseKey(hkeyPrinters);
1921 TRACE("returning %d needed = %ld\n", ret, needed);
1922 if(pcbNeeded) *pcbNeeded = needed;
1924 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1928 /*****************************************************************************
1929 * GetPrinterW [WINSPOOL.@]
1931 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1932 DWORD cbBuf, LPDWORD pcbNeeded)
1934 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1938 /*****************************************************************************
1939 * GetPrinterA [WINSPOOL.@]
1941 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1942 DWORD cbBuf, LPDWORD pcbNeeded)
1944 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1948 /*****************************************************************************
1949 * WINSPOOL_EnumPrinters
1951 * Implementation of EnumPrintersA|W
1953 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1954 DWORD dwLevel, LPBYTE lpbPrinters,
1955 DWORD cbBuf, LPDWORD lpdwNeeded,
1956 LPDWORD lpdwReturned, BOOL unicode)
1959 HKEY hkeyPrinters, hkeyPrinter;
1960 WCHAR PrinterName[255];
1961 DWORD needed = 0, number = 0;
1962 DWORD used, i, left;
1966 memset(lpbPrinters, 0, cbBuf);
1972 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1973 if(dwType == PRINTER_ENUM_DEFAULT)
1976 if (dwType & PRINTER_ENUM_CONNECTIONS) {
1977 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
1978 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
1979 dwType |= PRINTER_ENUM_LOCAL;
1982 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1983 FIXME("dwType = %08lx\n", dwType);
1984 SetLastError(ERROR_INVALID_FLAGS);
1988 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1990 ERR("Can't create Printers key\n");
1994 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1995 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1996 RegCloseKey(hkeyPrinters);
1997 ERR("Can't query Printers key\n");
2000 TRACE("Found %ld printers\n", number);
2004 RegCloseKey(hkeyPrinters);
2006 *lpdwReturned = number;
2010 used = number * sizeof(PRINTER_INFO_2W);
2013 used = number * sizeof(PRINTER_INFO_4W);
2016 used = number * sizeof(PRINTER_INFO_5W);
2020 SetLastError(ERROR_INVALID_LEVEL);
2021 RegCloseKey(hkeyPrinters);
2024 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2026 for(i = 0; i < number; i++) {
2027 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2029 ERR("Can't enum key number %ld\n", i);
2030 RegCloseKey(hkeyPrinters);
2033 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2034 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2036 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2037 RegCloseKey(hkeyPrinters);
2042 buf = lpbPrinters + used;
2043 left = cbBuf - used;
2051 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2052 left, &needed, unicode);
2054 if(pi) pi += sizeof(PRINTER_INFO_2W);
2057 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2058 left, &needed, unicode);
2060 if(pi) pi += sizeof(PRINTER_INFO_4W);
2063 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2064 left, &needed, unicode);
2066 if(pi) pi += sizeof(PRINTER_INFO_5W);
2069 ERR("Shouldn't be here!\n");
2070 RegCloseKey(hkeyPrinter);
2071 RegCloseKey(hkeyPrinters);
2074 RegCloseKey(hkeyPrinter);
2076 RegCloseKey(hkeyPrinters);
2083 memset(lpbPrinters, 0, cbBuf);
2084 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2088 *lpdwReturned = number;
2089 SetLastError(ERROR_SUCCESS);
2094 /******************************************************************
2095 * EnumPrintersW [WINSPOOL.@]
2097 * Enumerates the available printers, print servers and print
2098 * providers, depending on the specified flags, name and level.
2102 * If level is set to 1:
2103 * Not implemented yet!
2104 * Returns TRUE with an empty list.
2106 * If level is set to 2:
2107 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2108 * Returns an array of PRINTER_INFO_2 data structures in the
2109 * lpbPrinters buffer. Note that according to MSDN also an
2110 * OpenPrinter should be performed on every remote printer.
2112 * If level is set to 4 (officially WinNT only):
2113 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2114 * Fast: Only the registry is queried to retrieve printer names,
2115 * no connection to the driver is made.
2116 * Returns an array of PRINTER_INFO_4 data structures in the
2117 * lpbPrinters buffer.
2119 * If level is set to 5 (officially WinNT4/Win9x only):
2120 * Fast: Only the registry is queried to retrieve printer names,
2121 * no connection to the driver is made.
2122 * Returns an array of PRINTER_INFO_5 data structures in the
2123 * lpbPrinters buffer.
2125 * If level set to 3 or 6+:
2126 * returns zero (failure!)
2128 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2132 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2133 * - Only levels 2, 4 and 5 are implemented at the moment.
2134 * - 16-bit printer drivers are not enumerated.
2135 * - Returned amount of bytes used/needed does not match the real Windoze
2136 * implementation (as in this implementation, all strings are part
2137 * of the buffer, whereas Win32 keeps them somewhere else)
2138 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2141 * - In a regular Wine installation, no registry settings for printers
2142 * exist, which makes this function return an empty list.
2144 BOOL WINAPI EnumPrintersW(
2145 DWORD dwType, /* [in] Types of print objects to enumerate */
2146 LPWSTR lpszName, /* [in] name of objects to enumerate */
2147 DWORD dwLevel, /* [in] type of printer info structure */
2148 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2149 DWORD cbBuf, /* [in] max size of buffer in bytes */
2150 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2151 LPDWORD lpdwReturned /* [out] number of entries returned */
2154 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2155 lpdwNeeded, lpdwReturned, TRUE);
2158 /******************************************************************
2159 * EnumPrintersA [WINSPOOL.@]
2162 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2163 DWORD dwLevel, LPBYTE lpbPrinters,
2164 DWORD cbBuf, LPDWORD lpdwNeeded,
2165 LPDWORD lpdwReturned)
2168 UNICODE_STRING lpszNameW;
2169 RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
2170 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW.Buffer, dwLevel, lpbPrinters, cbBuf,
2171 lpdwNeeded, lpdwReturned, FALSE);
2172 RtlFreeUnicodeString(&lpszNameW);
2176 /*****************************************************************************
2177 * WINSPOOL_GetDriverInfoFromReg [internal]
2179 * Enters the information from the registry into the DRIVER_INFO struct
2182 * zero if the printer driver does not exist in the registry
2183 * (only if Level > 1) otherwise nonzero
2185 static BOOL WINSPOOL_GetDriverInfoFromReg(
2188 LPWSTR pEnvironment,
2190 LPBYTE ptr, /* DRIVER_INFO */
2191 LPBYTE pDriverStrings, /* strings buffer */
2192 DWORD cbBuf, /* size of string buffer */
2193 LPDWORD pcbNeeded, /* space needed for str. */
2194 BOOL unicode) /* type of strings */
2195 { DWORD dw, size, tmp, type;
2197 LPBYTE strPtr = pDriverStrings;
2199 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2200 debugstr_w(DriverName), debugstr_w(pEnvironment),
2201 Level, ptr, pDriverStrings, cbBuf, unicode);
2204 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2205 if (*pcbNeeded <= cbBuf)
2206 strcpyW((LPWSTR)strPtr, DriverName);
2208 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2210 if(*pcbNeeded <= cbBuf)
2211 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2216 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2220 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2221 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2224 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2225 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2226 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2231 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2233 WARN("Can't get Version\n");
2235 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2238 pEnvironment = DefaultEnvironmentW;
2240 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2242 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2245 if(*pcbNeeded <= cbBuf) {
2247 strcpyW((LPWSTR)strPtr, pEnvironment);
2249 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2252 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2253 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2256 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2259 if(*pcbNeeded <= cbBuf)
2260 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2263 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2264 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2267 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2270 if(*pcbNeeded <= cbBuf)
2271 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2274 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2275 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2278 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2279 0, &size, unicode)) {
2281 if(*pcbNeeded <= cbBuf)
2282 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2283 size, &tmp, unicode);
2285 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2286 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2290 RegCloseKey(hkeyDriver);
2291 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2295 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2298 if(*pcbNeeded <= cbBuf)
2299 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2300 size, &tmp, unicode);
2302 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2303 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2306 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2309 if(*pcbNeeded <= cbBuf)
2310 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2311 size, &tmp, unicode);
2313 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2314 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2317 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2320 if(*pcbNeeded <= cbBuf)
2321 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2322 size, &tmp, unicode);
2324 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2325 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2328 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2331 if(*pcbNeeded <= cbBuf)
2332 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2333 size, &tmp, unicode);
2335 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2336 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2339 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2340 RegCloseKey(hkeyDriver);
2344 /*****************************************************************************
2345 * WINSPOOL_GetPrinterDriver
2347 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2348 DWORD Level, LPBYTE pDriverInfo,
2349 DWORD cbBuf, LPDWORD pcbNeeded,
2353 WCHAR DriverName[100];
2354 DWORD ret, type, size, needed = 0;
2356 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2358 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2359 Level,pDriverInfo,cbBuf, pcbNeeded);
2361 ZeroMemory(pDriverInfo, cbBuf);
2363 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2365 if(Level < 1 || Level > 3) {
2366 SetLastError(ERROR_INVALID_LEVEL);
2369 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2371 ERR("Can't create Printers key\n");
2374 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2376 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2377 RegCloseKey(hkeyPrinters);
2378 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2381 size = sizeof(DriverName);
2383 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2384 (LPBYTE)DriverName, &size);
2385 RegCloseKey(hkeyPrinter);
2386 RegCloseKey(hkeyPrinters);
2387 if(ret != ERROR_SUCCESS) {
2388 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2392 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2394 ERR("Can't create Drivers key\n");
2400 size = sizeof(DRIVER_INFO_1W);
2403 size = sizeof(DRIVER_INFO_2W);
2406 size = sizeof(DRIVER_INFO_3W);
2409 ERR("Invalid level\n");
2414 ptr = pDriverInfo + size;
2416 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2417 pEnvironment, Level, pDriverInfo,
2418 (cbBuf < size) ? NULL : ptr,
2419 (cbBuf < size) ? 0 : cbBuf - size,
2420 &needed, unicode)) {
2421 RegCloseKey(hkeyDrivers);
2425 RegCloseKey(hkeyDrivers);
2427 if(pcbNeeded) *pcbNeeded = size + needed;
2428 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2429 if(cbBuf >= needed) return TRUE;
2430 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2434 /*****************************************************************************
2435 * GetPrinterDriverA [WINSPOOL.@]
2437 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2438 DWORD Level, LPBYTE pDriverInfo,
2439 DWORD cbBuf, LPDWORD pcbNeeded)
2442 UNICODE_STRING pEnvW;
2443 RtlCreateUnicodeStringFromAsciiz(&pEnvW, pEnvironment);
2444 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW.Buffer, Level, pDriverInfo,
2445 cbBuf, pcbNeeded, FALSE);
2446 RtlFreeUnicodeString(&pEnvW);
2449 /*****************************************************************************
2450 * GetPrinterDriverW [WINSPOOL.@]
2452 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2453 DWORD Level, LPBYTE pDriverInfo,
2454 DWORD cbBuf, LPDWORD pcbNeeded)
2456 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2457 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2460 /*****************************************************************************
2461 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2463 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2464 DWORD Level, LPBYTE pDriverDirectory,
2465 DWORD cbBuf, LPDWORD pcbNeeded)
2469 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2470 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2472 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2473 SetLastError(ERROR_INVALID_PARAMETER);
2476 if(pEnvironment != NULL) {
2477 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2478 SetLastError(ERROR_INVALID_ENVIRONMENT);
2481 if(Level != 1) /* win95 ignores this so we just carry on */
2482 WARN("Level = %ld - assuming 1\n", Level);
2484 /* FIXME should read from registry */
2485 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2486 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2490 needed*=sizeof(WCHAR);
2493 *pcbNeeded = needed;
2494 TRACE("required <%08lx>\n", *pcbNeeded);
2495 if(needed > cbBuf) {
2496 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2503 /*****************************************************************************
2504 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2506 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2507 DWORD Level, LPBYTE pDriverDirectory,
2508 DWORD cbBuf, LPDWORD pcbNeeded)
2510 UNICODE_STRING nameW, environmentW;
2513 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2514 WCHAR *driverDirectoryW = NULL;
2516 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2518 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2519 else nameW.Buffer = NULL;
2520 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2521 else environmentW.Buffer = NULL;
2523 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2524 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2527 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2528 pDriverDirectory, cbBuf, NULL, NULL);
2530 *pcbNeeded = needed;
2531 ret = (needed <= cbBuf) ? TRUE : FALSE;
2533 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2535 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2537 if(driverDirectoryW)
2538 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2539 RtlFreeUnicodeString(&environmentW);
2540 RtlFreeUnicodeString(&nameW);
2545 /*****************************************************************************
2546 * AddPrinterDriverA [WINSPOOL.@]
2548 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2551 HKEY hkeyDrivers, hkeyName;
2553 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2555 if(level != 2 && level != 3) {
2556 SetLastError(ERROR_INVALID_LEVEL);
2560 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2561 SetLastError(ERROR_INVALID_PARAMETER);
2565 WARN("pDriverInfo == NULL\n");
2566 SetLastError(ERROR_INVALID_PARAMETER);
2571 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2573 memset(&di3, 0, sizeof(di3));
2574 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2577 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2579 SetLastError(ERROR_INVALID_PARAMETER);
2582 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2583 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2584 if(!di3.pHelpFile) di3.pHelpFile = "";
2585 if(!di3.pMonitorName) di3.pMonitorName = "";
2587 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2590 ERR("Can't create Drivers key\n");
2594 if(level == 2) { /* apparently can't overwrite with level2 */
2595 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2596 RegCloseKey(hkeyName);
2597 RegCloseKey(hkeyDrivers);
2598 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2599 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2603 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2604 RegCloseKey(hkeyDrivers);
2605 ERR("Can't create Name key\n");
2608 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2610 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2611 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2612 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2614 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2615 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2616 di3.pDependentFiles, 0);
2617 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2618 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2619 RegCloseKey(hkeyName);
2620 RegCloseKey(hkeyDrivers);
2624 /*****************************************************************************
2625 * AddPrinterDriverW [WINSPOOL.@]
2627 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2630 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2636 /*****************************************************************************
2637 * PrinterProperties [WINSPOOL.@]
2639 * Displays a dialog to set the properties of the printer.
2642 * nonzero on success or zero on failure
2645 * implemented as stub only
2647 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2648 HANDLE hPrinter /* [in] handle to printer object */
2650 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2651 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2655 /*****************************************************************************
2656 * EnumJobsA [WINSPOOL.@]
2659 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2660 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2663 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2664 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2666 if(pcbNeeded) *pcbNeeded = 0;
2667 if(pcReturned) *pcReturned = 0;
2672 /*****************************************************************************
2673 * EnumJobsW [WINSPOOL.@]
2676 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2677 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2680 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2681 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2683 if(pcbNeeded) *pcbNeeded = 0;
2684 if(pcReturned) *pcReturned = 0;
2688 /*****************************************************************************
2689 * WINSPOOL_EnumPrinterDrivers [internal]
2691 * Delivers information about all printer drivers installed on the
2692 * localhost or a given server
2695 * nonzero on success or zero on failure. If the buffer for the returned
2696 * information is too small the function will return an error
2699 * - only implemented for localhost, foreign hosts will return an error
2701 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2702 DWORD Level, LPBYTE pDriverInfo,
2703 DWORD cbBuf, LPDWORD pcbNeeded,
2704 LPDWORD pcReturned, BOOL unicode)
2707 DWORD i, needed, number = 0, size = 0;
2708 WCHAR DriverNameW[255];
2711 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2712 debugstr_w(pName), debugstr_w(pEnvironment),
2713 Level, pDriverInfo, cbBuf, unicode);
2715 /* check for local drivers */
2717 ERR("remote drivers unsupported! Current remote host is %s\n",
2722 /* check input parameter */
2723 if((Level < 1) || (Level > 3)) {
2724 ERR("unsupported level %ld \n", Level);
2728 /* initialize return values */
2730 memset( pDriverInfo, 0, cbBuf);
2734 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2736 ERR("Can't open Drivers key\n");
2740 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2741 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2742 RegCloseKey(hkeyDrivers);
2743 ERR("Can't query Drivers key\n");
2746 TRACE("Found %ld Drivers\n", number);
2748 /* get size of single struct
2749 * unicode and ascii structure have the same size
2753 size = sizeof(DRIVER_INFO_1A);
2756 size = sizeof(DRIVER_INFO_2A);
2759 size = sizeof(DRIVER_INFO_3A);
2763 /* calculate required buffer size */
2764 *pcbNeeded = size * number;
2766 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2768 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2769 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2771 ERR("Can't enum key number %ld\n", i);
2772 RegCloseKey(hkeyDrivers);
2775 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2776 pEnvironment, Level, ptr,
2777 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2778 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2779 &needed, unicode)) {
2780 RegCloseKey(hkeyDrivers);
2783 (*pcbNeeded) += needed;
2786 RegCloseKey(hkeyDrivers);
2788 if(cbBuf < *pcbNeeded){
2789 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2796 /*****************************************************************************
2797 * EnumPrinterDriversW [WINSPOOL.@]
2799 * see function EnumPrinterDrivers for RETURNS, BUGS
2801 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2802 LPBYTE pDriverInfo, DWORD cbBuf,
2803 LPDWORD pcbNeeded, LPDWORD pcReturned)
2805 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2806 cbBuf, pcbNeeded, pcReturned, TRUE);
2809 /*****************************************************************************
2810 * EnumPrinterDriversA [WINSPOOL.@]
2812 * see function EnumPrinterDrivers for RETURNS, BUGS
2814 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2815 LPBYTE pDriverInfo, DWORD cbBuf,
2816 LPDWORD pcbNeeded, LPDWORD pcReturned)
2818 UNICODE_STRING pNameW, pEnvironmentW;
2821 RtlCreateUnicodeStringFromAsciiz(&pNameW, pName);
2823 RtlCreateUnicodeStringFromAsciiz(&pEnvironmentW, pEnvironment);
2825 ret = WINSPOOL_EnumPrinterDrivers(pNameW.Buffer, pEnvironmentW.Buffer,
2826 Level, pDriverInfo, cbBuf, pcbNeeded,
2829 RtlFreeUnicodeString(&pNameW);
2831 RtlFreeUnicodeString(&pEnvironmentW);
2837 /******************************************************************************
2838 * EnumPortsA (WINSPOOL.@)
2840 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2841 LPDWORD bufneeded,LPDWORD bufreturned)
2843 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2847 /******************************************************************************
2848 * GetDefaultPrinterA (WINSPOOL.@)
2850 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2852 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2858 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2862 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2864 SetLastError (ERROR_FILE_NOT_FOUND);
2868 if ((ptr = strchr (name, ',')) == NULL)
2870 SetLastError (ERROR_FILE_NOT_FOUND);
2875 *namesize = strlen (name) + 1;
2880 /******************************************************************************
2881 * GetDefaultPrinterW (WINSPOOL.@)
2883 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2890 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2894 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2895 ret = GetDefaultPrinterA (buf, namesize);
2898 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2901 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2904 else *namesize = len;
2907 HeapFree (GetProcessHeap (), 0, buf);
2912 /******************************************************************************
2913 * SetPrinterDataExA (WINSPOOL.@)
2915 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2916 LPSTR pValueName, DWORD Type,
2917 LPBYTE pData, DWORD cbData)
2919 HKEY hkeyPrinter, hkeySubkey;
2922 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2923 debugstr_a(pValueName), Type, pData, cbData);
2925 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2929 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2931 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2932 RegCloseKey(hkeyPrinter);
2935 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2936 RegCloseKey(hkeySubkey);
2937 RegCloseKey(hkeyPrinter);
2941 /******************************************************************************
2942 * SetPrinterDataExW (WINSPOOL.@)
2944 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2945 LPWSTR pValueName, DWORD Type,
2946 LPBYTE pData, DWORD cbData)
2948 HKEY hkeyPrinter, hkeySubkey;
2951 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2952 debugstr_w(pValueName), Type, pData, cbData);
2954 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2958 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2960 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2961 RegCloseKey(hkeyPrinter);
2964 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2965 RegCloseKey(hkeySubkey);
2966 RegCloseKey(hkeyPrinter);
2970 /******************************************************************************
2971 * SetPrinterDataA (WINSPOOL.@)
2973 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2974 LPBYTE pData, DWORD cbData)
2976 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2980 /******************************************************************************
2981 * SetPrinterDataW (WINSPOOL.@)
2983 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2984 LPBYTE pData, DWORD cbData)
2986 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2990 /******************************************************************************
2991 * GetPrinterDataExA (WINSPOOL.@)
2993 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2994 LPSTR pValueName, LPDWORD pType,
2995 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2997 HKEY hkeyPrinter, hkeySubkey;
3000 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3001 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3004 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3008 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3010 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3011 RegCloseKey(hkeyPrinter);
3015 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3016 RegCloseKey(hkeySubkey);
3017 RegCloseKey(hkeyPrinter);
3021 /******************************************************************************
3022 * GetPrinterDataExW (WINSPOOL.@)
3024 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3025 LPWSTR pValueName, LPDWORD pType,
3026 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3028 HKEY hkeyPrinter, hkeySubkey;
3031 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3032 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3035 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3039 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3041 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3042 RegCloseKey(hkeyPrinter);
3046 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3047 RegCloseKey(hkeySubkey);
3048 RegCloseKey(hkeyPrinter);
3052 /******************************************************************************
3053 * GetPrinterDataA (WINSPOOL.@)
3055 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3056 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3058 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3059 pData, nSize, pcbNeeded);
3062 /******************************************************************************
3063 * GetPrinterDataW (WINSPOOL.@)
3065 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3066 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3068 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3069 pData, nSize, pcbNeeded);
3072 /*******************************************************************************
3073 * EnumPrinterDataExW [WINSPOOL.@]
3075 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3076 LPBYTE pEnumValues, DWORD cbEnumValues,
3077 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3079 HKEY hkPrinter, hkSubKey;
3080 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3081 cbValueNameLen, cbMaxValueLen, cbValueLen,
3086 PPRINTER_ENUM_VALUESW ppev;
3088 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3090 if (pKeyName == NULL || *pKeyName == 0)
3091 return ERROR_INVALID_PARAMETER;
3093 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3094 if (ret != ERROR_SUCCESS)
3096 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3101 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3102 if (ret != ERROR_SUCCESS)
3104 r = RegCloseKey (hkPrinter);
3105 if (r != ERROR_SUCCESS)
3106 WARN ("RegCloseKey returned %li\n", r);
3107 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3108 debugstr_w (pKeyName), ret);
3112 ret = RegCloseKey (hkPrinter);
3113 if (ret != ERROR_SUCCESS)
3115 ERR ("RegCloseKey returned %li\n", ret);
3116 r = RegCloseKey (hkSubKey);
3117 if (r != ERROR_SUCCESS)
3118 WARN ("RegCloseKey returned %li\n", r);
3122 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3123 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3124 if (ret != ERROR_SUCCESS)
3126 r = RegCloseKey (hkSubKey);
3127 if (r != ERROR_SUCCESS)
3128 WARN ("RegCloseKey returned %li\n", r);
3129 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3133 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3134 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3136 if (cValues == 0) /* empty key */
3138 r = RegCloseKey (hkSubKey);
3139 if (r != ERROR_SUCCESS)
3140 WARN ("RegCloseKey returned %li\n", r);
3141 *pcbEnumValues = *pnEnumValues = 0;
3142 return ERROR_SUCCESS;
3145 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3147 hHeap = GetProcessHeap ();
3150 ERR ("GetProcessHeap failed\n");
3151 r = RegCloseKey (hkSubKey);
3152 if (r != ERROR_SUCCESS)
3153 WARN ("RegCloseKey returned %li\n", r);
3154 return ERROR_OUTOFMEMORY;
3157 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3158 if (lpValueName == NULL)
3160 ERR ("Failed to allocate %li bytes from process heap\n",
3161 cbMaxValueNameLen * sizeof (WCHAR));
3162 r = RegCloseKey (hkSubKey);
3163 if (r != ERROR_SUCCESS)
3164 WARN ("RegCloseKey returned %li\n", r);
3165 return ERROR_OUTOFMEMORY;
3168 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3169 if (lpValue == NULL)
3171 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3172 if (HeapFree (hHeap, 0, lpValueName) == 0)
3173 WARN ("HeapFree failed with code %li\n", GetLastError ());
3174 r = RegCloseKey (hkSubKey);
3175 if (r != ERROR_SUCCESS)
3176 WARN ("RegCloseKey returned %li\n", r);
3177 return ERROR_OUTOFMEMORY;
3180 TRACE ("pass 1: calculating buffer required for all names and values\n");
3182 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3184 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3186 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3188 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3189 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3190 NULL, NULL, lpValue, &cbValueLen);
3191 if (ret != ERROR_SUCCESS)
3193 if (HeapFree (hHeap, 0, lpValue) == 0)
3194 WARN ("HeapFree failed with code %li\n", GetLastError ());
3195 if (HeapFree (hHeap, 0, lpValueName) == 0)
3196 WARN ("HeapFree failed with code %li\n", GetLastError ());
3197 r = RegCloseKey (hkSubKey);
3198 if (r != ERROR_SUCCESS)
3199 WARN ("RegCloseKey returned %li\n", r);
3200 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3204 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3205 debugstr_w (lpValueName), dwIndex,
3206 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3208 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3209 cbBufSize += cbValueLen;
3212 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3214 *pcbEnumValues = cbBufSize;
3215 *pnEnumValues = cValues;
3217 if (cbEnumValues < cbBufSize) /* buffer too small */
3219 if (HeapFree (hHeap, 0, lpValue) == 0)
3220 WARN ("HeapFree failed with code %li\n", GetLastError ());
3221 if (HeapFree (hHeap, 0, lpValueName) == 0)
3222 WARN ("HeapFree failed with code %li\n", GetLastError ());
3223 r = RegCloseKey (hkSubKey);
3224 if (r != ERROR_SUCCESS)
3225 WARN ("RegCloseKey returned %li\n", r);
3226 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3227 return ERROR_MORE_DATA;
3230 TRACE ("pass 2: copying all names and values to buffer\n");
3232 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3233 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3235 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3237 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3238 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3239 NULL, &dwType, lpValue, &cbValueLen);
3240 if (ret != ERROR_SUCCESS)
3242 if (HeapFree (hHeap, 0, lpValue) == 0)
3243 WARN ("HeapFree failed with code %li\n", GetLastError ());
3244 if (HeapFree (hHeap, 0, lpValueName) == 0)
3245 WARN ("HeapFree failed with code %li\n", GetLastError ());
3246 r = RegCloseKey (hkSubKey);
3247 if (r != ERROR_SUCCESS)
3248 WARN ("RegCloseKey returned %li\n", r);
3249 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3253 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3254 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3255 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3256 pEnumValues += cbValueNameLen;
3258 /* return # of *bytes* (including trailing \0), not # of chars */
3259 ppev[dwIndex].cbValueName = cbValueNameLen;
3261 ppev[dwIndex].dwType = dwType;
3263 memcpy (pEnumValues, lpValue, cbValueLen);
3264 ppev[dwIndex].pData = pEnumValues;
3265 pEnumValues += cbValueLen;
3267 ppev[dwIndex].cbData = cbValueLen;
3269 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3270 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3273 if (HeapFree (hHeap, 0, lpValue) == 0)
3275 ret = GetLastError ();
3276 ERR ("HeapFree failed with code %li\n", ret);
3277 if (HeapFree (hHeap, 0, lpValueName) == 0)
3278 WARN ("HeapFree failed with code %li\n", GetLastError ());
3279 r = RegCloseKey (hkSubKey);
3280 if (r != ERROR_SUCCESS)
3281 WARN ("RegCloseKey returned %li\n", r);
3285 if (HeapFree (hHeap, 0, lpValueName) == 0)
3287 ret = GetLastError ();
3288 ERR ("HeapFree failed with code %li\n", ret);
3289 r = RegCloseKey (hkSubKey);
3290 if (r != ERROR_SUCCESS)
3291 WARN ("RegCloseKey returned %li\n", r);
3295 ret = RegCloseKey (hkSubKey);
3296 if (ret != ERROR_SUCCESS)
3298 ERR ("RegCloseKey returned %li\n", ret);
3302 return ERROR_SUCCESS;
3305 /*******************************************************************************
3306 * EnumPrinterDataExA [WINSPOOL.@]
3308 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3309 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3310 * what Windows 2000 SP1 does.
3313 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3314 LPBYTE pEnumValues, DWORD cbEnumValues,
3315 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3319 DWORD ret, dwIndex, dwBufSize;
3323 TRACE ("%p %s\n", hPrinter, pKeyName);
3325 if (pKeyName == NULL || *pKeyName == 0)
3326 return ERROR_INVALID_PARAMETER;
3328 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3331 ret = GetLastError ();
3332 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3336 hHeap = GetProcessHeap ();
3339 ERR ("GetProcessHeap failed\n");
3340 return ERROR_OUTOFMEMORY;
3343 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3344 if (pKeyNameW == NULL)
3346 ERR ("Failed to allocate %li bytes from process heap\n",
3347 (LONG) len * sizeof (WCHAR));
3348 return ERROR_OUTOFMEMORY;
3351 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3353 ret = GetLastError ();
3354 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3355 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3356 WARN ("HeapFree failed with code %li\n", GetLastError ());
3360 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3361 pcbEnumValues, pnEnumValues);
3362 if (ret != ERROR_SUCCESS)
3364 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3365 WARN ("HeapFree failed with code %li\n", GetLastError ());
3366 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3370 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3372 ret = GetLastError ();
3373 ERR ("HeapFree failed with code %li\n", ret);
3377 if (*pnEnumValues == 0) /* empty key */
3378 return ERROR_SUCCESS;
3381 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3383 PPRINTER_ENUM_VALUESW ppev =
3384 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3386 if (dwBufSize < ppev->cbValueName)
3387 dwBufSize = ppev->cbValueName;
3389 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3390 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3391 dwBufSize = ppev->cbData;
3394 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3396 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3397 if (pBuffer == NULL)
3399 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3400 return ERROR_OUTOFMEMORY;
3403 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3405 PPRINTER_ENUM_VALUESW ppev =
3406 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3408 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3409 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3413 ret = GetLastError ();
3414 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3415 if (HeapFree (hHeap, 0, pBuffer) == 0)
3416 WARN ("HeapFree failed with code %li\n", GetLastError ());
3420 memcpy (ppev->pValueName, pBuffer, len);
3422 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3424 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3425 ppev->dwType != REG_MULTI_SZ)
3428 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3429 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3432 ret = GetLastError ();
3433 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3434 if (HeapFree (hHeap, 0, pBuffer) == 0)
3435 WARN ("HeapFree failed with code %li\n", GetLastError ());
3439 memcpy (ppev->pData, pBuffer, len);
3441 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3442 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3445 if (HeapFree (hHeap, 0, pBuffer) == 0)
3447 ret = GetLastError ();
3448 ERR ("HeapFree failed with code %li\n", ret);
3452 return ERROR_SUCCESS;