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
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
97 WCHAR *document_title;
105 LPCWSTR versionregpath;
106 LPCWSTR versionsubdir;
109 /* ############################### */
111 static opened_printer_t **printer_handles;
112 static int nb_printer_handles;
113 static LONG next_job_id = 1;
115 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
116 WORD fwCapability, LPSTR lpszOutput,
118 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
119 LPSTR lpszDevice, LPSTR lpszPort,
120 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
123 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
124 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
125 'c','o','n','t','r','o','l','\\',
126 'P','r','i','n','t','\\',
127 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
128 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
130 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'C','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'M','o','n','i','t','o','r','s',0};
136 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
137 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
138 'C','o','n','t','r','o','l','\\',
139 'P','r','i','n','t','\\',
140 'P','r','i','n','t','e','r','s',0};
142 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
144 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
145 'M','i','c','r','o','s','o','f','t','\\',
146 'W','i','n','d','o','w','s',' ','N','T','\\',
147 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
148 'W','i','n','d','o','w','s',0};
150 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'D','e','v','i','c','e','s',0};
156 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
157 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
158 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
159 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
160 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
161 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
162 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
164 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
166 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
167 'i','o','n',' ','F','i','l','e',0};
168 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
169 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
170 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
172 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
174 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
175 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
176 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
177 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
178 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
179 static const WCHAR NameW[] = {'N','a','m','e',0};
180 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
181 static const WCHAR PortW[] = {'P','o','r','t',0};
182 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
184 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
186 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
187 'v','e','r','D','a','t','a',0};
188 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
190 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
191 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
192 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
193 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
194 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
195 static const WCHAR emptyStringW[] = {0};
197 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
199 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
200 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
201 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
203 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
204 'D','o','c','u','m','e','n','t',0};
206 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
207 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
208 DWORD Level, LPBYTE pDriverInfo,
209 DWORD cbBuf, LPDWORD pcbNeeded,
211 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
212 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
214 /******************************************************************
215 * validate the user-supplied printing-environment [internal]
218 * env [I] PTR to Environment-String or NULL
222 * Success: PTR to printenv_t
225 * An empty string is handled the same way as NULL.
226 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
230 static const printenv_t * validate_envW(LPCWSTR env)
232 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
233 3, Version3_RegPathW, Version3_SubdirW};
234 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
235 0, emptyStringW, emptyStringW};
236 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
238 const printenv_t *result = NULL;
241 TRACE("testing %s\n", debugstr_w(env));
244 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
246 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
248 result = all_printenv[i];
253 if (result == NULL) {
254 FIXME("unsupported Environment: %s\n", debugstr_w(env));
255 SetLastError(ERROR_INVALID_ENVIRONMENT);
257 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
261 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
263 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
269 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
270 if passed a NULL string. This returns NULLs to the result.
272 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
276 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
277 return usBufferPtr->Buffer;
279 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
283 static LPWSTR strdupW(LPCWSTR p)
289 len = (strlenW(p) + 1) * sizeof(WCHAR);
290 ret = HeapAlloc(GetProcessHeap(), 0, len);
296 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
299 /* If forcing, or no profile string entry for device yet, set the entry
301 * The always change entry if not WINEPS yet is discussable.
304 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
306 !strstr(qbuf,"WINEPS.DRV")
308 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
311 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
312 WriteProfileStringA("windows","device",buf);
313 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
314 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
317 HeapFree(GetProcessHeap(),0,buf);
321 #ifdef HAVE_CUPS_CUPS_H
322 static typeof(cupsGetDests) *pcupsGetDests;
323 static typeof(cupsGetPPD) *pcupsGetPPD;
324 static typeof(cupsPrintFile) *pcupsPrintFile;
325 static void *cupshandle;
327 static BOOL CUPS_LoadPrinters(void)
330 BOOL hadprinter = FALSE;
332 PRINTER_INFO_2A pinfo2a;
334 HKEY hkeyPrinter, hkeyPrinters, hkey;
336 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
339 TRACE("loaded %s\n", SONAME_LIBCUPS);
342 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
343 if (!p##x) return FALSE;
346 DYNCUPS(cupsGetDests);
347 DYNCUPS(cupsPrintFile);
350 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
352 ERR("Can't create Printers key\n");
356 nrofdests = pcupsGetDests(&dests);
357 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
358 for (i=0;i<nrofdests;i++) {
359 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
360 sprintf(port,"LPR:%s",dests[i].name);
361 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
362 sprintf(devline,"WINEPS.DRV,%s",port);
363 WriteProfileStringA("devices",dests[i].name,devline);
364 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
365 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
368 HeapFree(GetProcessHeap(),0,devline);
370 TRACE("Printer %d: %s\n", i, dests[i].name);
371 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
372 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
374 TRACE("Printer already exists\n");
375 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
376 RegCloseKey(hkeyPrinter);
378 memset(&pinfo2a,0,sizeof(pinfo2a));
379 pinfo2a.pPrinterName = dests[i].name;
380 pinfo2a.pDatatype = "RAW";
381 pinfo2a.pPrintProcessor = "WinPrint";
382 pinfo2a.pDriverName = "PS Driver";
383 pinfo2a.pComment = "WINEPS Printer using CUPS";
384 pinfo2a.pLocation = "<physical location of printer>";
385 pinfo2a.pPortName = port;
386 pinfo2a.pParameters = "<parameters?>";
387 pinfo2a.pShareName = "<share name?>";
388 pinfo2a.pSepFile = "<sep file?>";
390 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
391 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
392 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
395 HeapFree(GetProcessHeap(),0,port);
398 if (dests[i].is_default)
399 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
401 RegCloseKey(hkeyPrinters);
407 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
408 PRINTER_INFO_2A pinfo2a;
409 char *e,*s,*name,*prettyname,*devname;
410 BOOL ret = FALSE, set_default = FALSE;
411 char *port,*devline,*env_default;
412 HKEY hkeyPrinter, hkeyPrinters, hkey;
414 while (isspace(*pent)) pent++;
415 s = strchr(pent,':');
417 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
425 TRACE("name=%s entry=%s\n",name, pent);
427 if(ispunct(*name)) { /* a tc entry, not a real printer */
428 TRACE("skipping tc entry\n");
432 if(strstr(pent,":server")) { /* server only version so skip */
433 TRACE("skipping server entry\n");
437 /* Determine whether this is a postscript printer. */
440 env_default = getenv("PRINTER");
442 /* Get longest name, usually the one at the right for later display. */
443 while((s=strchr(prettyname,'|'))) {
446 while(isspace(*--e)) *e = '\0';
447 TRACE("\t%s\n", debugstr_a(prettyname));
448 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
449 for(prettyname = s+1; isspace(*prettyname); prettyname++)
452 e = prettyname + strlen(prettyname);
453 while(isspace(*--e)) *e = '\0';
454 TRACE("\t%s\n", debugstr_a(prettyname));
455 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
457 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
458 * if it is too long, we use it as comment below. */
459 devname = prettyname;
460 if (strlen(devname)>=CCHDEVICENAME-1)
462 if (strlen(devname)>=CCHDEVICENAME-1) {
467 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
468 sprintf(port,"LPR:%s",name);
470 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
471 sprintf(devline,"WINEPS.DRV,%s",port);
472 WriteProfileStringA("devices",devname,devline);
473 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
474 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
477 HeapFree(GetProcessHeap(),0,devline);
479 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
481 ERR("Can't create Printers key\n");
485 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
486 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
488 TRACE("Printer already exists\n");
489 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
490 RegCloseKey(hkeyPrinter);
492 memset(&pinfo2a,0,sizeof(pinfo2a));
493 pinfo2a.pPrinterName = devname;
494 pinfo2a.pDatatype = "RAW";
495 pinfo2a.pPrintProcessor = "WinPrint";
496 pinfo2a.pDriverName = "PS Driver";
497 pinfo2a.pComment = "WINEPS Printer using LPR";
498 pinfo2a.pLocation = prettyname;
499 pinfo2a.pPortName = port;
500 pinfo2a.pParameters = "<parameters?>";
501 pinfo2a.pShareName = "<share name?>";
502 pinfo2a.pSepFile = "<sep file?>";
504 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
505 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
506 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
509 RegCloseKey(hkeyPrinters);
511 if (isfirst || set_default)
512 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
514 HeapFree(GetProcessHeap(), 0, port);
516 HeapFree(GetProcessHeap(), 0, name);
521 PRINTCAP_LoadPrinters(void) {
522 BOOL hadprinter = FALSE;
526 BOOL had_bash = FALSE;
528 f = fopen("/etc/printcap","r");
532 while(fgets(buf,sizeof(buf),f)) {
535 end=strchr(buf,'\n');
539 while(isspace(*start)) start++;
540 if(*start == '#' || *start == '\0')
543 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
544 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
545 HeapFree(GetProcessHeap(),0,pent);
549 if (end && *--end == '\\') {
556 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
559 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
565 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
566 HeapFree(GetProcessHeap(),0,pent);
572 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
575 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
576 lstrlenW(value) * sizeof(WCHAR));
578 return ERROR_FILE_NOT_FOUND;
581 void WINSPOOL_LoadSystemPrinters(void)
583 HKEY hkey, hkeyPrinters;
586 DWORD needed, num, i;
587 WCHAR PrinterName[256];
590 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
591 di3a.pName = "PS Driver";
592 di3a.pEnvironment = NULL; /* NULL means auto */
593 di3a.pDriverPath = "wineps16";
594 di3a.pDataFile = "<datafile?>";
595 di3a.pConfigFile = "wineps16";
596 di3a.pHelpFile = "<helpfile?>";
597 di3a.pDependentFiles = "<dependend files?>";
598 di3a.pMonitorName = "<monitor name?>";
599 di3a.pDefaultDataType = "RAW";
601 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
602 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
606 /* This ensures that all printer entries have a valid Name value. If causes
607 problems later if they don't. If one is found to be missed we create one
608 and set it equal to the name of the key */
609 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
610 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
611 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
612 for(i = 0; i < num; i++) {
613 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
614 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
615 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
616 set_reg_szW(hkey, NameW, PrinterName);
623 RegCloseKey(hkeyPrinters);
626 /* We want to avoid calling AddPrinter on printers as much as
627 possible, because on cups printers this will (eventually) lead
628 to a call to cupsGetPPD which takes forever, even with non-cups
629 printers AddPrinter takes a while. So we'll tag all printers that
630 were automatically added last time around, if they still exist
631 we'll leave them be otherwise we'll delete them. */
632 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
634 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
635 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
636 for(i = 0; i < num; i++) {
637 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
638 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
639 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
641 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
649 HeapFree(GetProcessHeap(), 0, pi);
653 #ifdef HAVE_CUPS_CUPS_H
654 done = CUPS_LoadPrinters();
657 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
658 /* Check for [ppd] section in config file before parsing /etc/printcap */
659 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
660 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
661 &hkey) == ERROR_SUCCESS) {
663 PRINTCAP_LoadPrinters();
667 /* Now enumerate the list again and delete any printers that a still tagged */
668 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
670 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
671 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
672 for(i = 0; i < num; i++) {
673 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
674 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
675 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
676 DWORD dw, type, size = sizeof(dw);
677 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
678 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
688 HeapFree(GetProcessHeap(), 0, pi);
695 /*****************************************************************************
696 * enumerate the local monitors (INTERNAL)
698 * returns the needed size (in bytes) for pMonitors
699 * and *lpreturned is set to number of entries returned in pMonitors
702 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
707 LPMONITOR_INFO_2W mi;
708 WCHAR buffer[MAX_PATH];
709 WCHAR dllname[MAX_PATH];
717 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
719 numentries = *lpreturned; /* this is 0, when we scan the registry */
720 len = entrysize * numentries;
721 ptr = (LPWSTR) &pMonitors[len];
724 len = sizeof(buffer);
727 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
728 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
729 /* Scan all Monitor-Registry-Keys */
730 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
731 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
732 dllsize = sizeof(dllname);
735 /* The Monitor must have a Driver-DLL */
736 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
737 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
738 /* We found a valid DLL for this Monitor. */
739 TRACE("using Driver: %s\n", debugstr_w(dllname));
744 /* Windows returns only Port-Monitors here, but to simplify our code,
745 we do no filtering for Language-Monitors */
749 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
751 /* we install and return only monitors for "Windows NT x86" */
752 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
756 /* required size is calculated. Now fill the user-buffer */
757 if (pMonitors && (cbBuf >= needed)){
758 mi = (LPMONITOR_INFO_2W) pMonitors;
759 pMonitors += entrysize;
761 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
763 lstrcpyW(ptr, buffer); /* Name of the Monitor */
764 ptr += (len+1); /* len is lstrlenW(monitorname) */
766 mi->pEnvironment = ptr;
767 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
768 ptr += (lstrlenW(envname_x86W)+1);
771 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
772 ptr += (dllsize / sizeof(WCHAR));
777 len = sizeof(buffer);
782 *lpreturned = numentries;
783 TRACE("need %ld byte for %ld entries\n", needed, numentries);
787 /******************************************************************
788 * get_opened_printer_entry
789 * Get the first place empty in the opened printer table
792 * - pDefault is ignored
794 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
796 UINT_PTR handle = nb_printer_handles, i;
797 jobqueue_t *queue = NULL;
798 opened_printer_t *printer = NULL;
800 EnterCriticalSection(&printer_handles_cs);
802 for (i = 0; i < nb_printer_handles; i++)
804 if (!printer_handles[i])
806 if(handle == nb_printer_handles)
811 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
812 queue = printer_handles[i]->queue;
816 if (handle >= nb_printer_handles)
818 opened_printer_t **new_array;
820 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
821 (nb_printer_handles + 16) * sizeof(*new_array) );
823 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
824 (nb_printer_handles + 16) * sizeof(*new_array) );
831 printer_handles = new_array;
832 nb_printer_handles += 16;
835 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
842 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
843 if (!printer->name) {
847 strcpyW(printer->name, name);
851 printer->queue = queue;
854 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
855 if (!printer->queue) {
859 list_init(&printer->queue->jobs);
860 printer->queue->ref = 0;
862 InterlockedIncrement(&printer->queue->ref);
864 printer_handles[handle] = printer;
867 LeaveCriticalSection(&printer_handles_cs);
868 if (!handle && printer) {
869 /* Something Failed: Free the Buffers */
870 HeapFree(GetProcessHeap(), 0, printer->name);
871 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
872 HeapFree(GetProcessHeap(), 0, printer);
875 return (HANDLE)handle;
878 /******************************************************************
880 * Get the pointer to the opened printer referred by the handle
882 static opened_printer_t *get_opened_printer(HANDLE hprn)
884 UINT_PTR idx = (UINT_PTR)hprn;
885 opened_printer_t *ret = NULL;
887 EnterCriticalSection(&printer_handles_cs);
889 if ((idx <= 0) || (idx > nb_printer_handles))
892 ret = printer_handles[idx - 1];
894 LeaveCriticalSection(&printer_handles_cs);
898 /******************************************************************
899 * get_opened_printer_name
900 * Get the pointer to the opened printer name referred by the handle
902 static LPCWSTR get_opened_printer_name(HANDLE hprn)
904 opened_printer_t *printer = get_opened_printer(hprn);
905 if(!printer) return NULL;
906 return printer->name;
909 /******************************************************************
910 * WINSPOOL_GetOpenedPrinterRegKey
913 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
915 LPCWSTR name = get_opened_printer_name(hPrinter);
919 if(!name) return ERROR_INVALID_HANDLE;
921 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
925 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
927 ERR("Can't find opened printer %s in registry\n",
929 RegCloseKey(hkeyPrinters);
930 return ERROR_INVALID_PRINTER_NAME; /* ? */
932 RegCloseKey(hkeyPrinters);
933 return ERROR_SUCCESS;
936 /******************************************************************
939 * Get the pointer to the specified job.
940 * Should hold the printer_handles_cs before calling.
942 static job_t *get_job(HANDLE hprn, DWORD JobId)
944 opened_printer_t *printer = get_opened_printer(hprn);
947 if(!printer) return NULL;
948 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
950 if(job->job_id == JobId)
956 /***********************************************************
959 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
962 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
965 Formname = (dmA->dmSize > off_formname);
966 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
967 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
968 dmW->dmDeviceName, CCHDEVICENAME);
970 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
971 dmA->dmSize - CCHDEVICENAME);
973 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
974 off_formname - CCHDEVICENAME);
975 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
976 dmW->dmFormName, CCHFORMNAME);
977 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
978 (off_formname + CCHFORMNAME));
981 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
986 /***********************************************************
988 * Creates an ascii copy of supplied devmode on heap
990 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
995 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
997 if(!dmW) return NULL;
998 Formname = (dmW->dmSize > off_formname);
999 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1000 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1001 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1002 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1004 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1005 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1007 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1008 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1009 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1010 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1011 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1012 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1015 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1016 dmW->dmDriverExtra);
1020 /***********************************************************
1021 * PRINTER_INFO_2AtoW
1022 * Creates a unicode copy of PRINTER_INFO_2A on heap
1024 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1026 LPPRINTER_INFO_2W piW;
1027 UNICODE_STRING usBuffer;
1029 if(!piA) return NULL;
1030 piW = HeapAlloc(heap, 0, sizeof(*piW));
1031 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1033 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1034 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1035 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1036 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1037 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1038 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1039 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1040 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1041 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1042 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1043 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1044 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1048 /***********************************************************
1049 * FREE_PRINTER_INFO_2W
1050 * Free PRINTER_INFO_2W and all strings
1052 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1056 HeapFree(heap,0,piW->pServerName);
1057 HeapFree(heap,0,piW->pPrinterName);
1058 HeapFree(heap,0,piW->pShareName);
1059 HeapFree(heap,0,piW->pPortName);
1060 HeapFree(heap,0,piW->pDriverName);
1061 HeapFree(heap,0,piW->pComment);
1062 HeapFree(heap,0,piW->pLocation);
1063 HeapFree(heap,0,piW->pDevMode);
1064 HeapFree(heap,0,piW->pSepFile);
1065 HeapFree(heap,0,piW->pPrintProcessor);
1066 HeapFree(heap,0,piW->pDatatype);
1067 HeapFree(heap,0,piW->pParameters);
1068 HeapFree(heap,0,piW);
1072 /******************************************************************
1073 * DeviceCapabilities [WINSPOOL.@]
1074 * DeviceCapabilitiesA [WINSPOOL.@]
1077 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1078 LPSTR pOutput, LPDEVMODEA lpdm)
1082 if (!GDI_CallDeviceCapabilities16)
1084 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1086 if (!GDI_CallDeviceCapabilities16) return -1;
1088 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1090 /* If DC_PAPERSIZE map POINT16s to POINTs */
1091 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1092 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1093 POINT *pt = (POINT *)pOutput;
1095 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1096 for(i = 0; i < ret; i++, pt++)
1101 HeapFree( GetProcessHeap(), 0, tmp );
1107 /*****************************************************************************
1108 * DeviceCapabilitiesW [WINSPOOL.@]
1110 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1113 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1114 WORD fwCapability, LPWSTR pOutput,
1115 const DEVMODEW *pDevMode)
1117 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1118 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1119 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1122 if(pOutput && (fwCapability == DC_BINNAMES ||
1123 fwCapability == DC_FILEDEPENDENCIES ||
1124 fwCapability == DC_PAPERNAMES)) {
1125 /* These need A -> W translation */
1128 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1132 switch(fwCapability) {
1137 case DC_FILEDEPENDENCIES:
1141 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1142 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1144 for(i = 0; i < ret; i++)
1145 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1146 pOutput + (i * size), size);
1147 HeapFree(GetProcessHeap(), 0, pOutputA);
1149 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1150 (LPSTR)pOutput, dmA);
1152 HeapFree(GetProcessHeap(),0,pPortA);
1153 HeapFree(GetProcessHeap(),0,pDeviceA);
1154 HeapFree(GetProcessHeap(),0,dmA);
1158 /******************************************************************
1159 * DocumentPropertiesA [WINSPOOL.@]
1161 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1163 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1164 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1165 LPDEVMODEA pDevModeInput,DWORD fMode )
1167 LPSTR lpName = pDeviceName;
1170 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1171 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1175 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1177 ERR("no name from hPrinter?\n");
1178 SetLastError(ERROR_INVALID_HANDLE);
1181 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1184 if (!GDI_CallExtDeviceMode16)
1186 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1188 if (!GDI_CallExtDeviceMode16) {
1189 ERR("No CallExtDeviceMode16?\n");
1193 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1194 pDevModeInput, NULL, fMode);
1197 HeapFree(GetProcessHeap(),0,lpName);
1202 /*****************************************************************************
1203 * DocumentPropertiesW (WINSPOOL.@)
1205 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1207 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1209 LPDEVMODEW pDevModeOutput,
1210 LPDEVMODEW pDevModeInput, DWORD fMode)
1213 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1214 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1215 LPDEVMODEA pDevModeOutputA = NULL;
1218 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1219 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1221 if(pDevModeOutput) {
1222 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1223 if(ret < 0) return ret;
1224 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1226 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1227 pDevModeInputA, fMode);
1228 if(pDevModeOutput) {
1229 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1230 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1232 if(fMode == 0 && ret > 0)
1233 ret += (CCHDEVICENAME + CCHFORMNAME);
1234 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1235 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1239 /******************************************************************
1240 * OpenPrinterA [WINSPOOL.@]
1245 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1246 LPPRINTER_DEFAULTSA pDefault)
1248 UNICODE_STRING lpPrinterNameW;
1249 UNICODE_STRING usBuffer;
1250 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1251 PWSTR pwstrPrinterNameW;
1254 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1257 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1258 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1259 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1260 pDefaultW = &DefaultW;
1262 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1264 RtlFreeUnicodeString(&usBuffer);
1265 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1267 RtlFreeUnicodeString(&lpPrinterNameW);
1271 /******************************************************************
1272 * OpenPrinterW [WINSPOOL.@]
1274 * Open a Printer / Printserver or a Printer-Object
1277 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1278 * phPrinter [O] The resulting Handle is stored here
1279 * pDefault [I] PTR to Default Printer Settings or NULL
1286 * lpPrinterName is one of:
1287 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1288 *| Printer: "PrinterName"
1289 *| Printer-Object: "PrinterName,Job xxx"
1290 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1291 *| XcvPort: "Servername,XcvPort PortName"
1294 *| Printer-Object not supported
1295 *| XcvMonitor not supported
1296 *| XcvPort not supported
1297 *| pDefaults is ignored
1300 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1302 HKEY hkeyPrinters = NULL;
1303 HKEY hkeyPrinter = NULL;
1305 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1307 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1308 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1311 if(lpPrinterName != NULL)
1313 /* Check any Printer exists */
1314 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1315 ERR("Can't create Printers key\n");
1316 SetLastError(ERROR_FILE_NOT_FOUND);
1319 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1320 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1322 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1323 RegCloseKey(hkeyPrinters);
1324 SetLastError(ERROR_INVALID_PRINTER_NAME);
1327 RegCloseKey(hkeyPrinter);
1328 RegCloseKey(hkeyPrinters);
1331 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1332 SetLastError(ERROR_INVALID_PARAMETER);
1336 /* Get the unique handle of the printer or Printserver */
1337 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1338 return (*phPrinter != 0);
1341 /******************************************************************
1342 * AddMonitorA [WINSPOOL.@]
1347 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1349 LPWSTR nameW = NULL;
1352 LPMONITOR_INFO_2A mi2a;
1353 MONITOR_INFO_2W mi2w;
1355 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1356 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1357 mi2a ? debugstr_a(mi2a->pName) : NULL,
1358 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1359 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1362 SetLastError(ERROR_INVALID_LEVEL);
1366 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1372 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1373 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1374 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1377 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1379 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1380 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1381 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1383 if (mi2a->pEnvironment) {
1384 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1385 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1386 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1388 if (mi2a->pDLLName) {
1389 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1390 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1391 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1394 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1396 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1397 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1398 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1400 HeapFree(GetProcessHeap(), 0, nameW);
1404 /******************************************************************************
1405 * AddMonitorW [WINSPOOL.@]
1407 * Install a Printmonitor
1410 * pName [I] Servername or NULL (local Computer)
1411 * Level [I] Structure-Level (Must be 2)
1412 * pMonitors [I] PTR to MONITOR_INFO_2
1419 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1422 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1424 LPMONITOR_INFO_2W mi2w;
1427 HMODULE hdll = NULL;
1431 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1432 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1433 mi2w ? debugstr_w(mi2w->pName) : NULL,
1434 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1435 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1438 SetLastError(ERROR_INVALID_LEVEL);
1442 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1447 if (pName && (pName[0])) {
1448 FIXME("for server %s not implemented\n", debugstr_w(pName));
1449 SetLastError(ERROR_ACCESS_DENIED);
1454 if (!mi2w->pName || (! mi2w->pName[0])) {
1455 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1456 SetLastError(ERROR_INVALID_PARAMETER);
1459 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1460 WARN("Environment %s requested (we support only %s)\n",
1461 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1462 SetLastError(ERROR_INVALID_ENVIRONMENT);
1466 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1467 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1468 SetLastError(ERROR_INVALID_PARAMETER);
1472 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1478 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1482 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1483 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1485 if (disposition == REG_OPENED_EXISTING_KEY) {
1486 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1487 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1488 9x: ERROR_ALREADY_EXISTS (183) */
1489 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1494 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1495 res = (RegSetValueExW(hentry, DriverW, 0,
1496 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1498 RegCloseKey(hentry);
1505 /******************************************************************
1506 * DeletePrinterDriverA [WINSPOOL.@]
1510 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1512 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1513 debugstr_a(pDriverName));
1514 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1518 /******************************************************************
1519 * DeletePrinterDriverW [WINSPOOL.@]
1523 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1525 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1526 debugstr_w(pDriverName));
1527 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1531 /******************************************************************
1532 * DeleteMonitorA [WINSPOOL.@]
1534 * See DeleteMonitorW.
1537 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1539 LPWSTR nameW = NULL;
1540 LPWSTR EnvironmentW = NULL;
1541 LPWSTR MonitorNameW = NULL;
1546 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1547 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1548 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1552 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1553 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1554 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1557 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1558 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1559 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1562 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1564 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1565 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1566 HeapFree(GetProcessHeap(), 0, nameW);
1570 /******************************************************************
1571 * DeleteMonitorW [WINSPOOL.@]
1573 * Delete a specific Printmonitor from a Printing-Environment
1576 * pName [I] Servername or NULL (local Computer)
1577 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1578 * pMonitorName [I] Name of the Monitor, that should be deleted
1585 * pEnvironment is ignored in Windows for the local Computer.
1589 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1593 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1594 debugstr_w(pMonitorName));
1596 if (pName && (pName[0])) {
1597 FIXME("for server %s not implemented\n", debugstr_w(pName));
1598 SetLastError(ERROR_ACCESS_DENIED);
1602 /* pEnvironment is ignored in Windows for the local Computer */
1604 if (!pMonitorName || !pMonitorName[0]) {
1605 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1606 SetLastError(ERROR_INVALID_PARAMETER);
1610 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1611 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1615 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1616 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1617 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1622 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1625 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1626 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1630 /******************************************************************
1631 * DeletePortA [WINSPOOL.@]
1637 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1639 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1640 debugstr_a(pPortName));
1641 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1645 /******************************************************************
1646 * DeletePortW [WINSPOOL.@]
1648 * Delete a specific Port
1651 * pName [I] Servername or NULL (local Computer)
1652 * hWnd [I] Handle to parent Window for the Dialog-Box
1653 * pPortName [I] Name of the Port, that should be deleted
1664 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1666 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1667 debugstr_w(pPortName));
1668 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1672 /******************************************************************************
1673 * SetPrinterW [WINSPOOL.@]
1675 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1677 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1678 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1682 /******************************************************************************
1683 * WritePrinter [WINSPOOL.@]
1685 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1687 opened_printer_t *printer;
1690 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1692 EnterCriticalSection(&printer_handles_cs);
1693 printer = get_opened_printer(hPrinter);
1696 SetLastError(ERROR_INVALID_HANDLE);
1702 SetLastError(ERROR_SPL_NO_STARTDOC);
1706 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1708 LeaveCriticalSection(&printer_handles_cs);
1712 /*****************************************************************************
1713 * AddFormA [WINSPOOL.@]
1715 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1717 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1721 /*****************************************************************************
1722 * AddFormW [WINSPOOL.@]
1724 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1726 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1730 /*****************************************************************************
1731 * AddJobA [WINSPOOL.@]
1733 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1736 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1740 SetLastError(ERROR_INVALID_LEVEL);
1744 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1747 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1748 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1749 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1750 if(*pcbNeeded > cbBuf) {
1751 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1754 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1755 addjobA->JobId = addjobW->JobId;
1756 addjobA->Path = (char *)(addjobA + 1);
1757 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1763 /*****************************************************************************
1764 * AddJobW [WINSPOOL.@]
1766 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1768 opened_printer_t *printer;
1771 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1772 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1773 WCHAR path[MAX_PATH], filename[MAX_PATH];
1775 ADDJOB_INFO_1W *addjob;
1777 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1779 EnterCriticalSection(&printer_handles_cs);
1781 printer = get_opened_printer(hPrinter);
1784 SetLastError(ERROR_INVALID_HANDLE);
1789 SetLastError(ERROR_INVALID_LEVEL);
1793 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1797 job->job_id = InterlockedIncrement(&next_job_id);
1799 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1800 if(path[len - 1] != '\\')
1802 memcpy(path + len, spool_path, sizeof(spool_path));
1803 sprintfW(filename, fmtW, path, job->job_id);
1805 len = strlenW(filename);
1806 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1807 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1808 job->document_title = strdupW(default_doc_title);
1809 list_add_tail(&printer->queue->jobs, &job->entry);
1811 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1812 if(*pcbNeeded <= cbBuf) {
1813 addjob = (ADDJOB_INFO_1W*)pData;
1814 addjob->JobId = job->job_id;
1815 addjob->Path = (WCHAR *)(addjob + 1);
1816 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1819 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1822 LeaveCriticalSection(&printer_handles_cs);
1826 /*****************************************************************************
1827 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1829 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1830 DWORD level, LPBYTE Info,
1831 DWORD cbBuf, LPDWORD needed)
1833 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1834 level, Info, cbBuf);
1838 /*****************************************************************************
1839 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1841 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1842 DWORD level, LPBYTE Info,
1843 DWORD cbBuf, LPDWORD needed)
1845 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1846 level, Info, cbBuf);
1850 /*****************************************************************************
1851 * WINSPOOL_OpenDriverReg [internal]
1853 * opens the registry for the printer drivers depending on the given input
1854 * variable pEnvironment
1857 * the opened hkey on success
1860 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1864 const printenv_t * env;
1867 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
1869 if (!pEnvironment || unicode) {
1870 /* pEnvironment was NULL or an Unicode-String: use it direct */
1871 env = validate_envW(pEnvironment);
1875 /* pEnvironment was an ANSI-String: convert to unicode first */
1877 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1878 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1879 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1880 env = validate_envW(buffer);
1881 HeapFree(GetProcessHeap(), 0, buffer);
1883 if (!env) return NULL;
1885 buffer = HeapAlloc( GetProcessHeap(), 0,
1886 (strlenW(DriversW) + strlenW(env->envname) +
1887 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
1889 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
1890 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1891 HeapFree(GetProcessHeap(), 0, buffer);
1896 /*****************************************************************************
1897 * AddPrinterW [WINSPOOL.@]
1899 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1901 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1905 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1908 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1911 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1912 SetLastError(ERROR_INVALID_PARAMETER);
1916 ERR("Level = %ld, unsupported!\n", Level);
1917 SetLastError(ERROR_INVALID_LEVEL);
1920 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1921 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1922 debugstr_w(pi->pPrinterName)
1924 SetLastError(ERROR_INVALID_LEVEL);
1928 SetLastError(ERROR_INVALID_PARAMETER);
1931 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1933 ERR("Can't create Printers key\n");
1936 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1937 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1938 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1939 RegCloseKey(hkeyPrinter);
1940 RegCloseKey(hkeyPrinters);
1943 RegCloseKey(hkeyPrinter);
1945 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1947 ERR("Can't create Drivers key\n");
1948 RegCloseKey(hkeyPrinters);
1951 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1953 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1954 RegCloseKey(hkeyPrinters);
1955 RegCloseKey(hkeyDrivers);
1956 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1959 RegCloseKey(hkeyDriver);
1960 RegCloseKey(hkeyDrivers);
1962 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1963 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1964 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1965 RegCloseKey(hkeyPrinters);
1969 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1971 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1972 SetLastError(ERROR_INVALID_PRINTER_NAME);
1973 RegCloseKey(hkeyPrinters);
1976 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1977 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1978 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1980 /* See if we can load the driver. We may need the devmode structure anyway
1983 * Note that DocumentPropertiesW will briefly try to open the printer we
1984 * just create to find a DEVMODEA struct (it will use the WINEPS default
1985 * one in case it is not there, so we are ok).
1987 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1990 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1991 size = sizeof(DEVMODEW);
1997 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1998 ZeroMemory(dmW,size);
2000 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2002 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2003 HeapFree(GetProcessHeap(),0,dmW);
2008 /* set devmode to printer name */
2009 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
2013 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2014 and we support these drivers. NT writes DEVMODEW so somehow
2015 we'll need to distinguish between these when we support NT
2019 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2020 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2021 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2022 HeapFree(GetProcessHeap(), 0, dmA);
2024 HeapFree(GetProcessHeap(), 0, dmW);
2026 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2027 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2028 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2029 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2031 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2032 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2033 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2034 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2035 (LPBYTE)&pi->Priority, sizeof(DWORD));
2036 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2037 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2038 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2039 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2040 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2041 (LPBYTE)&pi->Status, sizeof(DWORD));
2042 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2043 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2045 RegCloseKey(hkeyPrinter);
2046 RegCloseKey(hkeyPrinters);
2047 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2048 ERR("OpenPrinter failing\n");
2054 /*****************************************************************************
2055 * AddPrinterA [WINSPOOL.@]
2057 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2059 UNICODE_STRING pNameW;
2061 PRINTER_INFO_2W *piW;
2062 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2065 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2067 ERR("Level = %ld, unsupported!\n", Level);
2068 SetLastError(ERROR_INVALID_LEVEL);
2071 pwstrNameW = asciitounicode(&pNameW,pName);
2072 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2074 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2076 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2077 RtlFreeUnicodeString(&pNameW);
2082 /*****************************************************************************
2083 * ClosePrinter [WINSPOOL.@]
2085 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2087 UINT_PTR i = (UINT_PTR)hPrinter;
2088 opened_printer_t *printer = NULL;
2091 TRACE("Handle %p\n", hPrinter);
2093 EnterCriticalSection(&printer_handles_cs);
2095 if ((i > 0) && (i <= nb_printer_handles))
2096 printer = printer_handles[i - 1];
2100 struct list *cursor, *cursor2;
2103 EndDocPrinter(hPrinter);
2105 if(InterlockedDecrement(&printer->queue->ref) == 0)
2107 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2109 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2110 ScheduleJob(hPrinter, job->job_id);
2112 HeapFree(GetProcessHeap(), 0, printer->queue);
2114 HeapFree(GetProcessHeap(), 0, printer->name);
2115 HeapFree(GetProcessHeap(), 0, printer);
2116 printer_handles[i - 1] = NULL;
2119 LeaveCriticalSection(&printer_handles_cs);
2123 /*****************************************************************************
2124 * DeleteFormA [WINSPOOL.@]
2126 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2128 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2132 /*****************************************************************************
2133 * DeleteFormW [WINSPOOL.@]
2135 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2137 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2141 /*****************************************************************************
2142 * WINSPOOL_SHRegDeleteKey
2144 * Recursively delete subkeys.
2145 * Cut & paste from shlwapi.
2148 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2150 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2151 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2154 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2157 /* Find how many subkeys there are */
2158 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2159 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2163 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2164 /* Name too big: alloc a buffer for it */
2165 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2168 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2171 /* Recursively delete all the subkeys */
2172 for(i = 0; i < dwKeyCount && !dwRet; i++)
2174 dwSize = dwMaxSubkeyLen;
2175 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2177 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2180 if (lpszName != szNameBuf)
2181 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2185 RegCloseKey(hSubKey);
2187 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2192 /*****************************************************************************
2193 * DeletePrinter [WINSPOOL.@]
2195 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2197 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2198 HKEY hkeyPrinters, hkey;
2201 SetLastError(ERROR_INVALID_HANDLE);
2204 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2205 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2206 RegCloseKey(hkeyPrinters);
2208 WriteProfileStringW(devicesW, lpNameW, NULL);
2209 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2210 RegDeleteValueW(hkey, lpNameW);
2216 /*****************************************************************************
2217 * SetPrinterA [WINSPOOL.@]
2219 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2222 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2226 /*****************************************************************************
2227 * SetJobA [WINSPOOL.@]
2229 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2230 LPBYTE pJob, DWORD Command)
2234 UNICODE_STRING usBuffer;
2236 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2238 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2239 are all ignored by SetJob, so we don't bother copying them */
2247 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2248 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2250 JobW = (LPBYTE)info1W;
2251 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2252 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2253 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2254 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2255 info1W->Status = info1A->Status;
2256 info1W->Priority = info1A->Priority;
2257 info1W->Position = info1A->Position;
2258 info1W->PagesPrinted = info1A->PagesPrinted;
2263 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2264 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2266 JobW = (LPBYTE)info2W;
2267 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2268 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2269 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2270 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2271 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2272 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2273 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2274 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2275 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2276 info2W->Status = info2A->Status;
2277 info2W->Priority = info2A->Priority;
2278 info2W->Position = info2A->Position;
2279 info2W->StartTime = info2A->StartTime;
2280 info2W->UntilTime = info2A->UntilTime;
2281 info2W->PagesPrinted = info2A->PagesPrinted;
2285 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2286 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2289 SetLastError(ERROR_INVALID_LEVEL);
2293 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2299 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2300 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2301 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2302 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2303 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2308 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2309 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2310 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2311 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2312 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2313 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2314 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2315 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2316 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2320 HeapFree(GetProcessHeap(), 0, JobW);
2325 /*****************************************************************************
2326 * SetJobW [WINSPOOL.@]
2328 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2329 LPBYTE pJob, DWORD Command)
2334 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2335 FIXME("Ignoring everything other than document title\n");
2337 EnterCriticalSection(&printer_handles_cs);
2338 job = get_job(hPrinter, JobId);
2348 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2349 HeapFree(GetProcessHeap(), 0, job->document_title);
2350 job->document_title = strdupW(info1->pDocument);
2355 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2356 HeapFree(GetProcessHeap(), 0, job->document_title);
2357 job->document_title = strdupW(info2->pDocument);
2363 SetLastError(ERROR_INVALID_LEVEL);
2368 LeaveCriticalSection(&printer_handles_cs);
2372 /*****************************************************************************
2373 * EndDocPrinter [WINSPOOL.@]
2375 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2377 opened_printer_t *printer;
2379 TRACE("(%p)\n", hPrinter);
2381 EnterCriticalSection(&printer_handles_cs);
2383 printer = get_opened_printer(hPrinter);
2386 SetLastError(ERROR_INVALID_HANDLE);
2392 SetLastError(ERROR_SPL_NO_STARTDOC);
2396 CloseHandle(printer->doc->hf);
2397 ScheduleJob(hPrinter, printer->doc->job_id);
2398 HeapFree(GetProcessHeap(), 0, printer->doc);
2399 printer->doc = NULL;
2402 LeaveCriticalSection(&printer_handles_cs);
2406 /*****************************************************************************
2407 * EndPagePrinter [WINSPOOL.@]
2409 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2411 FIXME("(%p): stub\n", hPrinter);
2415 /*****************************************************************************
2416 * StartDocPrinterA [WINSPOOL.@]
2418 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2420 UNICODE_STRING usBuffer;
2422 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2425 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2426 or one (DOC_INFO_3) extra DWORDs */
2430 doc2W.JobId = doc2->JobId;
2433 doc2W.dwMode = doc2->dwMode;
2436 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2437 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2438 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2442 SetLastError(ERROR_INVALID_LEVEL);
2446 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2448 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2449 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2450 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2455 /*****************************************************************************
2456 * StartDocPrinterW [WINSPOOL.@]
2458 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2460 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2461 opened_printer_t *printer;
2462 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2463 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2464 JOB_INFO_1W job_info;
2465 DWORD needed, ret = 0;
2469 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2470 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2471 debugstr_w(doc->pDatatype));
2473 if(Level < 1 || Level > 3)
2475 SetLastError(ERROR_INVALID_LEVEL);
2479 EnterCriticalSection(&printer_handles_cs);
2480 printer = get_opened_printer(hPrinter);
2483 SetLastError(ERROR_INVALID_HANDLE);
2489 SetLastError(ERROR_INVALID_PRINTER_STATE);
2493 /* Even if we're printing to a file we still add a print job, we'll
2494 just ignore the spool file name */
2496 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2498 ERR("AddJob failed gle %08lx\n", GetLastError());
2502 if(doc->pOutputFile)
2503 filename = doc->pOutputFile;
2505 filename = addjob->Path;
2507 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2508 if(hf == INVALID_HANDLE_VALUE)
2511 memset(&job_info, 0, sizeof(job_info));
2512 job_info.pDocument = doc->pDocName;
2513 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2515 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2516 printer->doc->hf = hf;
2517 ret = printer->doc->job_id = addjob->JobId;
2519 LeaveCriticalSection(&printer_handles_cs);
2524 /*****************************************************************************
2525 * StartPagePrinter [WINSPOOL.@]
2527 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2529 FIXME("(%p): stub\n", hPrinter);
2533 /*****************************************************************************
2534 * GetFormA [WINSPOOL.@]
2536 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2537 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2539 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2540 Level,pForm,cbBuf,pcbNeeded);
2544 /*****************************************************************************
2545 * GetFormW [WINSPOOL.@]
2547 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2548 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2550 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2551 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2555 /*****************************************************************************
2556 * SetFormA [WINSPOOL.@]
2558 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2561 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2565 /*****************************************************************************
2566 * SetFormW [WINSPOOL.@]
2568 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2571 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2575 /*****************************************************************************
2576 * ReadPrinter [WINSPOOL.@]
2578 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2579 LPDWORD pNoBytesRead)
2581 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2585 /*****************************************************************************
2586 * ResetPrinterA [WINSPOOL.@]
2588 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2590 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2594 /*****************************************************************************
2595 * ResetPrinterW [WINSPOOL.@]
2597 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2599 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2603 /*****************************************************************************
2604 * WINSPOOL_GetDWORDFromReg
2606 * Return DWORD associated with ValueName from hkey.
2608 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2610 DWORD sz = sizeof(DWORD), type, value = 0;
2613 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2615 if(ret != ERROR_SUCCESS) {
2616 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2619 if(type != REG_DWORD) {
2620 ERR("Got type %ld\n", type);
2626 /*****************************************************************************
2627 * WINSPOOL_GetStringFromReg
2629 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2630 * String is stored either as unicode or ascii.
2631 * Bit of a hack here to get the ValueName if we want ascii.
2633 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2634 DWORD buflen, DWORD *needed,
2637 DWORD sz = buflen, type;
2641 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2643 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2644 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2645 HeapFree(GetProcessHeap(),0,ValueNameA);
2647 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2648 WARN("Got ret = %ld\n", ret);
2652 /* add space for terminating '\0' */
2653 sz += unicode ? sizeof(WCHAR) : 1;
2657 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2662 /*****************************************************************************
2663 * WINSPOOL_GetDefaultDevMode
2665 * Get a default DevMode values for wineps.
2669 static void WINSPOOL_GetDefaultDevMode(
2671 DWORD buflen, DWORD *needed,
2675 static const char szwps[] = "wineps.drv";
2677 /* fill default DEVMODE - should be read from ppd... */
2678 ZeroMemory( &dm, sizeof(dm) );
2679 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2680 dm.dmSpecVersion = DM_SPECVERSION;
2681 dm.dmDriverVersion = 1;
2682 dm.dmSize = sizeof(DEVMODEA);
2683 dm.dmDriverExtra = 0;
2685 DM_ORIENTATION | DM_PAPERSIZE |
2686 DM_PAPERLENGTH | DM_PAPERWIDTH |
2689 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2690 DM_YRESOLUTION | DM_TTOPTION;
2692 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2693 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2694 dm.u1.s1.dmPaperLength = 2970;
2695 dm.u1.s1.dmPaperWidth = 2100;
2699 dm.dmDefaultSource = DMBIN_AUTO;
2700 dm.dmPrintQuality = DMRES_MEDIUM;
2703 dm.dmYResolution = 300; /* 300dpi */
2704 dm.dmTTOption = DMTT_BITMAP;
2707 /* dm.dmLogPixels */
2708 /* dm.dmBitsPerPel */
2709 /* dm.dmPelsWidth */
2710 /* dm.dmPelsHeight */
2711 /* dm.dmDisplayFlags */
2712 /* dm.dmDisplayFrequency */
2713 /* dm.dmICMMethod */
2714 /* dm.dmICMIntent */
2715 /* dm.dmMediaType */
2716 /* dm.dmDitherType */
2717 /* dm.dmReserved1 */
2718 /* dm.dmReserved2 */
2719 /* dm.dmPanningWidth */
2720 /* dm.dmPanningHeight */
2723 if(buflen >= sizeof(DEVMODEW)) {
2724 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2725 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2726 HeapFree(GetProcessHeap(),0,pdmW);
2728 *needed = sizeof(DEVMODEW);
2732 if(buflen >= sizeof(DEVMODEA)) {
2733 memcpy(ptr, &dm, sizeof(DEVMODEA));
2735 *needed = sizeof(DEVMODEA);
2739 /*****************************************************************************
2740 * WINSPOOL_GetDevModeFromReg
2742 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2743 * DevMode is stored either as unicode or ascii.
2745 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2747 DWORD buflen, DWORD *needed,
2750 DWORD sz = buflen, type;
2753 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2754 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2755 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2756 if (sz < sizeof(DEVMODEA))
2758 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2761 /* ensures that dmSize is not erratically bogus if registry is invalid */
2762 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2763 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2765 sz += (CCHDEVICENAME + CCHFORMNAME);
2767 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2768 memcpy(ptr, dmW, sz);
2769 HeapFree(GetProcessHeap(),0,dmW);
2776 /*********************************************************************
2777 * WINSPOOL_GetPrinter_2
2779 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2780 * The strings are either stored as unicode or ascii.
2782 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2783 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2786 DWORD size, left = cbBuf;
2787 BOOL space = (cbBuf > 0);
2792 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2794 if(space && size <= left) {
2795 pi2->pPrinterName = (LPWSTR)ptr;
2802 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2804 if(space && size <= left) {
2805 pi2->pShareName = (LPWSTR)ptr;
2812 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2814 if(space && size <= left) {
2815 pi2->pPortName = (LPWSTR)ptr;
2822 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2824 if(space && size <= left) {
2825 pi2->pDriverName = (LPWSTR)ptr;
2832 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2834 if(space && size <= left) {
2835 pi2->pComment = (LPWSTR)ptr;
2842 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2844 if(space && size <= left) {
2845 pi2->pLocation = (LPWSTR)ptr;
2852 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2854 if(space && size <= left) {
2855 pi2->pDevMode = (LPDEVMODEW)ptr;
2864 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2865 if(space && size <= left) {
2866 pi2->pDevMode = (LPDEVMODEW)ptr;
2873 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2875 if(space && size <= left) {
2876 pi2->pSepFile = (LPWSTR)ptr;
2883 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2885 if(space && size <= left) {
2886 pi2->pPrintProcessor = (LPWSTR)ptr;
2893 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2895 if(space && size <= left) {
2896 pi2->pDatatype = (LPWSTR)ptr;
2903 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2905 if(space && size <= left) {
2906 pi2->pParameters = (LPWSTR)ptr;
2914 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2915 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2916 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2917 "Default Priority");
2918 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2919 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2922 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2923 memset(pi2, 0, sizeof(*pi2));
2928 /*********************************************************************
2929 * WINSPOOL_GetPrinter_4
2931 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2933 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2934 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2937 DWORD size, left = cbBuf;
2938 BOOL space = (cbBuf > 0);
2943 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2945 if(space && size <= left) {
2946 pi4->pPrinterName = (LPWSTR)ptr;
2954 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2957 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2958 memset(pi4, 0, sizeof(*pi4));
2963 /*********************************************************************
2964 * WINSPOOL_GetPrinter_5
2966 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2968 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2969 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2972 DWORD size, left = cbBuf;
2973 BOOL space = (cbBuf > 0);
2978 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2980 if(space && size <= left) {
2981 pi5->pPrinterName = (LPWSTR)ptr;
2988 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2990 if(space && size <= left) {
2991 pi5->pPortName = (LPWSTR)ptr;
2999 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3000 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3002 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3006 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3007 memset(pi5, 0, sizeof(*pi5));
3012 /*****************************************************************************
3013 * WINSPOOL_GetPrinter
3015 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3016 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3017 * just a collection of pointers to strings.
3019 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3020 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3023 DWORD size, needed = 0;
3025 HKEY hkeyPrinter, hkeyPrinters;
3028 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3030 if (!(name = get_opened_printer_name(hPrinter))) {
3031 SetLastError(ERROR_INVALID_HANDLE);
3035 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3037 ERR("Can't create Printers key\n");
3040 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3042 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3043 RegCloseKey(hkeyPrinters);
3044 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3051 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3053 size = sizeof(PRINTER_INFO_2W);
3055 ptr = pPrinter + size;
3057 memset(pPrinter, 0, size);
3062 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3070 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3072 size = sizeof(PRINTER_INFO_4W);
3074 ptr = pPrinter + size;
3076 memset(pPrinter, 0, size);
3081 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3090 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3092 size = sizeof(PRINTER_INFO_5W);
3094 ptr = pPrinter + size;
3096 memset(pPrinter, 0, size);
3102 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3109 FIXME("Unimplemented level %ld\n", Level);
3110 SetLastError(ERROR_INVALID_LEVEL);
3111 RegCloseKey(hkeyPrinters);
3112 RegCloseKey(hkeyPrinter);
3116 RegCloseKey(hkeyPrinter);
3117 RegCloseKey(hkeyPrinters);
3119 TRACE("returning %d needed = %ld\n", ret, needed);
3120 if(pcbNeeded) *pcbNeeded = needed;
3122 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3126 /*****************************************************************************
3127 * GetPrinterW [WINSPOOL.@]
3129 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3130 DWORD cbBuf, LPDWORD pcbNeeded)
3132 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3136 /*****************************************************************************
3137 * GetPrinterA [WINSPOOL.@]
3139 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3140 DWORD cbBuf, LPDWORD pcbNeeded)
3142 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3146 /*****************************************************************************
3147 * WINSPOOL_EnumPrinters
3149 * Implementation of EnumPrintersA|W
3151 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3152 DWORD dwLevel, LPBYTE lpbPrinters,
3153 DWORD cbBuf, LPDWORD lpdwNeeded,
3154 LPDWORD lpdwReturned, BOOL unicode)
3157 HKEY hkeyPrinters, hkeyPrinter;
3158 WCHAR PrinterName[255];
3159 DWORD needed = 0, number = 0;
3160 DWORD used, i, left;
3164 memset(lpbPrinters, 0, cbBuf);
3170 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3171 if(dwType == PRINTER_ENUM_DEFAULT)
3174 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3175 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3176 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3177 if(!dwType) return TRUE;
3180 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3181 FIXME("dwType = %08lx\n", dwType);
3182 SetLastError(ERROR_INVALID_FLAGS);
3186 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3188 ERR("Can't create Printers key\n");
3192 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3193 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3194 RegCloseKey(hkeyPrinters);
3195 ERR("Can't query Printers key\n");
3198 TRACE("Found %ld printers\n", number);
3202 RegCloseKey(hkeyPrinters);
3204 *lpdwReturned = number;
3208 used = number * sizeof(PRINTER_INFO_2W);
3211 used = number * sizeof(PRINTER_INFO_4W);
3214 used = number * sizeof(PRINTER_INFO_5W);
3218 SetLastError(ERROR_INVALID_LEVEL);
3219 RegCloseKey(hkeyPrinters);
3222 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3224 for(i = 0; i < number; i++) {
3225 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3227 ERR("Can't enum key number %ld\n", i);
3228 RegCloseKey(hkeyPrinters);
3231 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3232 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3234 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3235 RegCloseKey(hkeyPrinters);
3240 buf = lpbPrinters + used;
3241 left = cbBuf - used;
3249 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3250 left, &needed, unicode);
3252 if(pi) pi += sizeof(PRINTER_INFO_2W);
3255 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3256 left, &needed, unicode);
3258 if(pi) pi += sizeof(PRINTER_INFO_4W);
3261 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3262 left, &needed, unicode);
3264 if(pi) pi += sizeof(PRINTER_INFO_5W);
3267 ERR("Shouldn't be here!\n");
3268 RegCloseKey(hkeyPrinter);
3269 RegCloseKey(hkeyPrinters);
3272 RegCloseKey(hkeyPrinter);
3274 RegCloseKey(hkeyPrinters);
3281 memset(lpbPrinters, 0, cbBuf);
3282 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3286 *lpdwReturned = number;
3287 SetLastError(ERROR_SUCCESS);
3292 /******************************************************************
3293 * EnumPrintersW [WINSPOOL.@]
3295 * Enumerates the available printers, print servers and print
3296 * providers, depending on the specified flags, name and level.
3300 * If level is set to 1:
3301 * Not implemented yet!
3302 * Returns TRUE with an empty list.
3304 * If level is set to 2:
3305 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3306 * Returns an array of PRINTER_INFO_2 data structures in the
3307 * lpbPrinters buffer. Note that according to MSDN also an
3308 * OpenPrinter should be performed on every remote printer.
3310 * If level is set to 4 (officially WinNT only):
3311 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3312 * Fast: Only the registry is queried to retrieve printer names,
3313 * no connection to the driver is made.
3314 * Returns an array of PRINTER_INFO_4 data structures in the
3315 * lpbPrinters buffer.
3317 * If level is set to 5 (officially WinNT4/Win9x only):
3318 * Fast: Only the registry is queried to retrieve printer names,
3319 * no connection to the driver is made.
3320 * Returns an array of PRINTER_INFO_5 data structures in the
3321 * lpbPrinters buffer.
3323 * If level set to 3 or 6+:
3324 * returns zero (failure!)
3326 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3330 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3331 * - Only levels 2, 4 and 5 are implemented at the moment.
3332 * - 16-bit printer drivers are not enumerated.
3333 * - Returned amount of bytes used/needed does not match the real Windoze
3334 * implementation (as in this implementation, all strings are part
3335 * of the buffer, whereas Win32 keeps them somewhere else)
3336 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3339 * - In a regular Wine installation, no registry settings for printers
3340 * exist, which makes this function return an empty list.
3342 BOOL WINAPI EnumPrintersW(
3343 DWORD dwType, /* [in] Types of print objects to enumerate */
3344 LPWSTR lpszName, /* [in] name of objects to enumerate */
3345 DWORD dwLevel, /* [in] type of printer info structure */
3346 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3347 DWORD cbBuf, /* [in] max size of buffer in bytes */
3348 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3349 LPDWORD lpdwReturned /* [out] number of entries returned */
3352 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3353 lpdwNeeded, lpdwReturned, TRUE);
3356 /******************************************************************
3357 * EnumPrintersA [WINSPOOL.@]
3360 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3361 DWORD dwLevel, LPBYTE lpbPrinters,
3362 DWORD cbBuf, LPDWORD lpdwNeeded,
3363 LPDWORD lpdwReturned)
3366 UNICODE_STRING lpszNameW;
3369 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3370 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3371 lpdwNeeded, lpdwReturned, FALSE);
3372 RtlFreeUnicodeString(&lpszNameW);
3376 /*****************************************************************************
3377 * WINSPOOL_GetDriverInfoFromReg [internal]
3379 * Enters the information from the registry into the DRIVER_INFO struct
3382 * zero if the printer driver does not exist in the registry
3383 * (only if Level > 1) otherwise nonzero
3385 static BOOL WINSPOOL_GetDriverInfoFromReg(
3388 LPWSTR pEnvironment,
3390 LPBYTE ptr, /* DRIVER_INFO */
3391 LPBYTE pDriverStrings, /* strings buffer */
3392 DWORD cbBuf, /* size of string buffer */
3393 LPDWORD pcbNeeded, /* space needed for str. */
3394 BOOL unicode) /* type of strings */
3398 LPBYTE strPtr = pDriverStrings;
3400 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3401 debugstr_w(DriverName), debugstr_w(pEnvironment),
3402 Level, ptr, pDriverStrings, cbBuf, unicode);
3405 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3406 if (*pcbNeeded <= cbBuf)
3407 strcpyW((LPWSTR)strPtr, DriverName);
3409 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3411 if(*pcbNeeded <= cbBuf)
3412 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3413 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3417 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3421 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3422 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3425 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3426 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3427 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3432 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3435 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3437 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3439 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3442 if(*pcbNeeded <= cbBuf) {
3444 strcpyW((LPWSTR)strPtr, pEnvironment);
3446 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3447 (LPSTR)strPtr, size, NULL, NULL);
3449 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3450 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3453 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3456 if(*pcbNeeded <= cbBuf)
3457 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3460 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3461 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3464 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3467 if(*pcbNeeded <= cbBuf)
3468 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3471 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3472 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3475 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3476 0, &size, unicode)) {
3478 if(*pcbNeeded <= cbBuf)
3479 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3480 size, &tmp, unicode);
3482 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3483 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3487 RegCloseKey(hkeyDriver);
3488 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3492 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3495 if(*pcbNeeded <= cbBuf)
3496 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3497 size, &tmp, unicode);
3499 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3500 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3503 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3506 if(*pcbNeeded <= cbBuf)
3507 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3508 size, &tmp, unicode);
3510 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3511 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3514 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3517 if(*pcbNeeded <= cbBuf)
3518 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3519 size, &tmp, unicode);
3521 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3522 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3525 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3528 if(*pcbNeeded <= cbBuf)
3529 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3530 size, &tmp, unicode);
3532 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3533 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3536 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3537 RegCloseKey(hkeyDriver);
3541 /*****************************************************************************
3542 * WINSPOOL_GetPrinterDriver
3544 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3545 DWORD Level, LPBYTE pDriverInfo,
3546 DWORD cbBuf, LPDWORD pcbNeeded,
3550 WCHAR DriverName[100];
3551 DWORD ret, type, size, needed = 0;
3553 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3555 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3556 Level,pDriverInfo,cbBuf, pcbNeeded);
3558 ZeroMemory(pDriverInfo, cbBuf);
3560 if (!(name = get_opened_printer_name(hPrinter))) {
3561 SetLastError(ERROR_INVALID_HANDLE);
3564 if(Level < 1 || Level > 6) {
3565 SetLastError(ERROR_INVALID_LEVEL);
3568 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3570 ERR("Can't create Printers key\n");
3573 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3575 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3576 RegCloseKey(hkeyPrinters);
3577 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3580 size = sizeof(DriverName);
3582 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3583 (LPBYTE)DriverName, &size);
3584 RegCloseKey(hkeyPrinter);
3585 RegCloseKey(hkeyPrinters);
3586 if(ret != ERROR_SUCCESS) {
3587 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3591 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3593 ERR("Can't create Drivers key\n");
3599 size = sizeof(DRIVER_INFO_1W);
3602 size = sizeof(DRIVER_INFO_2W);
3605 size = sizeof(DRIVER_INFO_3W);
3608 size = sizeof(DRIVER_INFO_4W);
3611 size = sizeof(DRIVER_INFO_5W);
3614 size = sizeof(DRIVER_INFO_6W);
3617 ERR("Invalid level\n");
3622 ptr = pDriverInfo + size;
3624 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3625 pEnvironment, Level, pDriverInfo,
3626 (cbBuf < size) ? NULL : ptr,
3627 (cbBuf < size) ? 0 : cbBuf - size,
3628 &needed, unicode)) {
3629 RegCloseKey(hkeyDrivers);
3633 RegCloseKey(hkeyDrivers);
3635 if(pcbNeeded) *pcbNeeded = size + needed;
3636 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3637 if(cbBuf >= needed) return TRUE;
3638 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3642 /*****************************************************************************
3643 * GetPrinterDriverA [WINSPOOL.@]
3645 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3646 DWORD Level, LPBYTE pDriverInfo,
3647 DWORD cbBuf, LPDWORD pcbNeeded)
3650 UNICODE_STRING pEnvW;
3653 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3654 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3655 cbBuf, pcbNeeded, FALSE);
3656 RtlFreeUnicodeString(&pEnvW);
3659 /*****************************************************************************
3660 * GetPrinterDriverW [WINSPOOL.@]
3662 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3663 DWORD Level, LPBYTE pDriverInfo,
3664 DWORD cbBuf, LPDWORD pcbNeeded)
3666 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3667 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3670 /*****************************************************************************
3671 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3673 * Return the PATH for the Printer-Drivers (UNICODE)
3676 * pName [I] Servername (NT only) or NULL (local Computer)
3677 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3678 * Level [I] Structure-Level (must be 1)
3679 * pDriverDirectory [O] PTR to Buffer that receives the Result
3680 * cbBuf [I] Size of Buffer at pDriverDirectory
3681 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3682 * required for pDriverDirectory
3685 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3686 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3687 * if cbBuf is too small
3689 * Native Values returned in pDriverDirectory on Success:
3690 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3691 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3692 *| win9x(Windows 4.0): "%winsysdir%"
3694 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3697 *- Only NULL or "" is supported for pName
3700 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3701 DWORD Level, LPBYTE pDriverDirectory,
3702 DWORD cbBuf, LPDWORD pcbNeeded)
3705 const printenv_t * env;
3707 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3708 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3709 if(pName != NULL && pName[0]) {
3710 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3711 SetLastError(ERROR_INVALID_PARAMETER);
3715 env = validate_envW(pEnvironment);
3716 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3719 WARN("(Level: %ld) is ignored in win9x\n", Level);
3720 SetLastError(ERROR_INVALID_LEVEL);
3724 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3725 needed = GetSystemDirectoryW(NULL, 0);
3726 /* add the Size for the Subdirectories */
3727 needed += lstrlenW(spooldriversW);
3728 needed += lstrlenW(env->subdir);
3729 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3732 *pcbNeeded = needed;
3733 TRACE("required: 0x%lx/%ld\n", needed, needed);
3734 if(needed > cbBuf) {
3735 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3738 if(pcbNeeded == NULL) {
3739 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3740 SetLastError(RPC_X_NULL_REF_POINTER);
3743 if(pDriverDirectory == NULL) {
3744 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3745 SetLastError(ERROR_INVALID_USER_BUFFER);
3749 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3750 /* add the Subdirectories */
3751 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3752 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3753 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3758 /*****************************************************************************
3759 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3761 * Return the PATH for the Printer-Drivers (ANSI)
3763 * See GetPrinterDriverDirectoryW.
3766 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3769 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3770 DWORD Level, LPBYTE pDriverDirectory,
3771 DWORD cbBuf, LPDWORD pcbNeeded)
3773 UNICODE_STRING nameW, environmentW;
3776 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3777 WCHAR *driverDirectoryW = NULL;
3779 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3780 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3782 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3784 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3785 else nameW.Buffer = NULL;
3786 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3787 else environmentW.Buffer = NULL;
3789 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3790 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3793 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3794 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3796 *pcbNeeded = needed;
3797 ret = (needed <= cbBuf) ? TRUE : FALSE;
3799 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3801 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3803 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3804 RtlFreeUnicodeString(&environmentW);
3805 RtlFreeUnicodeString(&nameW);
3810 /*****************************************************************************
3811 * AddPrinterDriverA [WINSPOOL.@]
3813 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3816 HKEY hkeyDrivers, hkeyName;
3818 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3820 if(level != 2 && level != 3) {
3821 SetLastError(ERROR_INVALID_LEVEL);
3825 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3826 SetLastError(ERROR_INVALID_PARAMETER);
3830 WARN("pDriverInfo == NULL\n");
3831 SetLastError(ERROR_INVALID_PARAMETER);
3836 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3838 memset(&di3, 0, sizeof(di3));
3839 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3842 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3844 SetLastError(ERROR_INVALID_PARAMETER);
3847 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3848 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3849 if(!di3.pHelpFile) di3.pHelpFile = "";
3850 if(!di3.pMonitorName) di3.pMonitorName = "";
3852 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3855 ERR("Can't create Drivers key\n");
3859 if(level == 2) { /* apparently can't overwrite with level2 */
3860 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3861 RegCloseKey(hkeyName);
3862 RegCloseKey(hkeyDrivers);
3863 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3864 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3868 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3869 RegCloseKey(hkeyDrivers);
3870 ERR("Can't create Name key\n");
3873 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3875 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3876 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3877 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3879 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3880 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3881 (LPBYTE) di3.pDependentFiles, 0);
3882 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3883 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3884 RegCloseKey(hkeyName);
3885 RegCloseKey(hkeyDrivers);
3890 /*****************************************************************************
3891 * AddPrinterDriverW [WINSPOOL.@]
3893 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3896 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3901 /*****************************************************************************
3902 * AddPrintProcessorA [WINSPOOL.@]
3904 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3905 LPSTR pPrintProcessorName)
3907 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3908 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3912 /*****************************************************************************
3913 * AddPrintProcessorW [WINSPOOL.@]
3915 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3916 LPWSTR pPrintProcessorName)
3918 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3919 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3923 /*****************************************************************************
3924 * AddPrintProvidorA [WINSPOOL.@]
3926 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3928 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3932 /*****************************************************************************
3933 * AddPrintProvidorW [WINSPOOL.@]
3935 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3937 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3941 /*****************************************************************************
3942 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3944 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3945 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3947 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3948 pDevModeOutput, pDevModeInput);
3952 /*****************************************************************************
3953 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3955 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3956 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3958 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3959 pDevModeOutput, pDevModeInput);
3963 /*****************************************************************************
3964 * PrinterProperties [WINSPOOL.@]
3966 * Displays a dialog to set the properties of the printer.
3969 * nonzero on success or zero on failure
3972 * implemented as stub only
3974 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3975 HANDLE hPrinter /* [in] handle to printer object */
3977 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3978 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3982 /*****************************************************************************
3983 * EnumJobsA [WINSPOOL.@]
3986 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3987 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3990 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3991 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3993 if(pcbNeeded) *pcbNeeded = 0;
3994 if(pcReturned) *pcReturned = 0;
3999 /*****************************************************************************
4000 * EnumJobsW [WINSPOOL.@]
4003 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4004 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4007 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4008 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4010 if(pcbNeeded) *pcbNeeded = 0;
4011 if(pcReturned) *pcReturned = 0;
4015 /*****************************************************************************
4016 * WINSPOOL_EnumPrinterDrivers [internal]
4018 * Delivers information about all printer drivers installed on the
4019 * localhost or a given server
4022 * nonzero on success or zero on failure. If the buffer for the returned
4023 * information is too small the function will return an error
4026 * - only implemented for localhost, foreign hosts will return an error
4028 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4029 DWORD Level, LPBYTE pDriverInfo,
4030 DWORD cbBuf, LPDWORD pcbNeeded,
4031 LPDWORD pcReturned, BOOL unicode)
4034 DWORD i, needed, number = 0, size = 0;
4035 WCHAR DriverNameW[255];
4038 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4039 debugstr_w(pName), debugstr_w(pEnvironment),
4040 Level, pDriverInfo, cbBuf, unicode);
4042 /* check for local drivers */
4043 if((pName) && (pName[0])) {
4044 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4045 SetLastError(ERROR_ACCESS_DENIED);
4049 /* check input parameter */
4050 if((Level < 1) || (Level > 3)) {
4051 ERR("unsupported level %ld\n", Level);
4052 SetLastError(ERROR_INVALID_LEVEL);
4056 /* initialize return values */
4058 memset( pDriverInfo, 0, cbBuf);
4062 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4064 ERR("Can't open Drivers key\n");
4068 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4069 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4070 RegCloseKey(hkeyDrivers);
4071 ERR("Can't query Drivers key\n");
4074 TRACE("Found %ld Drivers\n", number);
4076 /* get size of single struct
4077 * unicode and ascii structure have the same size
4081 size = sizeof(DRIVER_INFO_1A);
4084 size = sizeof(DRIVER_INFO_2A);
4087 size = sizeof(DRIVER_INFO_3A);
4091 /* calculate required buffer size */
4092 *pcbNeeded = size * number;
4094 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4096 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4097 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4099 ERR("Can't enum key number %ld\n", i);
4100 RegCloseKey(hkeyDrivers);
4103 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4104 pEnvironment, Level, ptr,
4105 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4106 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4107 &needed, unicode)) {
4108 RegCloseKey(hkeyDrivers);
4111 (*pcbNeeded) += needed;
4114 RegCloseKey(hkeyDrivers);
4116 if(cbBuf < *pcbNeeded){
4117 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4121 *pcReturned = number;
4125 /*****************************************************************************
4126 * EnumPrinterDriversW [WINSPOOL.@]
4128 * see function EnumPrinterDrivers for RETURNS, BUGS
4130 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4131 LPBYTE pDriverInfo, DWORD cbBuf,
4132 LPDWORD pcbNeeded, LPDWORD pcReturned)
4134 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4135 cbBuf, pcbNeeded, pcReturned, TRUE);
4138 /*****************************************************************************
4139 * EnumPrinterDriversA [WINSPOOL.@]
4141 * see function EnumPrinterDrivers for RETURNS, BUGS
4143 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4144 LPBYTE pDriverInfo, DWORD cbBuf,
4145 LPDWORD pcbNeeded, LPDWORD pcReturned)
4147 UNICODE_STRING pNameW, pEnvironmentW;
4148 PWSTR pwstrNameW, pwstrEnvironmentW;
4150 pwstrNameW = asciitounicode(&pNameW, pName);
4151 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4153 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4154 Level, pDriverInfo, cbBuf, pcbNeeded,
4156 RtlFreeUnicodeString(&pNameW);
4157 RtlFreeUnicodeString(&pEnvironmentW);
4162 static CHAR PortMonitor[] = "Wine Port Monitor";
4163 static CHAR PortDescription[] = "Wine Port";
4165 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4169 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4170 NULL, OPEN_EXISTING, 0, NULL );
4171 if (handle == INVALID_HANDLE_VALUE)
4173 TRACE("Checking %s exists\n", name );
4174 CloseHandle( handle );
4178 static DWORD WINSPOOL_CountSerialPorts(void)
4185 strcpy( name, "COMx:" );
4187 if (WINSPOOL_ComPortExists( name ))
4194 /******************************************************************************
4195 * EnumPortsA (WINSPOOL.@)
4200 * ANSI-Version did not call the UNICODE-Version
4203 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4204 LPDWORD bufneeded,LPDWORD bufreturned)
4207 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4208 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4212 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4213 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4218 info_size = sizeof (PORT_INFO_1A);
4221 info_size = sizeof (PORT_INFO_2A);
4224 SetLastError(ERROR_INVALID_LEVEL);
4228 /* see how many exist */
4231 serial_count = WINSPOOL_CountSerialPorts();
4234 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4235 if ( r == ERROR_SUCCESS )
4237 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4238 &printer_count, NULL, NULL, NULL, NULL);
4240 count = serial_count + printer_count;
4242 /* then fill in the structure info structure once
4243 we know the offset to the first string */
4245 memset( buffer, 0, bufsize );
4247 ofs = info_size*count;
4248 for ( i=0; i<count; i++)
4250 DWORD vallen = sizeof(portname) - 1;
4252 /* get the serial port values, then the printer values */
4253 if ( i < serial_count )
4255 strcpy( portname, "COMx:" );
4256 portname[3] = '1' + i;
4257 if (!WINSPOOL_ComPortExists( portname ))
4260 TRACE("Found %s\n", portname );
4261 vallen = strlen( portname );
4265 r = RegEnumValueA( hkey_printer, i-serial_count,
4266 portname, &vallen, NULL, NULL, NULL, 0 );
4271 /* add a colon if necessary, and make it upper case */
4272 CharUpperBuffA(portname,vallen);
4273 if (strcasecmp(portname,"nul")!=0)
4274 if (vallen && (portname[vallen-1] != ':') )
4275 lstrcatA(portname,":");
4277 /* add the port info structure if we can fit it */
4278 if ( info_size*(n+1) < bufsize )
4282 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4283 info->pName = (LPSTR) &buffer[ofs];
4285 else if ( level == 2)
4287 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4288 info->pPortName = (LPSTR) &buffer[ofs];
4289 /* FIXME: fill in more stuff here */
4290 info->pMonitorName = PortMonitor;
4291 info->pDescription = PortDescription;
4292 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4295 /* add the name of the port if we can fit it */
4296 if ( ofs < bufsize )
4297 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4303 ofs += lstrlenA(portname)+1;
4306 RegCloseKey(hkey_printer);
4317 /******************************************************************************
4318 * EnumPortsW (WINSPOOL.@)
4320 * Enumerate available Ports
4323 * name [I] Servername or NULL (local Computer)
4324 * level [I] Structure-Level (1 or 2)
4325 * buffer [O] PTR to Buffer that receives the Result
4326 * bufsize [I] Size of Buffer at buffer
4327 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4328 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4332 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4335 * UNICODE-Version is a stub
4338 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4339 LPDWORD bufneeded,LPDWORD bufreturned)
4341 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4342 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4346 /******************************************************************************
4347 * GetDefaultPrinterW (WINSPOOL.@)
4350 * This function must read the value from data 'device' of key
4351 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4353 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4357 WCHAR *buffer, *ptr;
4361 SetLastError(ERROR_INVALID_PARAMETER);
4365 /* make the buffer big enough for the stuff from the profile/registry,
4366 * the content must fit into the local buffer to compute the correct
4367 * size even if the extern buffer is too small or not given.
4368 * (20 for ,driver,port) */
4370 len = max(100, (insize + 20));
4371 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4373 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4375 SetLastError (ERROR_FILE_NOT_FOUND);
4379 TRACE("%s\n", debugstr_w(buffer));
4381 if ((ptr = strchrW(buffer, ',')) == NULL)
4383 SetLastError(ERROR_INVALID_NAME);
4389 *namesize = strlenW(buffer) + 1;
4390 if(!name || (*namesize > insize))
4392 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4396 strcpyW(name, buffer);
4399 HeapFree( GetProcessHeap(), 0, buffer);
4404 /******************************************************************************
4405 * GetDefaultPrinterA (WINSPOOL.@)
4407 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4411 WCHAR *bufferW = NULL;
4415 SetLastError(ERROR_INVALID_PARAMETER);
4419 if(name && *namesize) {
4421 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4424 if(!GetDefaultPrinterW( bufferW, namesize)) {
4429 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4433 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4436 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4439 HeapFree( GetProcessHeap(), 0, bufferW);
4444 /******************************************************************************
4445 * SetDefaultPrinterW (WINSPOOL.204)
4447 * Set the Name of the Default Printer
4450 * pszPrinter [I] Name of the Printer or NULL
4457 * When the Parameter is NULL or points to an Empty String and
4458 * a Default Printer was already present, then this Function changes nothing.
4459 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4460 * the First enumerated local Printer is used.
4463 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4466 TRACE("(%s)\n", debugstr_w(pszPrinter));
4468 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4472 /******************************************************************************
4473 * SetDefaultPrinterA (WINSPOOL.202)
4475 * See SetDefaultPrinterW.
4478 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4481 TRACE("(%s)\n", debugstr_a(pszPrinter));
4483 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4488 /******************************************************************************
4489 * SetPrinterDataExA (WINSPOOL.@)
4491 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4492 LPCSTR pValueName, DWORD Type,
4493 LPBYTE pData, DWORD cbData)
4495 HKEY hkeyPrinter, hkeySubkey;
4498 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4499 debugstr_a(pValueName), Type, pData, cbData);
4501 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4505 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4507 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4508 RegCloseKey(hkeyPrinter);
4511 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4512 RegCloseKey(hkeySubkey);
4513 RegCloseKey(hkeyPrinter);
4517 /******************************************************************************
4518 * SetPrinterDataExW (WINSPOOL.@)
4520 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4521 LPCWSTR pValueName, DWORD Type,
4522 LPBYTE pData, DWORD cbData)
4524 HKEY hkeyPrinter, hkeySubkey;
4527 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4528 debugstr_w(pValueName), Type, pData, cbData);
4530 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4534 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4536 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4537 RegCloseKey(hkeyPrinter);
4540 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4541 RegCloseKey(hkeySubkey);
4542 RegCloseKey(hkeyPrinter);
4546 /******************************************************************************
4547 * SetPrinterDataA (WINSPOOL.@)
4549 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4550 LPBYTE pData, DWORD cbData)
4552 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4556 /******************************************************************************
4557 * SetPrinterDataW (WINSPOOL.@)
4559 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4560 LPBYTE pData, DWORD cbData)
4562 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4566 /******************************************************************************
4567 * GetPrinterDataExA (WINSPOOL.@)
4569 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4570 LPCSTR pValueName, LPDWORD pType,
4571 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4573 HKEY hkeyPrinter, hkeySubkey;
4576 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4577 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4580 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4584 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4586 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4587 RegCloseKey(hkeyPrinter);
4591 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4592 RegCloseKey(hkeySubkey);
4593 RegCloseKey(hkeyPrinter);
4597 /******************************************************************************
4598 * GetPrinterDataExW (WINSPOOL.@)
4600 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4601 LPCWSTR pValueName, LPDWORD pType,
4602 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4604 HKEY hkeyPrinter, hkeySubkey;
4607 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4608 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4611 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4615 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4617 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4618 RegCloseKey(hkeyPrinter);
4622 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4623 RegCloseKey(hkeySubkey);
4624 RegCloseKey(hkeyPrinter);
4628 /******************************************************************************
4629 * GetPrinterDataA (WINSPOOL.@)
4631 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4632 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4634 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4635 pData, nSize, pcbNeeded);
4638 /******************************************************************************
4639 * GetPrinterDataW (WINSPOOL.@)
4641 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4642 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4644 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4645 pData, nSize, pcbNeeded);
4648 /*******************************************************************************
4649 * EnumPrinterDataExW [WINSPOOL.@]
4651 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4652 LPBYTE pEnumValues, DWORD cbEnumValues,
4653 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4655 HKEY hkPrinter, hkSubKey;
4656 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4657 cbValueNameLen, cbMaxValueLen, cbValueLen,
4662 PPRINTER_ENUM_VALUESW ppev;
4664 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4666 if (pKeyName == NULL || *pKeyName == 0)
4667 return ERROR_INVALID_PARAMETER;
4669 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4670 if (ret != ERROR_SUCCESS)
4672 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4677 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4678 if (ret != ERROR_SUCCESS)
4680 r = RegCloseKey (hkPrinter);
4681 if (r != ERROR_SUCCESS)
4682 WARN ("RegCloseKey returned %li\n", r);
4683 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4684 debugstr_w (pKeyName), ret);
4688 ret = RegCloseKey (hkPrinter);
4689 if (ret != ERROR_SUCCESS)
4691 ERR ("RegCloseKey returned %li\n", ret);
4692 r = RegCloseKey (hkSubKey);
4693 if (r != ERROR_SUCCESS)
4694 WARN ("RegCloseKey returned %li\n", r);
4698 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4699 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4700 if (ret != ERROR_SUCCESS)
4702 r = RegCloseKey (hkSubKey);
4703 if (r != ERROR_SUCCESS)
4704 WARN ("RegCloseKey returned %li\n", r);
4705 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4709 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4710 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4712 if (cValues == 0) /* empty key */
4714 r = RegCloseKey (hkSubKey);
4715 if (r != ERROR_SUCCESS)
4716 WARN ("RegCloseKey returned %li\n", r);
4717 *pcbEnumValues = *pnEnumValues = 0;
4718 return ERROR_SUCCESS;
4721 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4723 hHeap = GetProcessHeap ();
4726 ERR ("GetProcessHeap failed\n");
4727 r = RegCloseKey (hkSubKey);
4728 if (r != ERROR_SUCCESS)
4729 WARN ("RegCloseKey returned %li\n", r);
4730 return ERROR_OUTOFMEMORY;
4733 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4734 if (lpValueName == NULL)
4736 ERR ("Failed to allocate %li bytes from process heap\n",
4737 cbMaxValueNameLen * sizeof (WCHAR));
4738 r = RegCloseKey (hkSubKey);
4739 if (r != ERROR_SUCCESS)
4740 WARN ("RegCloseKey returned %li\n", r);
4741 return ERROR_OUTOFMEMORY;
4744 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4745 if (lpValue == NULL)
4747 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4748 if (HeapFree (hHeap, 0, lpValueName) == 0)
4749 WARN ("HeapFree failed with code %li\n", GetLastError ());
4750 r = RegCloseKey (hkSubKey);
4751 if (r != ERROR_SUCCESS)
4752 WARN ("RegCloseKey returned %li\n", r);
4753 return ERROR_OUTOFMEMORY;
4756 TRACE ("pass 1: calculating buffer required for all names and values\n");
4758 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4760 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4762 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4764 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4765 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4766 NULL, NULL, lpValue, &cbValueLen);
4767 if (ret != ERROR_SUCCESS)
4769 if (HeapFree (hHeap, 0, lpValue) == 0)
4770 WARN ("HeapFree failed with code %li\n", GetLastError ());
4771 if (HeapFree (hHeap, 0, lpValueName) == 0)
4772 WARN ("HeapFree failed with code %li\n", GetLastError ());
4773 r = RegCloseKey (hkSubKey);
4774 if (r != ERROR_SUCCESS)
4775 WARN ("RegCloseKey returned %li\n", r);
4776 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4780 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4781 debugstr_w (lpValueName), dwIndex,
4782 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4784 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4785 cbBufSize += cbValueLen;
4788 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4790 *pcbEnumValues = cbBufSize;
4791 *pnEnumValues = cValues;
4793 if (cbEnumValues < cbBufSize) /* buffer too small */
4795 if (HeapFree (hHeap, 0, lpValue) == 0)
4796 WARN ("HeapFree failed with code %li\n", GetLastError ());
4797 if (HeapFree (hHeap, 0, lpValueName) == 0)
4798 WARN ("HeapFree failed with code %li\n", GetLastError ());
4799 r = RegCloseKey (hkSubKey);
4800 if (r != ERROR_SUCCESS)
4801 WARN ("RegCloseKey returned %li\n", r);
4802 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4803 return ERROR_MORE_DATA;
4806 TRACE ("pass 2: copying all names and values to buffer\n");
4808 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4809 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4811 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4813 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4814 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4815 NULL, &dwType, lpValue, &cbValueLen);
4816 if (ret != ERROR_SUCCESS)
4818 if (HeapFree (hHeap, 0, lpValue) == 0)
4819 WARN ("HeapFree failed with code %li\n", GetLastError ());
4820 if (HeapFree (hHeap, 0, lpValueName) == 0)
4821 WARN ("HeapFree failed with code %li\n", GetLastError ());
4822 r = RegCloseKey (hkSubKey);
4823 if (r != ERROR_SUCCESS)
4824 WARN ("RegCloseKey returned %li\n", r);
4825 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4829 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4830 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4831 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4832 pEnumValues += cbValueNameLen;
4834 /* return # of *bytes* (including trailing \0), not # of chars */
4835 ppev[dwIndex].cbValueName = cbValueNameLen;
4837 ppev[dwIndex].dwType = dwType;
4839 memcpy (pEnumValues, lpValue, cbValueLen);
4840 ppev[dwIndex].pData = pEnumValues;
4841 pEnumValues += cbValueLen;
4843 ppev[dwIndex].cbData = cbValueLen;
4845 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4846 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4849 if (HeapFree (hHeap, 0, lpValue) == 0)
4851 ret = GetLastError ();
4852 ERR ("HeapFree failed with code %li\n", ret);
4853 if (HeapFree (hHeap, 0, lpValueName) == 0)
4854 WARN ("HeapFree failed with code %li\n", GetLastError ());
4855 r = RegCloseKey (hkSubKey);
4856 if (r != ERROR_SUCCESS)
4857 WARN ("RegCloseKey returned %li\n", r);
4861 if (HeapFree (hHeap, 0, lpValueName) == 0)
4863 ret = GetLastError ();
4864 ERR ("HeapFree failed with code %li\n", ret);
4865 r = RegCloseKey (hkSubKey);
4866 if (r != ERROR_SUCCESS)
4867 WARN ("RegCloseKey returned %li\n", r);
4871 ret = RegCloseKey (hkSubKey);
4872 if (ret != ERROR_SUCCESS)
4874 ERR ("RegCloseKey returned %li\n", ret);
4878 return ERROR_SUCCESS;
4881 /*******************************************************************************
4882 * EnumPrinterDataExA [WINSPOOL.@]
4884 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4885 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4886 * what Windows 2000 SP1 does.
4889 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4890 LPBYTE pEnumValues, DWORD cbEnumValues,
4891 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4895 DWORD ret, dwIndex, dwBufSize;
4899 TRACE ("%p %s\n", hPrinter, pKeyName);
4901 if (pKeyName == NULL || *pKeyName == 0)
4902 return ERROR_INVALID_PARAMETER;
4904 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4907 ret = GetLastError ();
4908 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4912 hHeap = GetProcessHeap ();
4915 ERR ("GetProcessHeap failed\n");
4916 return ERROR_OUTOFMEMORY;
4919 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4920 if (pKeyNameW == NULL)
4922 ERR ("Failed to allocate %li bytes from process heap\n",
4923 (LONG) len * sizeof (WCHAR));
4924 return ERROR_OUTOFMEMORY;
4927 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4929 ret = GetLastError ();
4930 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4931 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4932 WARN ("HeapFree failed with code %li\n", GetLastError ());
4936 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4937 pcbEnumValues, pnEnumValues);
4938 if (ret != ERROR_SUCCESS)
4940 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4941 WARN ("HeapFree failed with code %li\n", GetLastError ());
4942 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4946 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4948 ret = GetLastError ();
4949 ERR ("HeapFree failed with code %li\n", ret);
4953 if (*pnEnumValues == 0) /* empty key */
4954 return ERROR_SUCCESS;
4957 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4959 PPRINTER_ENUM_VALUESW ppev =
4960 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4962 if (dwBufSize < ppev->cbValueName)
4963 dwBufSize = ppev->cbValueName;
4965 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4966 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4967 dwBufSize = ppev->cbData;
4970 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4972 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4973 if (pBuffer == NULL)
4975 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4976 return ERROR_OUTOFMEMORY;
4979 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4981 PPRINTER_ENUM_VALUESW ppev =
4982 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4984 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4985 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4989 ret = GetLastError ();
4990 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4991 if (HeapFree (hHeap, 0, pBuffer) == 0)
4992 WARN ("HeapFree failed with code %li\n", GetLastError ());
4996 memcpy (ppev->pValueName, pBuffer, len);
4998 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5000 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5001 ppev->dwType != REG_MULTI_SZ)
5004 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5005 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5008 ret = GetLastError ();
5009 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5010 if (HeapFree (hHeap, 0, pBuffer) == 0)
5011 WARN ("HeapFree failed with code %li\n", GetLastError ());
5015 memcpy (ppev->pData, pBuffer, len);
5017 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5018 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5021 if (HeapFree (hHeap, 0, pBuffer) == 0)
5023 ret = GetLastError ();
5024 ERR ("HeapFree failed with code %li\n", ret);
5028 return ERROR_SUCCESS;
5031 /******************************************************************************
5032 * AbortPrinter (WINSPOOL.@)
5034 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5036 FIXME("(%p), stub!\n", hPrinter);
5040 /******************************************************************************
5041 * AddPortA (WINSPOOL.@)
5046 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5048 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5052 /******************************************************************************
5053 * AddPortW (WINSPOOL.@)
5055 * Add a Port for a specific Monitor
5058 * pName [I] Servername or NULL (local Computer)
5059 * hWnd [I] Handle to parent Window for the Dialog-Box
5060 * pMonitorName [I] Name of the Monitor that manage the Port
5070 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5072 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5076 /******************************************************************************
5077 * AddPortExA (WINSPOOL.@)
5082 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5084 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5085 lpBuffer, debugstr_a(lpMonitorName));
5089 /******************************************************************************
5090 * AddPortExW (WINSPOOL.@)
5092 * Add a Port for a specific Monitor, without presenting a user interface
5095 * hMonitor [I] Handle from InitializePrintMonitor2()
5096 * pName [I] Servername or NULL (local Computer)
5097 * Level [I] Structure-Level (1 or 2) for lpBuffer
5098 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5099 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5109 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5111 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5112 lpBuffer, debugstr_w(lpMonitorName));
5116 /******************************************************************************
5117 * AddPrinterConnectionA (WINSPOOL.@)
5119 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5121 FIXME("%s\n", debugstr_a(pName));
5125 /******************************************************************************
5126 * AddPrinterConnectionW (WINSPOOL.@)
5128 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5130 FIXME("%s\n", debugstr_w(pName));
5134 /******************************************************************************
5135 * AddPrinterDriverExW (WINSPOOL.@)
5137 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5138 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5140 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5141 Level, pDriverInfo, dwFileCopyFlags);
5142 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5146 /******************************************************************************
5147 * AddPrinterDriverExA (WINSPOOL.@)
5149 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5150 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5152 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5153 Level, pDriverInfo, dwFileCopyFlags);
5154 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5158 /******************************************************************************
5159 * ConfigurePortA (WINSPOOL.@)
5161 * See ConfigurePortW.
5164 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5166 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5170 /******************************************************************************
5171 * ConfigurePortW (WINSPOOL.@)
5173 * Display the Configuration-Dialog for a specific Port
5176 * pName [I] Servername or NULL (local Computer)
5177 * hWnd [I] Handle to parent Window for the Dialog-Box
5178 * pPortName [I] Name of the Port, that should be configured
5188 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5190 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5194 /******************************************************************************
5195 * ConnectToPrinterDlg (WINSPOOL.@)
5197 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5199 FIXME("%p %lx\n", hWnd, Flags);
5203 /******************************************************************************
5204 * DeletePrinterConnectionA (WINSPOOL.@)
5206 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5208 FIXME("%s\n", debugstr_a(pName));
5212 /******************************************************************************
5213 * DeletePrinterConnectionW (WINSPOOL.@)
5215 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5217 FIXME("%s\n", debugstr_w(pName));
5221 /******************************************************************************
5222 * DeletePrinterDriverExW (WINSPOOL.@)
5224 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5225 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5227 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5228 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5232 /******************************************************************************
5233 * DeletePrinterDriverExA (WINSPOOL.@)
5235 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5236 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5238 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5239 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5243 /******************************************************************************
5244 * DeletePrinterDataExW (WINSPOOL.@)
5246 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5249 FIXME("%p %s %s\n", hPrinter,
5250 debugstr_w(pKeyName), debugstr_w(pValueName));
5251 return ERROR_INVALID_PARAMETER;
5254 /******************************************************************************
5255 * DeletePrinterDataExA (WINSPOOL.@)
5257 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5260 FIXME("%p %s %s\n", hPrinter,
5261 debugstr_a(pKeyName), debugstr_a(pValueName));
5262 return ERROR_INVALID_PARAMETER;
5265 /******************************************************************************
5266 * DeletePrintProcessorA (WINSPOOL.@)
5268 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5270 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5271 debugstr_a(pPrintProcessorName));
5275 /******************************************************************************
5276 * DeletePrintProcessorW (WINSPOOL.@)
5278 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5280 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5281 debugstr_w(pPrintProcessorName));
5285 /******************************************************************************
5286 * DeletePrintProvidorA (WINSPOOL.@)
5288 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5290 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5291 debugstr_a(pPrintProviderName));
5295 /******************************************************************************
5296 * DeletePrintProvidorW (WINSPOOL.@)
5298 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5300 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5301 debugstr_w(pPrintProviderName));
5305 /******************************************************************************
5306 * EnumFormsA (WINSPOOL.@)
5308 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5309 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5311 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5315 /******************************************************************************
5316 * EnumFormsW (WINSPOOL.@)
5318 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5319 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5321 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5325 /*****************************************************************************
5326 * EnumMonitorsA [WINSPOOL.@]
5328 * See EnumMonitorsW.
5331 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5332 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5335 LPBYTE bufferW = NULL;
5336 LPWSTR nameW = NULL;
5338 DWORD numentries = 0;
5341 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5342 cbBuf, pcbNeeded, pcReturned);
5344 /* convert servername to unicode */
5346 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5347 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5348 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5350 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5351 needed = cbBuf * sizeof(WCHAR);
5352 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5353 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5355 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5356 if (pcbNeeded) needed = *pcbNeeded;
5357 /* HeapReAlloc return NULL, when bufferW was NULL */
5358 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5359 HeapAlloc(GetProcessHeap(), 0, needed);
5361 /* Try again with the large Buffer */
5362 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5364 numentries = pcReturned ? *pcReturned : 0;
5367 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5368 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5371 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5372 DWORD entrysize = 0;
5375 LPMONITOR_INFO_2W mi2w;
5376 LPMONITOR_INFO_2A mi2a;
5378 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5379 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5381 /* First pass: calculate the size for all Entries */
5382 mi2w = (LPMONITOR_INFO_2W) bufferW;
5383 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5385 while (index < numentries) {
5387 needed += entrysize; /* MONITOR_INFO_?A */
5388 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5390 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5391 NULL, 0, NULL, NULL);
5393 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5394 NULL, 0, NULL, NULL);
5395 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5396 NULL, 0, NULL, NULL);
5398 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5399 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5400 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5403 /* check for errors and quit on failure */
5404 if (cbBuf < needed) {
5405 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5409 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5410 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5411 cbBuf -= len ; /* free Bytes in the user-Buffer */
5412 mi2w = (LPMONITOR_INFO_2W) bufferW;
5413 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5415 /* Second Pass: Fill the User Buffer (if we have one) */
5416 while ((index < numentries) && pMonitors) {
5418 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5420 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5421 ptr, cbBuf , NULL, NULL);
5425 mi2a->pEnvironment = ptr;
5426 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5427 ptr, cbBuf, NULL, NULL);
5431 mi2a->pDLLName = ptr;
5432 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5433 ptr, cbBuf, NULL, NULL);
5437 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5438 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5439 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5443 if (pcbNeeded) *pcbNeeded = needed;
5444 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5446 HeapFree(GetProcessHeap(), 0, nameW);
5447 HeapFree(GetProcessHeap(), 0, bufferW);
5449 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5450 (res), GetLastError(), needed, numentries);
5456 /*****************************************************************************
5457 * EnumMonitorsW [WINSPOOL.@]
5459 * Enumerate available Port-Monitors
5462 * pName [I] Servername or NULL (local Computer)
5463 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5464 * pMonitors [O] PTR to Buffer that receives the Result
5465 * cbBuf [I] Size of Buffer at pMonitors
5466 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5467 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5471 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5474 * Windows reads the Registry once and cache the Results.
5476 *| Language-Monitors are also installed in the same Registry-Location but
5477 *| they are filtered in Windows (not returned by EnumMonitors).
5478 *| We do no filtering to simplify our Code.
5481 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5482 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5485 DWORD numentries = 0;
5488 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5489 cbBuf, pcbNeeded, pcReturned);
5491 if (pName && (lstrlenW(pName))) {
5492 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5493 SetLastError(ERROR_ACCESS_DENIED);
5497 /* Level is not checked in win9x */
5498 if (!Level || (Level > 2)) {
5499 WARN("level (%ld) is ignored in win9x\n", Level);
5500 SetLastError(ERROR_INVALID_LEVEL);
5504 SetLastError(RPC_X_NULL_REF_POINTER);
5508 /* Scan all Monitor-Keys */
5510 needed = get_local_monitors(Level, NULL, 0, &numentries);
5512 /* we calculated the needed buffersize. now do the error-checks */
5513 if (cbBuf < needed) {
5514 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5517 else if (!pMonitors || !pcReturned) {
5518 SetLastError(RPC_X_NULL_REF_POINTER);
5522 /* fill the Buffer with the Monitor-Keys */
5523 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5527 if (pcbNeeded) *pcbNeeded = needed;
5528 if (pcReturned) *pcReturned = numentries;
5530 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5531 res, GetLastError(), needed, numentries);
5536 /******************************************************************************
5537 * XcvDataW (WINSPOOL.@)
5540 * There doesn't seem to be an A version...
5542 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5543 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5544 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5546 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5547 pInputData, cbInputData, pOutputData,
5548 cbOutputData, pcbOutputNeeded, pdwStatus);
5552 /*****************************************************************************
5553 * EnumPrinterDataA [WINSPOOL.@]
5556 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5557 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5558 DWORD cbData, LPDWORD pcbData )
5560 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5561 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5562 return ERROR_NO_MORE_ITEMS;
5565 /*****************************************************************************
5566 * EnumPrinterDataW [WINSPOOL.@]
5569 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5570 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5571 DWORD cbData, LPDWORD pcbData )
5573 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5574 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5575 return ERROR_NO_MORE_ITEMS;
5578 /*****************************************************************************
5579 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5582 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5583 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5584 LPDWORD pcbNeeded, LPDWORD pcReturned)
5586 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5587 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5588 pcbNeeded, pcReturned);
5592 /*****************************************************************************
5593 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5596 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5597 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5598 LPDWORD pcbNeeded, LPDWORD pcReturned)
5600 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5601 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5602 pcbNeeded, pcReturned);
5606 /*****************************************************************************
5607 * EnumPrintProcessorsA [WINSPOOL.@]
5610 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5611 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5613 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5614 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5618 /*****************************************************************************
5619 * EnumPrintProcessorsW [WINSPOOL.@]
5622 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5623 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5625 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5626 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5627 cbBuf, pcbNeeded, pcbReturned);
5631 /*****************************************************************************
5632 * ExtDeviceMode [WINSPOOL.@]
5635 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5636 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5639 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5640 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5641 debugstr_a(pProfile), fMode);
5645 /*****************************************************************************
5646 * FindClosePrinterChangeNotification [WINSPOOL.@]
5649 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5651 FIXME("Stub: %p\n", hChange);
5655 /*****************************************************************************
5656 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5659 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5660 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5662 FIXME("Stub: %p %lx %lx %p\n",
5663 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5664 return INVALID_HANDLE_VALUE;
5667 /*****************************************************************************
5668 * FindNextPrinterChangeNotification [WINSPOOL.@]
5671 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5672 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5674 FIXME("Stub: %p %p %p %p\n",
5675 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5679 /*****************************************************************************
5680 * FreePrinterNotifyInfo [WINSPOOL.@]
5683 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5685 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5689 /*****************************************************************************
5692 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5693 * ansi depending on the unicode parameter.
5695 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5705 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5708 memcpy(ptr, str, *size);
5715 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5718 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5725 /*****************************************************************************
5728 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5729 LPDWORD pcbNeeded, BOOL unicode)
5731 DWORD size, left = cbBuf;
5732 BOOL space = (cbBuf > 0);
5739 ji1->JobId = job->job_id;
5742 string_to_buf(job->document_title, ptr, left, &size, unicode);
5743 if(space && size <= left)
5745 ji1->pDocument = (LPWSTR)ptr;
5756 /*****************************************************************************
5759 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5760 LPDWORD pcbNeeded, BOOL unicode)
5762 DWORD size, left = cbBuf;
5763 BOOL space = (cbBuf > 0);
5770 ji2->JobId = job->job_id;
5773 string_to_buf(job->document_title, ptr, left, &size, unicode);
5774 if(space && size <= left)
5776 ji2->pDocument = (LPWSTR)ptr;
5787 /*****************************************************************************
5790 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5791 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5794 DWORD needed = 0, size;
5798 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5800 EnterCriticalSection(&printer_handles_cs);
5801 job = get_job(hPrinter, JobId);
5808 size = sizeof(JOB_INFO_1W);
5813 memset(pJob, 0, size);
5817 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5822 size = sizeof(JOB_INFO_2W);
5827 memset(pJob, 0, size);
5831 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5836 size = sizeof(JOB_INFO_3);
5840 memset(pJob, 0, size);
5849 SetLastError(ERROR_INVALID_LEVEL);
5853 *pcbNeeded = needed;
5855 LeaveCriticalSection(&printer_handles_cs);
5859 /*****************************************************************************
5860 * GetJobA [WINSPOOL.@]
5863 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5864 DWORD cbBuf, LPDWORD pcbNeeded)
5866 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5869 /*****************************************************************************
5870 * GetJobW [WINSPOOL.@]
5873 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5874 DWORD cbBuf, LPDWORD pcbNeeded)
5876 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5879 /*****************************************************************************
5882 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5884 char *unixname, *queue, *cmd;
5885 char fmt[] = "lpr -P%s %s";
5888 if(!(unixname = wine_get_unix_file_name(filename)))
5891 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5892 queue = HeapAlloc(GetProcessHeap(), 0, len);
5893 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5895 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5896 sprintf(cmd, fmt, queue, unixname);
5898 TRACE("printing with: %s\n", cmd);
5901 HeapFree(GetProcessHeap(), 0, cmd);
5902 HeapFree(GetProcessHeap(), 0, queue);
5903 HeapFree(GetProcessHeap(), 0, unixname);
5907 /*****************************************************************************
5910 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5912 #if HAVE_CUPS_CUPS_H
5915 char *unixname, *queue, *doc_titleA;
5919 if(!(unixname = wine_get_unix_file_name(filename)))
5922 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5923 queue = HeapAlloc(GetProcessHeap(), 0, len);
5924 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5926 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5927 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5928 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5930 TRACE("printing via cups\n");
5931 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5932 HeapFree(GetProcessHeap(), 0, doc_titleA);
5933 HeapFree(GetProcessHeap(), 0, queue);
5934 HeapFree(GetProcessHeap(), 0, unixname);
5940 return schedule_lpr(printer_name, filename);
5944 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5951 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5955 if(HIWORD(wparam) == BN_CLICKED)
5957 if(LOWORD(wparam) == IDOK)
5960 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5963 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5964 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5966 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5968 WCHAR caption[200], message[200];
5971 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5972 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5973 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5974 if(mb_ret == IDCANCEL)
5976 HeapFree(GetProcessHeap(), 0, filename);
5980 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5981 if(hf == INVALID_HANDLE_VALUE)
5983 WCHAR caption[200], message[200];
5985 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5986 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5987 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5988 HeapFree(GetProcessHeap(), 0, filename);
5992 DeleteFileW(filename);
5993 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5995 EndDialog(hwnd, IDOK);
5998 if(LOWORD(wparam) == IDCANCEL)
6000 EndDialog(hwnd, IDCANCEL);
6009 /*****************************************************************************
6012 static BOOL get_filename(LPWSTR *filename)
6014 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6015 file_dlg_proc, (LPARAM)filename) == IDOK;
6018 /*****************************************************************************
6021 static BOOL schedule_file(LPCWSTR filename)
6023 LPWSTR output = NULL;
6025 if(get_filename(&output))
6027 TRACE("copy to %s\n", debugstr_w(output));
6028 CopyFileW(filename, output, FALSE);
6029 HeapFree(GetProcessHeap(), 0, output);
6035 /*****************************************************************************
6038 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6041 char *unixname, *cmdA;
6043 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6047 if(!(unixname = wine_get_unix_file_name(filename)))
6050 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6051 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6052 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6054 TRACE("printing with: %s\n", cmdA);
6056 if((file_fd = open(unixname, O_RDONLY)) == -1)
6061 ERR("pipe() failed!\n");
6071 /* reset signals that we previously set to SIG_IGN */
6072 signal(SIGPIPE, SIG_DFL);
6073 signal(SIGCHLD, SIG_DFL);
6079 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6080 write(fds[1], buf, no_read);
6085 if(file_fd != -1) close(file_fd);
6086 if(fds[0] != -1) close(fds[0]);
6087 if(fds[1] != -1) close(fds[1]);
6089 HeapFree(GetProcessHeap(), 0, cmdA);
6090 HeapFree(GetProcessHeap(), 0, unixname);
6097 /*****************************************************************************
6100 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6102 int in_fd, out_fd, no_read;
6105 char *unixname, *outputA;
6108 if(!(unixname = wine_get_unix_file_name(filename)))
6111 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6112 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6113 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6115 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6116 in_fd = open(unixname, O_RDONLY);
6117 if(out_fd == -1 || in_fd == -1)
6120 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6121 write(out_fd, buf, no_read);
6125 if(in_fd != -1) close(in_fd);
6126 if(out_fd != -1) close(out_fd);
6127 HeapFree(GetProcessHeap(), 0, outputA);
6128 HeapFree(GetProcessHeap(), 0, unixname);
6132 /*****************************************************************************
6133 * ScheduleJob [WINSPOOL.@]
6136 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6138 opened_printer_t *printer;
6140 struct list *cursor, *cursor2;
6142 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6143 EnterCriticalSection(&printer_handles_cs);
6144 printer = get_opened_printer(hPrinter);
6148 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6150 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6153 if(job->job_id != dwJobID) continue;
6155 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6156 if(hf != INVALID_HANDLE_VALUE)
6158 PRINTER_INFO_5W *pi5;
6162 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6163 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6165 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6166 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6167 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6168 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6169 debugstr_w(pi5->pPortName));
6173 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6174 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6176 DWORD type, count = sizeof(output);
6177 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6180 if(output[0] == '|')
6182 schedule_pipe(output + 1, job->filename);
6186 schedule_unixfile(output, job->filename);
6188 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6190 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6192 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6194 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6196 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6198 schedule_file(job->filename);
6202 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6204 HeapFree(GetProcessHeap(), 0, pi5);
6206 DeleteFileW(job->filename);
6208 list_remove(cursor);
6209 HeapFree(GetProcessHeap(), 0, job->document_title);
6210 HeapFree(GetProcessHeap(), 0, job->filename);
6211 HeapFree(GetProcessHeap(), 0, job);
6216 LeaveCriticalSection(&printer_handles_cs);
6220 /*****************************************************************************
6221 * StartDocDlgA [WINSPOOL.@]
6223 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6225 UNICODE_STRING usBuffer;
6230 docW.cbSize = sizeof(docW);
6231 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6232 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6233 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6234 docW.fwType = doc->fwType;
6236 retW = StartDocDlgW(hPrinter, &docW);
6240 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6241 ret = HeapAlloc(GetProcessHeap(), 0, len);
6242 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6243 HeapFree(GetProcessHeap(), 0, retW);
6246 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6247 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6248 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6253 /*****************************************************************************
6254 * StartDocDlgW [WINSPOOL.@]
6256 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6257 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6258 * port is "FILE:". Also returns the full path if passed a relative path.
6260 * The caller should free the returned string from the process heap.
6262 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6267 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6269 PRINTER_INFO_5W *pi5;
6270 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6271 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6273 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6274 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6275 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6277 HeapFree(GetProcessHeap(), 0, pi5);
6280 HeapFree(GetProcessHeap(), 0, pi5);
6283 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6286 get_filename(&name);
6289 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6291 HeapFree(GetProcessHeap(), 0, name);
6294 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6295 GetFullPathNameW(name, len, ret, NULL);
6296 HeapFree(GetProcessHeap(), 0, name);
6301 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6304 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6305 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6307 attr = GetFileAttributesW(ret);
6308 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6310 HeapFree(GetProcessHeap(), 0, ret);