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};
165 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
167 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
168 'i','o','n',' ','F','i','l','e',0};
169 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
170 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
171 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
173 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
175 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
176 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
177 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
178 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
179 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
180 static const WCHAR NameW[] = {'N','a','m','e',0};
181 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
182 static const WCHAR PortW[] = {'P','o','r','t',0};
183 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
185 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
187 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
188 'v','e','r','D','a','t','a',0};
189 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
191 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
192 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
193 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
194 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
195 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
196 static const WCHAR emptyStringW[] = {0};
198 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
200 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
201 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
202 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
204 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
205 'D','o','c','u','m','e','n','t',0};
207 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
208 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
209 DWORD Level, LPBYTE pDriverInfo,
210 DWORD cbBuf, LPDWORD pcbNeeded,
212 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
213 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
215 /******************************************************************
216 * validate the user-supplied printing-environment [internal]
219 * env [I] PTR to Environment-String or NULL
223 * Success: PTR to printenv_t
226 * An empty string is handled the same way as NULL.
227 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
231 static const printenv_t * validate_envW(LPCWSTR env)
233 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
234 3, Version3_RegPathW, Version3_SubdirW};
235 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
236 0, emptyStringW, emptyStringW};
237 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
239 const printenv_t *result = NULL;
242 TRACE("testing %s\n", debugstr_w(env));
245 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
247 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
249 result = all_printenv[i];
254 if (result == NULL) {
255 FIXME("unsupported Environment: %s\n", debugstr_w(env));
256 SetLastError(ERROR_INVALID_ENVIRONMENT);
258 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
262 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
264 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
270 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
271 if passed a NULL string. This returns NULLs to the result.
273 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
277 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
278 return usBufferPtr->Buffer;
280 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
284 static LPWSTR strdupW(LPCWSTR p)
290 len = (strlenW(p) + 1) * sizeof(WCHAR);
291 ret = HeapAlloc(GetProcessHeap(), 0, len);
297 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
300 /* If forcing, or no profile string entry for device yet, set the entry
302 * The always change entry if not WINEPS yet is discussable.
305 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
307 !strstr(qbuf,"WINEPS.DRV")
309 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
312 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
313 WriteProfileStringA("windows","device",buf);
314 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
315 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
318 HeapFree(GetProcessHeap(),0,buf);
322 #ifdef HAVE_CUPS_CUPS_H
323 static typeof(cupsGetDests) *pcupsGetDests;
324 static typeof(cupsGetPPD) *pcupsGetPPD;
325 static typeof(cupsPrintFile) *pcupsPrintFile;
326 static void *cupshandle;
328 static BOOL CUPS_LoadPrinters(void)
331 BOOL hadprinter = FALSE;
333 PRINTER_INFO_2A pinfo2a;
335 HKEY hkeyPrinter, hkeyPrinters, hkey;
337 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
340 TRACE("loaded %s\n", SONAME_LIBCUPS);
343 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
344 if (!p##x) return FALSE;
347 DYNCUPS(cupsGetDests);
348 DYNCUPS(cupsPrintFile);
351 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
353 ERR("Can't create Printers key\n");
357 nrofdests = pcupsGetDests(&dests);
358 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
359 for (i=0;i<nrofdests;i++) {
360 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
361 sprintf(port,"LPR:%s",dests[i].name);
362 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
363 sprintf(devline,"WINEPS.DRV,%s",port);
364 WriteProfileStringA("devices",dests[i].name,devline);
365 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
366 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
369 HeapFree(GetProcessHeap(),0,devline);
371 TRACE("Printer %d: %s\n", i, dests[i].name);
372 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
373 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
375 TRACE("Printer already exists\n");
376 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
377 RegCloseKey(hkeyPrinter);
379 static CHAR data_type[] = "RAW",
380 print_proc[] = "WinPrint",
381 driver_name[] = "PS Driver",
382 comment[] = "WINEPS Printer using CUPS",
383 location[] = "<physical location of printer>",
384 params[] = "<parameters?>",
385 share_name[] = "<share name?>",
386 sep_file[] = "<sep file?>";
388 memset(&pinfo2a,0,sizeof(pinfo2a));
389 pinfo2a.pPrinterName = dests[i].name;
390 pinfo2a.pDatatype = data_type;
391 pinfo2a.pPrintProcessor = print_proc;
392 pinfo2a.pDriverName = driver_name;
393 pinfo2a.pComment = comment;
394 pinfo2a.pLocation = location;
395 pinfo2a.pPortName = port;
396 pinfo2a.pParameters = params;
397 pinfo2a.pShareName = share_name;
398 pinfo2a.pSepFile = sep_file;
400 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
401 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
402 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
405 HeapFree(GetProcessHeap(),0,port);
408 if (dests[i].is_default)
409 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
411 RegCloseKey(hkeyPrinters);
417 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
418 PRINTER_INFO_2A pinfo2a;
419 char *e,*s,*name,*prettyname,*devname;
420 BOOL ret = FALSE, set_default = FALSE;
421 char *port,*devline,*env_default;
422 HKEY hkeyPrinter, hkeyPrinters, hkey;
424 while (isspace(*pent)) pent++;
425 s = strchr(pent,':');
427 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
435 TRACE("name=%s entry=%s\n",name, pent);
437 if(ispunct(*name)) { /* a tc entry, not a real printer */
438 TRACE("skipping tc entry\n");
442 if(strstr(pent,":server")) { /* server only version so skip */
443 TRACE("skipping server entry\n");
447 /* Determine whether this is a postscript printer. */
450 env_default = getenv("PRINTER");
452 /* Get longest name, usually the one at the right for later display. */
453 while((s=strchr(prettyname,'|'))) {
456 while(isspace(*--e)) *e = '\0';
457 TRACE("\t%s\n", debugstr_a(prettyname));
458 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
459 for(prettyname = s+1; isspace(*prettyname); prettyname++)
462 e = prettyname + strlen(prettyname);
463 while(isspace(*--e)) *e = '\0';
464 TRACE("\t%s\n", debugstr_a(prettyname));
465 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
467 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
468 * if it is too long, we use it as comment below. */
469 devname = prettyname;
470 if (strlen(devname)>=CCHDEVICENAME-1)
472 if (strlen(devname)>=CCHDEVICENAME-1) {
477 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
478 sprintf(port,"LPR:%s",name);
480 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
481 sprintf(devline,"WINEPS.DRV,%s",port);
482 WriteProfileStringA("devices",devname,devline);
483 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
484 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
487 HeapFree(GetProcessHeap(),0,devline);
489 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491 ERR("Can't create Printers key\n");
495 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
496 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
498 TRACE("Printer already exists\n");
499 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
500 RegCloseKey(hkeyPrinter);
502 static CHAR data_type[] = "RAW",
503 print_proc[] = "WinPrint",
504 driver_name[] = "PS Driver",
505 comment[] = "WINEPS Printer using LPR",
506 params[] = "<parameters?>",
507 share_name[] = "<share name?>",
508 sep_file[] = "<sep file?>";
510 memset(&pinfo2a,0,sizeof(pinfo2a));
511 pinfo2a.pPrinterName = devname;
512 pinfo2a.pDatatype = data_type;
513 pinfo2a.pPrintProcessor = print_proc;
514 pinfo2a.pDriverName = driver_name;
515 pinfo2a.pComment = comment;
516 pinfo2a.pLocation = prettyname;
517 pinfo2a.pPortName = port;
518 pinfo2a.pParameters = params;
519 pinfo2a.pShareName = share_name;
520 pinfo2a.pSepFile = sep_file;
522 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
523 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
524 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
527 RegCloseKey(hkeyPrinters);
529 if (isfirst || set_default)
530 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
532 HeapFree(GetProcessHeap(), 0, port);
534 HeapFree(GetProcessHeap(), 0, name);
539 PRINTCAP_LoadPrinters(void) {
540 BOOL hadprinter = FALSE;
544 BOOL had_bash = FALSE;
546 f = fopen("/etc/printcap","r");
550 while(fgets(buf,sizeof(buf),f)) {
553 end=strchr(buf,'\n');
557 while(isspace(*start)) start++;
558 if(*start == '#' || *start == '\0')
561 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
562 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
563 HeapFree(GetProcessHeap(),0,pent);
567 if (end && *--end == '\\') {
574 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
577 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
583 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
584 HeapFree(GetProcessHeap(),0,pent);
590 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
593 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
594 lstrlenW(value) * sizeof(WCHAR));
596 return ERROR_FILE_NOT_FOUND;
599 void WINSPOOL_LoadSystemPrinters(void)
601 HKEY hkey, hkeyPrinters;
604 DWORD needed, num, i;
605 WCHAR PrinterName[256];
607 static CHAR name[] = "PS Driver",
608 driver_path[] = "wineps16",
609 data_file[] = "<datafile?>",
610 config_file[] = "wineps16",
611 help_file[] = "<helpfile?>",
612 dep_file[] = "<dependend files?>",
613 monitor_name[] = "<monitor name?>",
614 default_data_type[] = "RAW";
616 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
618 di3a.pEnvironment = NULL; /* NULL means auto */
619 di3a.pDriverPath = driver_path;
620 di3a.pDataFile = data_file;
621 di3a.pConfigFile = config_file;
622 di3a.pHelpFile = help_file;
623 di3a.pDependentFiles = dep_file;
624 di3a.pMonitorName = monitor_name;
625 di3a.pDefaultDataType = default_data_type;
627 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
628 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
632 /* This ensures that all printer entries have a valid Name value. If causes
633 problems later if they don't. If one is found to be missed we create one
634 and set it equal to the name of the key */
635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
636 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
637 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
638 for(i = 0; i < num; i++) {
639 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
640 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
641 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
642 set_reg_szW(hkey, NameW, PrinterName);
649 RegCloseKey(hkeyPrinters);
652 /* We want to avoid calling AddPrinter on printers as much as
653 possible, because on cups printers this will (eventually) lead
654 to a call to cupsGetPPD which takes forever, even with non-cups
655 printers AddPrinter takes a while. So we'll tag all printers that
656 were automatically added last time around, if they still exist
657 we'll leave them be otherwise we'll delete them. */
658 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
660 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
661 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
662 for(i = 0; i < num; i++) {
663 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
664 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
665 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
667 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
675 HeapFree(GetProcessHeap(), 0, pi);
679 #ifdef HAVE_CUPS_CUPS_H
680 done = CUPS_LoadPrinters();
683 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
684 /* Check for [ppd] section in config file before parsing /etc/printcap */
685 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
686 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
687 &hkey) == ERROR_SUCCESS) {
689 PRINTCAP_LoadPrinters();
693 /* Now enumerate the list again and delete any printers that a still tagged */
694 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
696 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
697 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
698 for(i = 0; i < num; i++) {
699 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
700 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
701 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
702 DWORD dw, type, size = sizeof(dw);
703 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
704 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
714 HeapFree(GetProcessHeap(), 0, pi);
721 /*****************************************************************************
722 * enumerate the local monitors (INTERNAL)
724 * returns the needed size (in bytes) for pMonitors
725 * and *lpreturned is set to number of entries returned in pMonitors
728 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
733 LPMONITOR_INFO_2W mi;
734 WCHAR buffer[MAX_PATH];
735 WCHAR dllname[MAX_PATH];
743 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
745 numentries = *lpreturned; /* this is 0, when we scan the registry */
746 len = entrysize * numentries;
747 ptr = (LPWSTR) &pMonitors[len];
750 len = sizeof(buffer);
753 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
754 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
755 /* Scan all Monitor-Registry-Keys */
756 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
757 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
758 dllsize = sizeof(dllname);
761 /* The Monitor must have a Driver-DLL */
762 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
763 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
764 /* We found a valid DLL for this Monitor. */
765 TRACE("using Driver: %s\n", debugstr_w(dllname));
770 /* Windows returns only Port-Monitors here, but to simplify our code,
771 we do no filtering for Language-Monitors */
775 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
777 /* we install and return only monitors for "Windows NT x86" */
778 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
782 /* required size is calculated. Now fill the user-buffer */
783 if (pMonitors && (cbBuf >= needed)){
784 mi = (LPMONITOR_INFO_2W) pMonitors;
785 pMonitors += entrysize;
787 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
789 lstrcpyW(ptr, buffer); /* Name of the Monitor */
790 ptr += (len+1); /* len is lstrlenW(monitorname) */
792 mi->pEnvironment = ptr;
793 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
794 ptr += (lstrlenW(envname_x86W)+1);
797 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
798 ptr += (dllsize / sizeof(WCHAR));
803 len = sizeof(buffer);
808 *lpreturned = numentries;
809 TRACE("need %ld byte for %ld entries\n", needed, numentries);
813 /******************************************************************
814 * get_opened_printer_entry
815 * Get the first place empty in the opened printer table
818 * - pDefault is ignored
820 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
822 UINT_PTR handle = nb_printer_handles, i;
823 jobqueue_t *queue = NULL;
824 opened_printer_t *printer = NULL;
826 EnterCriticalSection(&printer_handles_cs);
828 for (i = 0; i < nb_printer_handles; i++)
830 if (!printer_handles[i])
832 if(handle == nb_printer_handles)
837 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
838 queue = printer_handles[i]->queue;
842 if (handle >= nb_printer_handles)
844 opened_printer_t **new_array;
846 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
847 (nb_printer_handles + 16) * sizeof(*new_array) );
849 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
850 (nb_printer_handles + 16) * sizeof(*new_array) );
857 printer_handles = new_array;
858 nb_printer_handles += 16;
861 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
868 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
869 if (!printer->name) {
873 strcpyW(printer->name, name);
877 printer->queue = queue;
880 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
881 if (!printer->queue) {
885 list_init(&printer->queue->jobs);
886 printer->queue->ref = 0;
888 InterlockedIncrement(&printer->queue->ref);
890 printer_handles[handle] = printer;
893 LeaveCriticalSection(&printer_handles_cs);
894 if (!handle && printer) {
895 /* Something Failed: Free the Buffers */
896 HeapFree(GetProcessHeap(), 0, printer->name);
897 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
898 HeapFree(GetProcessHeap(), 0, printer);
901 return (HANDLE)handle;
904 /******************************************************************
906 * Get the pointer to the opened printer referred by the handle
908 static opened_printer_t *get_opened_printer(HANDLE hprn)
910 UINT_PTR idx = (UINT_PTR)hprn;
911 opened_printer_t *ret = NULL;
913 EnterCriticalSection(&printer_handles_cs);
915 if ((idx <= 0) || (idx > nb_printer_handles))
918 ret = printer_handles[idx - 1];
920 LeaveCriticalSection(&printer_handles_cs);
924 /******************************************************************
925 * get_opened_printer_name
926 * Get the pointer to the opened printer name referred by the handle
928 static LPCWSTR get_opened_printer_name(HANDLE hprn)
930 opened_printer_t *printer = get_opened_printer(hprn);
931 if(!printer) return NULL;
932 return printer->name;
935 /******************************************************************
936 * WINSPOOL_GetOpenedPrinterRegKey
939 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
941 LPCWSTR name = get_opened_printer_name(hPrinter);
945 if(!name) return ERROR_INVALID_HANDLE;
947 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
951 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
953 ERR("Can't find opened printer %s in registry\n",
955 RegCloseKey(hkeyPrinters);
956 return ERROR_INVALID_PRINTER_NAME; /* ? */
958 RegCloseKey(hkeyPrinters);
959 return ERROR_SUCCESS;
962 /******************************************************************
965 * Get the pointer to the specified job.
966 * Should hold the printer_handles_cs before calling.
968 static job_t *get_job(HANDLE hprn, DWORD JobId)
970 opened_printer_t *printer = get_opened_printer(hprn);
973 if(!printer) return NULL;
974 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
976 if(job->job_id == JobId)
982 /***********************************************************
985 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
988 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
991 Formname = (dmA->dmSize > off_formname);
992 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
993 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
994 dmW->dmDeviceName, CCHDEVICENAME);
996 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
997 dmA->dmSize - CCHDEVICENAME);
999 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1000 off_formname - CCHDEVICENAME);
1001 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1002 dmW->dmFormName, CCHFORMNAME);
1003 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1004 (off_formname + CCHFORMNAME));
1007 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1008 dmA->dmDriverExtra);
1012 /***********************************************************
1014 * Creates an ascii copy of supplied devmode on heap
1016 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1021 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1023 if(!dmW) return NULL;
1024 Formname = (dmW->dmSize > off_formname);
1025 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1026 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1027 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1028 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1030 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1031 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1033 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1034 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1035 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1036 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1037 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1038 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1041 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1042 dmW->dmDriverExtra);
1046 /***********************************************************
1047 * PRINTER_INFO_2AtoW
1048 * Creates a unicode copy of PRINTER_INFO_2A on heap
1050 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1052 LPPRINTER_INFO_2W piW;
1053 UNICODE_STRING usBuffer;
1055 if(!piA) return NULL;
1056 piW = HeapAlloc(heap, 0, sizeof(*piW));
1057 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1059 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1060 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1061 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1062 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1063 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1064 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1065 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1066 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1067 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1068 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1069 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1070 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1074 /***********************************************************
1075 * FREE_PRINTER_INFO_2W
1076 * Free PRINTER_INFO_2W and all strings
1078 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1082 HeapFree(heap,0,piW->pServerName);
1083 HeapFree(heap,0,piW->pPrinterName);
1084 HeapFree(heap,0,piW->pShareName);
1085 HeapFree(heap,0,piW->pPortName);
1086 HeapFree(heap,0,piW->pDriverName);
1087 HeapFree(heap,0,piW->pComment);
1088 HeapFree(heap,0,piW->pLocation);
1089 HeapFree(heap,0,piW->pDevMode);
1090 HeapFree(heap,0,piW->pSepFile);
1091 HeapFree(heap,0,piW->pPrintProcessor);
1092 HeapFree(heap,0,piW->pDatatype);
1093 HeapFree(heap,0,piW->pParameters);
1094 HeapFree(heap,0,piW);
1098 /******************************************************************
1099 * DeviceCapabilities [WINSPOOL.@]
1100 * DeviceCapabilitiesA [WINSPOOL.@]
1103 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1104 LPSTR pOutput, LPDEVMODEA lpdm)
1108 if (!GDI_CallDeviceCapabilities16)
1110 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1112 if (!GDI_CallDeviceCapabilities16) return -1;
1114 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1116 /* If DC_PAPERSIZE map POINT16s to POINTs */
1117 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1118 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1119 POINT *pt = (POINT *)pOutput;
1121 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1122 for(i = 0; i < ret; i++, pt++)
1127 HeapFree( GetProcessHeap(), 0, tmp );
1133 /*****************************************************************************
1134 * DeviceCapabilitiesW [WINSPOOL.@]
1136 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1139 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1140 WORD fwCapability, LPWSTR pOutput,
1141 const DEVMODEW *pDevMode)
1143 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1144 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1145 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1148 if(pOutput && (fwCapability == DC_BINNAMES ||
1149 fwCapability == DC_FILEDEPENDENCIES ||
1150 fwCapability == DC_PAPERNAMES)) {
1151 /* These need A -> W translation */
1154 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1158 switch(fwCapability) {
1163 case DC_FILEDEPENDENCIES:
1167 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1168 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1170 for(i = 0; i < ret; i++)
1171 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1172 pOutput + (i * size), size);
1173 HeapFree(GetProcessHeap(), 0, pOutputA);
1175 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1176 (LPSTR)pOutput, dmA);
1178 HeapFree(GetProcessHeap(),0,pPortA);
1179 HeapFree(GetProcessHeap(),0,pDeviceA);
1180 HeapFree(GetProcessHeap(),0,dmA);
1184 /******************************************************************
1185 * DocumentPropertiesA [WINSPOOL.@]
1187 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1189 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1190 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1191 LPDEVMODEA pDevModeInput,DWORD fMode )
1193 LPSTR lpName = pDeviceName;
1194 static CHAR port[] = "LPT1:";
1197 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1198 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1202 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1204 ERR("no name from hPrinter?\n");
1205 SetLastError(ERROR_INVALID_HANDLE);
1208 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1211 if (!GDI_CallExtDeviceMode16)
1213 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1215 if (!GDI_CallExtDeviceMode16) {
1216 ERR("No CallExtDeviceMode16?\n");
1220 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1221 pDevModeInput, NULL, fMode);
1224 HeapFree(GetProcessHeap(),0,lpName);
1229 /*****************************************************************************
1230 * DocumentPropertiesW (WINSPOOL.@)
1232 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1234 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1236 LPDEVMODEW pDevModeOutput,
1237 LPDEVMODEW pDevModeInput, DWORD fMode)
1240 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1241 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1242 LPDEVMODEA pDevModeOutputA = NULL;
1245 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1246 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1248 if(pDevModeOutput) {
1249 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1250 if(ret < 0) return ret;
1251 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1253 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1254 pDevModeInputA, fMode);
1255 if(pDevModeOutput) {
1256 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1257 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1259 if(fMode == 0 && ret > 0)
1260 ret += (CCHDEVICENAME + CCHFORMNAME);
1261 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1262 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1266 /******************************************************************
1267 * OpenPrinterA [WINSPOOL.@]
1272 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1273 LPPRINTER_DEFAULTSA pDefault)
1275 UNICODE_STRING lpPrinterNameW;
1276 UNICODE_STRING usBuffer;
1277 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1278 PWSTR pwstrPrinterNameW;
1281 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1284 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1285 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1286 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1287 pDefaultW = &DefaultW;
1289 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1291 RtlFreeUnicodeString(&usBuffer);
1292 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1294 RtlFreeUnicodeString(&lpPrinterNameW);
1298 /******************************************************************
1299 * OpenPrinterW [WINSPOOL.@]
1301 * Open a Printer / Printserver or a Printer-Object
1304 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1305 * phPrinter [O] The resulting Handle is stored here
1306 * pDefault [I] PTR to Default Printer Settings or NULL
1313 * lpPrinterName is one of:
1314 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1315 *| Printer: "PrinterName"
1316 *| Printer-Object: "PrinterName,Job xxx"
1317 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1318 *| XcvPort: "Servername,XcvPort PortName"
1321 *| Printer-Object not supported
1322 *| XcvMonitor not supported
1323 *| XcvPort not supported
1324 *| pDefaults is ignored
1327 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1329 HKEY hkeyPrinters = NULL;
1330 HKEY hkeyPrinter = NULL;
1332 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1334 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1335 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1338 if(lpPrinterName != NULL)
1340 /* Check any Printer exists */
1341 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1342 ERR("Can't create Printers key\n");
1343 SetLastError(ERROR_FILE_NOT_FOUND);
1346 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1347 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1349 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1350 RegCloseKey(hkeyPrinters);
1351 SetLastError(ERROR_INVALID_PRINTER_NAME);
1354 RegCloseKey(hkeyPrinter);
1355 RegCloseKey(hkeyPrinters);
1358 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1359 SetLastError(ERROR_INVALID_PARAMETER);
1363 /* Get the unique handle of the printer or Printserver */
1364 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1365 return (*phPrinter != 0);
1368 /******************************************************************
1369 * AddMonitorA [WINSPOOL.@]
1374 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1376 LPWSTR nameW = NULL;
1379 LPMONITOR_INFO_2A mi2a;
1380 MONITOR_INFO_2W mi2w;
1382 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1383 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1384 mi2a ? debugstr_a(mi2a->pName) : NULL,
1385 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1386 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1389 SetLastError(ERROR_INVALID_LEVEL);
1393 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1399 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1400 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1401 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1404 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1406 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1407 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1408 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1410 if (mi2a->pEnvironment) {
1411 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1412 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1413 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1415 if (mi2a->pDLLName) {
1416 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1417 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1418 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1421 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1423 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1424 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1425 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1427 HeapFree(GetProcessHeap(), 0, nameW);
1431 /******************************************************************************
1432 * AddMonitorW [WINSPOOL.@]
1434 * Install a Printmonitor
1437 * pName [I] Servername or NULL (local Computer)
1438 * Level [I] Structure-Level (Must be 2)
1439 * pMonitors [I] PTR to MONITOR_INFO_2
1446 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1449 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1451 LPMONITOR_INFO_2W mi2w;
1454 HMODULE hdll = NULL;
1458 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1459 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1460 mi2w ? debugstr_w(mi2w->pName) : NULL,
1461 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1462 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1465 SetLastError(ERROR_INVALID_LEVEL);
1469 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1474 if (pName && (pName[0])) {
1475 FIXME("for server %s not implemented\n", debugstr_w(pName));
1476 SetLastError(ERROR_ACCESS_DENIED);
1481 if (!mi2w->pName || (! mi2w->pName[0])) {
1482 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1483 SetLastError(ERROR_INVALID_PARAMETER);
1486 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1487 WARN("Environment %s requested (we support only %s)\n",
1488 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1489 SetLastError(ERROR_INVALID_ENVIRONMENT);
1493 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1494 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1495 SetLastError(ERROR_INVALID_PARAMETER);
1499 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1504 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1505 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1509 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1510 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1511 &disposition) == ERROR_SUCCESS) {
1513 /* Some installers set options for the port before calling AddMonitor.
1514 We query the "Driver" entry to verify that the monitor is installed,
1515 before we return an error.
1516 When a user installs two print monitors at the same time with the
1517 same name but with a different driver DLL and a task switch comes
1518 between RegQueryValueExW and RegSetValueExW, a race condition
1519 is possible but silently ignored. */
1523 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1524 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1525 &namesize) == ERROR_SUCCESS)) {
1526 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1527 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1528 9x: ERROR_ALREADY_EXISTS (183) */
1529 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1534 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1535 res = (RegSetValueExW(hentry, DriverW, 0,
1536 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1538 RegCloseKey(hentry);
1545 /******************************************************************
1546 * DeletePrinterDriverA [WINSPOOL.@]
1550 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1552 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1553 debugstr_a(pDriverName));
1554 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1558 /******************************************************************
1559 * DeletePrinterDriverW [WINSPOOL.@]
1563 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1565 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1566 debugstr_w(pDriverName));
1567 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1571 /******************************************************************
1572 * DeleteMonitorA [WINSPOOL.@]
1574 * See DeleteMonitorW.
1577 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1579 LPWSTR nameW = NULL;
1580 LPWSTR EnvironmentW = NULL;
1581 LPWSTR MonitorNameW = NULL;
1586 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1587 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1588 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1592 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1593 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1594 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1597 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1598 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1599 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1602 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1604 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1605 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1606 HeapFree(GetProcessHeap(), 0, nameW);
1610 /******************************************************************
1611 * DeleteMonitorW [WINSPOOL.@]
1613 * Delete a specific Printmonitor from a Printing-Environment
1616 * pName [I] Servername or NULL (local Computer)
1617 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1618 * pMonitorName [I] Name of the Monitor, that should be deleted
1625 * pEnvironment is ignored in Windows for the local Computer.
1629 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1633 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1634 debugstr_w(pMonitorName));
1636 if (pName && (pName[0])) {
1637 FIXME("for server %s not implemented\n", debugstr_w(pName));
1638 SetLastError(ERROR_ACCESS_DENIED);
1642 /* pEnvironment is ignored in Windows for the local Computer */
1644 if (!pMonitorName || !pMonitorName[0]) {
1645 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1646 SetLastError(ERROR_INVALID_PARAMETER);
1650 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1651 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1655 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1656 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1657 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1662 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1665 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1666 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1670 /******************************************************************
1671 * DeletePortA [WINSPOOL.@]
1677 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1679 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1680 debugstr_a(pPortName));
1681 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1685 /******************************************************************
1686 * DeletePortW [WINSPOOL.@]
1688 * Delete a specific Port
1691 * pName [I] Servername or NULL (local Computer)
1692 * hWnd [I] Handle to parent Window for the Dialog-Box
1693 * pPortName [I] Name of the Port, that should be deleted
1704 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1706 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1707 debugstr_w(pPortName));
1708 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1712 /******************************************************************************
1713 * SetPrinterW [WINSPOOL.@]
1715 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1717 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1718 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1722 /******************************************************************************
1723 * WritePrinter [WINSPOOL.@]
1725 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1727 opened_printer_t *printer;
1730 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1732 EnterCriticalSection(&printer_handles_cs);
1733 printer = get_opened_printer(hPrinter);
1736 SetLastError(ERROR_INVALID_HANDLE);
1742 SetLastError(ERROR_SPL_NO_STARTDOC);
1746 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1748 LeaveCriticalSection(&printer_handles_cs);
1752 /*****************************************************************************
1753 * AddFormA [WINSPOOL.@]
1755 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1757 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1761 /*****************************************************************************
1762 * AddFormW [WINSPOOL.@]
1764 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1766 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1770 /*****************************************************************************
1771 * AddJobA [WINSPOOL.@]
1773 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1776 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1780 SetLastError(ERROR_INVALID_LEVEL);
1784 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1787 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1788 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1789 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1790 if(*pcbNeeded > cbBuf) {
1791 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1794 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1795 addjobA->JobId = addjobW->JobId;
1796 addjobA->Path = (char *)(addjobA + 1);
1797 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1803 /*****************************************************************************
1804 * AddJobW [WINSPOOL.@]
1806 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1808 opened_printer_t *printer;
1811 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1812 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1813 WCHAR path[MAX_PATH], filename[MAX_PATH];
1815 ADDJOB_INFO_1W *addjob;
1817 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1819 EnterCriticalSection(&printer_handles_cs);
1821 printer = get_opened_printer(hPrinter);
1824 SetLastError(ERROR_INVALID_HANDLE);
1829 SetLastError(ERROR_INVALID_LEVEL);
1833 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1837 job->job_id = InterlockedIncrement(&next_job_id);
1839 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1840 if(path[len - 1] != '\\')
1842 memcpy(path + len, spool_path, sizeof(spool_path));
1843 sprintfW(filename, fmtW, path, job->job_id);
1845 len = strlenW(filename);
1846 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1847 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1848 job->document_title = strdupW(default_doc_title);
1849 list_add_tail(&printer->queue->jobs, &job->entry);
1851 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1852 if(*pcbNeeded <= cbBuf) {
1853 addjob = (ADDJOB_INFO_1W*)pData;
1854 addjob->JobId = job->job_id;
1855 addjob->Path = (WCHAR *)(addjob + 1);
1856 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1859 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1862 LeaveCriticalSection(&printer_handles_cs);
1866 /*****************************************************************************
1867 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1869 * Return the PATH for the Print-Processors
1871 * See GetPrintProcessorDirectoryW.
1875 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1876 DWORD level, LPBYTE Info,
1877 DWORD cbBuf, LPDWORD pcbNeeded)
1879 LPWSTR serverW = NULL;
1884 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
1885 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
1889 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
1890 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1891 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
1895 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
1896 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1897 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
1900 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
1901 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
1903 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
1906 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
1907 cbBuf, NULL, NULL) > 0;
1910 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
1911 HeapFree(GetProcessHeap(), 0, envW);
1912 HeapFree(GetProcessHeap(), 0, serverW);
1916 /*****************************************************************************
1917 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1919 * Return the PATH for the Print-Processors
1922 * server [I] Servername (NT only) or NULL (local Computer)
1923 * env [I] Printing-Environment (see below) or NULL (Default)
1924 * level [I] Structure-Level (must be 1)
1925 * Info [O] PTR to Buffer that receives the Result
1926 * cbBuf [I] Size of Buffer at "Info"
1927 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1928 * required for the Buffer at "Info"
1931 * Success: TRUE and in pcbNeeded the Bytes used in Info
1932 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
1933 * if cbBuf is too small
1935 * Native Values returned in Info on Success:
1936 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1937 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1938 *| win9x(Windows 4.0): "%winsysdir%"
1940 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1943 * Only NULL or "" is supported for server
1946 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1947 DWORD level, LPBYTE Info,
1948 DWORD cbBuf, LPDWORD pcbNeeded)
1951 const printenv_t * env_t;
1953 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
1954 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
1956 if(server != NULL && server[0]) {
1957 FIXME("server not supported: %s\n", debugstr_w(server));
1958 SetLastError(ERROR_INVALID_PARAMETER);
1962 env_t = validate_envW(env);
1963 if(!env_t) return FALSE; /* environment invalid or unsupported */
1966 WARN("(Level: %ld) is ignored in win9x\n", level);
1967 SetLastError(ERROR_INVALID_LEVEL);
1971 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1972 needed = GetSystemDirectoryW(NULL, 0);
1973 /* add the Size for the Subdirectories */
1974 needed += lstrlenW(spoolprtprocsW);
1975 needed += lstrlenW(env_t->subdir);
1976 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1978 if(pcbNeeded) *pcbNeeded = needed;
1979 TRACE ("required: 0x%lx/%ld\n", needed, needed);
1980 if (needed > cbBuf) {
1981 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1984 if(pcbNeeded == NULL) {
1985 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
1986 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
1987 SetLastError(RPC_X_NULL_REF_POINTER);
1991 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
1992 SetLastError(RPC_X_NULL_REF_POINTER);
1996 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
1997 /* add the Subdirectories */
1998 lstrcatW((LPWSTR) Info, spoolprtprocsW);
1999 lstrcatW((LPWSTR) Info, env_t->subdir);
2000 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2004 /*****************************************************************************
2005 * WINSPOOL_OpenDriverReg [internal]
2007 * opens the registry for the printer drivers depending on the given input
2008 * variable pEnvironment
2011 * the opened hkey on success
2014 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2018 const printenv_t * env;
2021 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2023 if (!pEnvironment || unicode) {
2024 /* pEnvironment was NULL or an Unicode-String: use it direct */
2025 env = validate_envW(pEnvironment);
2029 /* pEnvironment was an ANSI-String: convert to unicode first */
2031 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2032 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2033 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2034 env = validate_envW(buffer);
2035 HeapFree(GetProcessHeap(), 0, buffer);
2037 if (!env) return NULL;
2039 buffer = HeapAlloc( GetProcessHeap(), 0,
2040 (strlenW(DriversW) + strlenW(env->envname) +
2041 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2043 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2044 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2045 HeapFree(GetProcessHeap(), 0, buffer);
2050 /*****************************************************************************
2051 * AddPrinterW [WINSPOOL.@]
2053 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2055 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2059 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2062 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2065 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2066 SetLastError(ERROR_INVALID_PARAMETER);
2070 ERR("Level = %ld, unsupported!\n", Level);
2071 SetLastError(ERROR_INVALID_LEVEL);
2075 SetLastError(ERROR_INVALID_PARAMETER);
2078 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2080 ERR("Can't create Printers key\n");
2083 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2084 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2085 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2086 RegCloseKey(hkeyPrinter);
2087 RegCloseKey(hkeyPrinters);
2090 RegCloseKey(hkeyPrinter);
2092 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2094 ERR("Can't create Drivers key\n");
2095 RegCloseKey(hkeyPrinters);
2098 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2100 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2101 RegCloseKey(hkeyPrinters);
2102 RegCloseKey(hkeyDrivers);
2103 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2106 RegCloseKey(hkeyDriver);
2107 RegCloseKey(hkeyDrivers);
2109 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2110 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2111 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2112 RegCloseKey(hkeyPrinters);
2116 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2118 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2119 SetLastError(ERROR_INVALID_PRINTER_NAME);
2120 RegCloseKey(hkeyPrinters);
2123 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2124 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2125 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2127 /* See if we can load the driver. We may need the devmode structure anyway
2130 * Note that DocumentPropertiesW will briefly try to open the printer we
2131 * just create to find a DEVMODEA struct (it will use the WINEPS default
2132 * one in case it is not there, so we are ok).
2134 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2137 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2138 size = sizeof(DEVMODEW);
2144 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2145 ZeroMemory(dmW,size);
2147 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2149 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2150 HeapFree(GetProcessHeap(),0,dmW);
2155 /* set devmode to printer name */
2156 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2160 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2161 and we support these drivers. NT writes DEVMODEW so somehow
2162 we'll need to distinguish between these when we support NT
2166 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2167 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2168 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2169 HeapFree(GetProcessHeap(), 0, dmA);
2171 HeapFree(GetProcessHeap(), 0, dmW);
2173 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2174 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2175 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2176 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2178 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2179 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2180 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2181 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2182 (LPBYTE)&pi->Priority, sizeof(DWORD));
2183 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2184 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2185 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2186 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2187 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2188 (LPBYTE)&pi->Status, sizeof(DWORD));
2189 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2190 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2192 RegCloseKey(hkeyPrinter);
2193 RegCloseKey(hkeyPrinters);
2194 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2195 ERR("OpenPrinter failing\n");
2201 /*****************************************************************************
2202 * AddPrinterA [WINSPOOL.@]
2204 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2206 UNICODE_STRING pNameW;
2208 PRINTER_INFO_2W *piW;
2209 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2212 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2214 ERR("Level = %ld, unsupported!\n", Level);
2215 SetLastError(ERROR_INVALID_LEVEL);
2218 pwstrNameW = asciitounicode(&pNameW,pName);
2219 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2221 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2223 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2224 RtlFreeUnicodeString(&pNameW);
2229 /*****************************************************************************
2230 * ClosePrinter [WINSPOOL.@]
2232 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2234 UINT_PTR i = (UINT_PTR)hPrinter;
2235 opened_printer_t *printer = NULL;
2238 TRACE("Handle %p\n", hPrinter);
2240 EnterCriticalSection(&printer_handles_cs);
2242 if ((i > 0) && (i <= nb_printer_handles))
2243 printer = printer_handles[i - 1];
2247 struct list *cursor, *cursor2;
2250 EndDocPrinter(hPrinter);
2252 if(InterlockedDecrement(&printer->queue->ref) == 0)
2254 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2256 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2257 ScheduleJob(hPrinter, job->job_id);
2259 HeapFree(GetProcessHeap(), 0, printer->queue);
2261 HeapFree(GetProcessHeap(), 0, printer->name);
2262 HeapFree(GetProcessHeap(), 0, printer);
2263 printer_handles[i - 1] = NULL;
2266 LeaveCriticalSection(&printer_handles_cs);
2270 /*****************************************************************************
2271 * DeleteFormA [WINSPOOL.@]
2273 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2275 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2279 /*****************************************************************************
2280 * DeleteFormW [WINSPOOL.@]
2282 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2284 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2288 /*****************************************************************************
2289 * WINSPOOL_SHRegDeleteKey
2291 * Recursively delete subkeys.
2292 * Cut & paste from shlwapi.
2295 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2297 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2298 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2301 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2304 /* Find how many subkeys there are */
2305 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2306 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2310 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2311 /* Name too big: alloc a buffer for it */
2312 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2315 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2318 /* Recursively delete all the subkeys */
2319 for(i = 0; i < dwKeyCount && !dwRet; i++)
2321 dwSize = dwMaxSubkeyLen;
2322 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2324 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2327 if (lpszName != szNameBuf)
2328 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2332 RegCloseKey(hSubKey);
2334 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2339 /*****************************************************************************
2340 * DeletePrinter [WINSPOOL.@]
2342 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2344 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2345 HKEY hkeyPrinters, hkey;
2348 SetLastError(ERROR_INVALID_HANDLE);
2351 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2352 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2353 RegCloseKey(hkeyPrinters);
2355 WriteProfileStringW(devicesW, lpNameW, NULL);
2356 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2357 RegDeleteValueW(hkey, lpNameW);
2363 /*****************************************************************************
2364 * SetPrinterA [WINSPOOL.@]
2366 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2369 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2373 /*****************************************************************************
2374 * SetJobA [WINSPOOL.@]
2376 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2377 LPBYTE pJob, DWORD Command)
2381 UNICODE_STRING usBuffer;
2383 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2385 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2386 are all ignored by SetJob, so we don't bother copying them */
2394 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2395 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2397 JobW = (LPBYTE)info1W;
2398 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2399 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2400 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2401 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2402 info1W->Status = info1A->Status;
2403 info1W->Priority = info1A->Priority;
2404 info1W->Position = info1A->Position;
2405 info1W->PagesPrinted = info1A->PagesPrinted;
2410 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2411 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2413 JobW = (LPBYTE)info2W;
2414 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2415 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2416 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2417 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2418 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2419 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2420 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2421 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2422 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2423 info2W->Status = info2A->Status;
2424 info2W->Priority = info2A->Priority;
2425 info2W->Position = info2A->Position;
2426 info2W->StartTime = info2A->StartTime;
2427 info2W->UntilTime = info2A->UntilTime;
2428 info2W->PagesPrinted = info2A->PagesPrinted;
2432 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2433 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2436 SetLastError(ERROR_INVALID_LEVEL);
2440 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2446 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2447 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2448 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2449 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2450 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2455 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2456 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2457 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2458 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2459 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2460 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2461 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2462 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2463 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2467 HeapFree(GetProcessHeap(), 0, JobW);
2472 /*****************************************************************************
2473 * SetJobW [WINSPOOL.@]
2475 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2476 LPBYTE pJob, DWORD Command)
2481 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2482 FIXME("Ignoring everything other than document title\n");
2484 EnterCriticalSection(&printer_handles_cs);
2485 job = get_job(hPrinter, JobId);
2495 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2496 HeapFree(GetProcessHeap(), 0, job->document_title);
2497 job->document_title = strdupW(info1->pDocument);
2502 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2503 HeapFree(GetProcessHeap(), 0, job->document_title);
2504 job->document_title = strdupW(info2->pDocument);
2510 SetLastError(ERROR_INVALID_LEVEL);
2515 LeaveCriticalSection(&printer_handles_cs);
2519 /*****************************************************************************
2520 * EndDocPrinter [WINSPOOL.@]
2522 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2524 opened_printer_t *printer;
2526 TRACE("(%p)\n", hPrinter);
2528 EnterCriticalSection(&printer_handles_cs);
2530 printer = get_opened_printer(hPrinter);
2533 SetLastError(ERROR_INVALID_HANDLE);
2539 SetLastError(ERROR_SPL_NO_STARTDOC);
2543 CloseHandle(printer->doc->hf);
2544 ScheduleJob(hPrinter, printer->doc->job_id);
2545 HeapFree(GetProcessHeap(), 0, printer->doc);
2546 printer->doc = NULL;
2549 LeaveCriticalSection(&printer_handles_cs);
2553 /*****************************************************************************
2554 * EndPagePrinter [WINSPOOL.@]
2556 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2558 FIXME("(%p): stub\n", hPrinter);
2562 /*****************************************************************************
2563 * StartDocPrinterA [WINSPOOL.@]
2565 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2567 UNICODE_STRING usBuffer;
2569 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2572 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2573 or one (DOC_INFO_3) extra DWORDs */
2577 doc2W.JobId = doc2->JobId;
2580 doc2W.dwMode = doc2->dwMode;
2583 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2584 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2585 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2589 SetLastError(ERROR_INVALID_LEVEL);
2593 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2595 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2596 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2597 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2602 /*****************************************************************************
2603 * StartDocPrinterW [WINSPOOL.@]
2605 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2607 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2608 opened_printer_t *printer;
2609 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2610 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2611 JOB_INFO_1W job_info;
2612 DWORD needed, ret = 0;
2616 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2617 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2618 debugstr_w(doc->pDatatype));
2620 if(Level < 1 || Level > 3)
2622 SetLastError(ERROR_INVALID_LEVEL);
2626 EnterCriticalSection(&printer_handles_cs);
2627 printer = get_opened_printer(hPrinter);
2630 SetLastError(ERROR_INVALID_HANDLE);
2636 SetLastError(ERROR_INVALID_PRINTER_STATE);
2640 /* Even if we're printing to a file we still add a print job, we'll
2641 just ignore the spool file name */
2643 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2645 ERR("AddJob failed gle %08lx\n", GetLastError());
2649 if(doc->pOutputFile)
2650 filename = doc->pOutputFile;
2652 filename = addjob->Path;
2654 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2655 if(hf == INVALID_HANDLE_VALUE)
2658 memset(&job_info, 0, sizeof(job_info));
2659 job_info.pDocument = doc->pDocName;
2660 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2662 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2663 printer->doc->hf = hf;
2664 ret = printer->doc->job_id = addjob->JobId;
2666 LeaveCriticalSection(&printer_handles_cs);
2671 /*****************************************************************************
2672 * StartPagePrinter [WINSPOOL.@]
2674 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2676 FIXME("(%p): stub\n", hPrinter);
2680 /*****************************************************************************
2681 * GetFormA [WINSPOOL.@]
2683 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2684 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2686 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2687 Level,pForm,cbBuf,pcbNeeded);
2691 /*****************************************************************************
2692 * GetFormW [WINSPOOL.@]
2694 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2695 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2697 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2698 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2702 /*****************************************************************************
2703 * SetFormA [WINSPOOL.@]
2705 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2708 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2712 /*****************************************************************************
2713 * SetFormW [WINSPOOL.@]
2715 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2718 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2722 /*****************************************************************************
2723 * ReadPrinter [WINSPOOL.@]
2725 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2726 LPDWORD pNoBytesRead)
2728 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2732 /*****************************************************************************
2733 * ResetPrinterA [WINSPOOL.@]
2735 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2737 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2741 /*****************************************************************************
2742 * ResetPrinterW [WINSPOOL.@]
2744 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2746 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2750 /*****************************************************************************
2751 * WINSPOOL_GetDWORDFromReg
2753 * Return DWORD associated with ValueName from hkey.
2755 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2757 DWORD sz = sizeof(DWORD), type, value = 0;
2760 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2762 if(ret != ERROR_SUCCESS) {
2763 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2766 if(type != REG_DWORD) {
2767 ERR("Got type %ld\n", type);
2773 /*****************************************************************************
2774 * WINSPOOL_GetStringFromReg
2776 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2777 * String is stored either as unicode or ascii.
2778 * Bit of a hack here to get the ValueName if we want ascii.
2780 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2781 DWORD buflen, DWORD *needed,
2784 DWORD sz = buflen, type;
2788 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2790 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2791 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2792 HeapFree(GetProcessHeap(),0,ValueNameA);
2794 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2795 WARN("Got ret = %ld\n", ret);
2799 /* add space for terminating '\0' */
2800 sz += unicode ? sizeof(WCHAR) : 1;
2804 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2809 /*****************************************************************************
2810 * WINSPOOL_GetDefaultDevMode
2812 * Get a default DevMode values for wineps.
2816 static void WINSPOOL_GetDefaultDevMode(
2818 DWORD buflen, DWORD *needed,
2822 static const char szwps[] = "wineps.drv";
2824 /* fill default DEVMODE - should be read from ppd... */
2825 ZeroMemory( &dm, sizeof(dm) );
2826 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2827 dm.dmSpecVersion = DM_SPECVERSION;
2828 dm.dmDriverVersion = 1;
2829 dm.dmSize = sizeof(DEVMODEA);
2830 dm.dmDriverExtra = 0;
2832 DM_ORIENTATION | DM_PAPERSIZE |
2833 DM_PAPERLENGTH | DM_PAPERWIDTH |
2836 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2837 DM_YRESOLUTION | DM_TTOPTION;
2839 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2840 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2841 dm.u1.s1.dmPaperLength = 2970;
2842 dm.u1.s1.dmPaperWidth = 2100;
2846 dm.dmDefaultSource = DMBIN_AUTO;
2847 dm.dmPrintQuality = DMRES_MEDIUM;
2850 dm.dmYResolution = 300; /* 300dpi */
2851 dm.dmTTOption = DMTT_BITMAP;
2854 /* dm.dmLogPixels */
2855 /* dm.dmBitsPerPel */
2856 /* dm.dmPelsWidth */
2857 /* dm.dmPelsHeight */
2858 /* dm.dmDisplayFlags */
2859 /* dm.dmDisplayFrequency */
2860 /* dm.dmICMMethod */
2861 /* dm.dmICMIntent */
2862 /* dm.dmMediaType */
2863 /* dm.dmDitherType */
2864 /* dm.dmReserved1 */
2865 /* dm.dmReserved2 */
2866 /* dm.dmPanningWidth */
2867 /* dm.dmPanningHeight */
2870 if(buflen >= sizeof(DEVMODEW)) {
2871 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2872 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2873 HeapFree(GetProcessHeap(),0,pdmW);
2875 *needed = sizeof(DEVMODEW);
2879 if(buflen >= sizeof(DEVMODEA)) {
2880 memcpy(ptr, &dm, sizeof(DEVMODEA));
2882 *needed = sizeof(DEVMODEA);
2886 /*****************************************************************************
2887 * WINSPOOL_GetDevModeFromReg
2889 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2890 * DevMode is stored either as unicode or ascii.
2892 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2894 DWORD buflen, DWORD *needed,
2897 DWORD sz = buflen, type;
2900 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2901 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2902 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2903 if (sz < sizeof(DEVMODEA))
2905 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2908 /* ensures that dmSize is not erratically bogus if registry is invalid */
2909 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2910 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2912 sz += (CCHDEVICENAME + CCHFORMNAME);
2914 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2915 memcpy(ptr, dmW, sz);
2916 HeapFree(GetProcessHeap(),0,dmW);
2923 /*********************************************************************
2924 * WINSPOOL_GetPrinter_2
2926 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2927 * The strings are either stored as unicode or ascii.
2929 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2930 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2933 DWORD size, left = cbBuf;
2934 BOOL space = (cbBuf > 0);
2939 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2941 if(space && size <= left) {
2942 pi2->pPrinterName = (LPWSTR)ptr;
2949 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2951 if(space && size <= left) {
2952 pi2->pShareName = (LPWSTR)ptr;
2959 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2961 if(space && size <= left) {
2962 pi2->pPortName = (LPWSTR)ptr;
2969 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2971 if(space && size <= left) {
2972 pi2->pDriverName = (LPWSTR)ptr;
2979 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2981 if(space && size <= left) {
2982 pi2->pComment = (LPWSTR)ptr;
2989 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2991 if(space && size <= left) {
2992 pi2->pLocation = (LPWSTR)ptr;
2999 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3001 if(space && size <= left) {
3002 pi2->pDevMode = (LPDEVMODEW)ptr;
3011 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3012 if(space && size <= left) {
3013 pi2->pDevMode = (LPDEVMODEW)ptr;
3020 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3022 if(space && size <= left) {
3023 pi2->pSepFile = (LPWSTR)ptr;
3030 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3032 if(space && size <= left) {
3033 pi2->pPrintProcessor = (LPWSTR)ptr;
3040 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3042 if(space && size <= left) {
3043 pi2->pDatatype = (LPWSTR)ptr;
3050 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3052 if(space && size <= left) {
3053 pi2->pParameters = (LPWSTR)ptr;
3061 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3062 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3063 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3064 "Default Priority");
3065 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3066 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3069 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3070 memset(pi2, 0, sizeof(*pi2));
3075 /*********************************************************************
3076 * WINSPOOL_GetPrinter_4
3078 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3080 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3081 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3084 DWORD size, left = cbBuf;
3085 BOOL space = (cbBuf > 0);
3090 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3092 if(space && size <= left) {
3093 pi4->pPrinterName = (LPWSTR)ptr;
3101 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3104 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3105 memset(pi4, 0, sizeof(*pi4));
3110 /*********************************************************************
3111 * WINSPOOL_GetPrinter_5
3113 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3115 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3116 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3119 DWORD size, left = cbBuf;
3120 BOOL space = (cbBuf > 0);
3125 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3127 if(space && size <= left) {
3128 pi5->pPrinterName = (LPWSTR)ptr;
3135 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3137 if(space && size <= left) {
3138 pi5->pPortName = (LPWSTR)ptr;
3146 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3147 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3149 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3153 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3154 memset(pi5, 0, sizeof(*pi5));
3159 /*****************************************************************************
3160 * WINSPOOL_GetPrinter
3162 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3163 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3164 * just a collection of pointers to strings.
3166 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3167 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3170 DWORD size, needed = 0;
3172 HKEY hkeyPrinter, hkeyPrinters;
3175 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3177 if (!(name = get_opened_printer_name(hPrinter))) {
3178 SetLastError(ERROR_INVALID_HANDLE);
3182 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3184 ERR("Can't create Printers key\n");
3187 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3189 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3190 RegCloseKey(hkeyPrinters);
3191 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3198 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3200 size = sizeof(PRINTER_INFO_2W);
3202 ptr = pPrinter + size;
3204 memset(pPrinter, 0, size);
3209 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3217 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3219 size = sizeof(PRINTER_INFO_4W);
3221 ptr = pPrinter + size;
3223 memset(pPrinter, 0, size);
3228 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3237 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3239 size = sizeof(PRINTER_INFO_5W);
3241 ptr = pPrinter + size;
3243 memset(pPrinter, 0, size);
3249 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3256 FIXME("Unimplemented level %ld\n", Level);
3257 SetLastError(ERROR_INVALID_LEVEL);
3258 RegCloseKey(hkeyPrinters);
3259 RegCloseKey(hkeyPrinter);
3263 RegCloseKey(hkeyPrinter);
3264 RegCloseKey(hkeyPrinters);
3266 TRACE("returning %d needed = %ld\n", ret, needed);
3267 if(pcbNeeded) *pcbNeeded = needed;
3269 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3273 /*****************************************************************************
3274 * GetPrinterW [WINSPOOL.@]
3276 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3277 DWORD cbBuf, LPDWORD pcbNeeded)
3279 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3283 /*****************************************************************************
3284 * GetPrinterA [WINSPOOL.@]
3286 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3287 DWORD cbBuf, LPDWORD pcbNeeded)
3289 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3293 /*****************************************************************************
3294 * WINSPOOL_EnumPrinters
3296 * Implementation of EnumPrintersA|W
3298 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3299 DWORD dwLevel, LPBYTE lpbPrinters,
3300 DWORD cbBuf, LPDWORD lpdwNeeded,
3301 LPDWORD lpdwReturned, BOOL unicode)
3304 HKEY hkeyPrinters, hkeyPrinter;
3305 WCHAR PrinterName[255];
3306 DWORD needed = 0, number = 0;
3307 DWORD used, i, left;
3311 memset(lpbPrinters, 0, cbBuf);
3317 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3318 if(dwType == PRINTER_ENUM_DEFAULT)
3321 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3322 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3323 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3324 if(!dwType) return TRUE;
3327 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3328 FIXME("dwType = %08lx\n", dwType);
3329 SetLastError(ERROR_INVALID_FLAGS);
3333 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3335 ERR("Can't create Printers key\n");
3339 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3340 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3341 RegCloseKey(hkeyPrinters);
3342 ERR("Can't query Printers key\n");
3345 TRACE("Found %ld printers\n", number);
3349 RegCloseKey(hkeyPrinters);
3351 *lpdwReturned = number;
3355 used = number * sizeof(PRINTER_INFO_2W);
3358 used = number * sizeof(PRINTER_INFO_4W);
3361 used = number * sizeof(PRINTER_INFO_5W);
3365 SetLastError(ERROR_INVALID_LEVEL);
3366 RegCloseKey(hkeyPrinters);
3369 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3371 for(i = 0; i < number; i++) {
3372 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3374 ERR("Can't enum key number %ld\n", i);
3375 RegCloseKey(hkeyPrinters);
3378 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3379 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3381 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3382 RegCloseKey(hkeyPrinters);
3387 buf = lpbPrinters + used;
3388 left = cbBuf - used;
3396 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3397 left, &needed, unicode);
3399 if(pi) pi += sizeof(PRINTER_INFO_2W);
3402 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3403 left, &needed, unicode);
3405 if(pi) pi += sizeof(PRINTER_INFO_4W);
3408 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3409 left, &needed, unicode);
3411 if(pi) pi += sizeof(PRINTER_INFO_5W);
3414 ERR("Shouldn't be here!\n");
3415 RegCloseKey(hkeyPrinter);
3416 RegCloseKey(hkeyPrinters);
3419 RegCloseKey(hkeyPrinter);
3421 RegCloseKey(hkeyPrinters);
3428 memset(lpbPrinters, 0, cbBuf);
3429 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3433 *lpdwReturned = number;
3434 SetLastError(ERROR_SUCCESS);
3439 /******************************************************************
3440 * EnumPrintersW [WINSPOOL.@]
3442 * Enumerates the available printers, print servers and print
3443 * providers, depending on the specified flags, name and level.
3447 * If level is set to 1:
3448 * Not implemented yet!
3449 * Returns TRUE with an empty list.
3451 * If level is set to 2:
3452 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3453 * Returns an array of PRINTER_INFO_2 data structures in the
3454 * lpbPrinters buffer. Note that according to MSDN also an
3455 * OpenPrinter should be performed on every remote printer.
3457 * If level is set to 4 (officially WinNT only):
3458 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3459 * Fast: Only the registry is queried to retrieve printer names,
3460 * no connection to the driver is made.
3461 * Returns an array of PRINTER_INFO_4 data structures in the
3462 * lpbPrinters buffer.
3464 * If level is set to 5 (officially WinNT4/Win9x only):
3465 * Fast: Only the registry is queried to retrieve printer names,
3466 * no connection to the driver is made.
3467 * Returns an array of PRINTER_INFO_5 data structures in the
3468 * lpbPrinters buffer.
3470 * If level set to 3 or 6+:
3471 * returns zero (failure!)
3473 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3477 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3478 * - Only levels 2, 4 and 5 are implemented at the moment.
3479 * - 16-bit printer drivers are not enumerated.
3480 * - Returned amount of bytes used/needed does not match the real Windoze
3481 * implementation (as in this implementation, all strings are part
3482 * of the buffer, whereas Win32 keeps them somewhere else)
3483 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3486 * - In a regular Wine installation, no registry settings for printers
3487 * exist, which makes this function return an empty list.
3489 BOOL WINAPI EnumPrintersW(
3490 DWORD dwType, /* [in] Types of print objects to enumerate */
3491 LPWSTR lpszName, /* [in] name of objects to enumerate */
3492 DWORD dwLevel, /* [in] type of printer info structure */
3493 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3494 DWORD cbBuf, /* [in] max size of buffer in bytes */
3495 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3496 LPDWORD lpdwReturned /* [out] number of entries returned */
3499 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3500 lpdwNeeded, lpdwReturned, TRUE);
3503 /******************************************************************
3504 * EnumPrintersA [WINSPOOL.@]
3507 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3508 DWORD dwLevel, LPBYTE lpbPrinters,
3509 DWORD cbBuf, LPDWORD lpdwNeeded,
3510 LPDWORD lpdwReturned)
3513 UNICODE_STRING lpszNameW;
3516 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3517 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3518 lpdwNeeded, lpdwReturned, FALSE);
3519 RtlFreeUnicodeString(&lpszNameW);
3523 /*****************************************************************************
3524 * WINSPOOL_GetDriverInfoFromReg [internal]
3526 * Enters the information from the registry into the DRIVER_INFO struct
3529 * zero if the printer driver does not exist in the registry
3530 * (only if Level > 1) otherwise nonzero
3532 static BOOL WINSPOOL_GetDriverInfoFromReg(
3535 LPWSTR pEnvironment,
3537 LPBYTE ptr, /* DRIVER_INFO */
3538 LPBYTE pDriverStrings, /* strings buffer */
3539 DWORD cbBuf, /* size of string buffer */
3540 LPDWORD pcbNeeded, /* space needed for str. */
3541 BOOL unicode) /* type of strings */
3545 LPBYTE strPtr = pDriverStrings;
3547 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3548 debugstr_w(DriverName), debugstr_w(pEnvironment),
3549 Level, ptr, pDriverStrings, cbBuf, unicode);
3552 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3553 if (*pcbNeeded <= cbBuf)
3554 strcpyW((LPWSTR)strPtr, DriverName);
3556 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3558 if(*pcbNeeded <= cbBuf)
3559 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3560 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3564 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3568 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3569 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3572 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3573 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3574 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3579 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3582 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3584 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3586 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3589 if(*pcbNeeded <= cbBuf) {
3591 strcpyW((LPWSTR)strPtr, pEnvironment);
3593 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3594 (LPSTR)strPtr, size, NULL, NULL);
3596 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3597 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3600 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3603 if(*pcbNeeded <= cbBuf)
3604 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3607 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3608 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3611 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3614 if(*pcbNeeded <= cbBuf)
3615 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3618 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3619 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3622 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3623 0, &size, unicode)) {
3625 if(*pcbNeeded <= cbBuf)
3626 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3627 size, &tmp, unicode);
3629 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3630 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3634 RegCloseKey(hkeyDriver);
3635 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3639 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3642 if(*pcbNeeded <= cbBuf)
3643 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3644 size, &tmp, unicode);
3646 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3647 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3650 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3653 if(*pcbNeeded <= cbBuf)
3654 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3655 size, &tmp, unicode);
3657 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3658 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3661 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3664 if(*pcbNeeded <= cbBuf)
3665 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3666 size, &tmp, unicode);
3668 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3669 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3672 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3675 if(*pcbNeeded <= cbBuf)
3676 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3677 size, &tmp, unicode);
3679 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3680 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3683 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3684 RegCloseKey(hkeyDriver);
3688 /*****************************************************************************
3689 * WINSPOOL_GetPrinterDriver
3691 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3692 DWORD Level, LPBYTE pDriverInfo,
3693 DWORD cbBuf, LPDWORD pcbNeeded,
3697 WCHAR DriverName[100];
3698 DWORD ret, type, size, needed = 0;
3700 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3702 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3703 Level,pDriverInfo,cbBuf, pcbNeeded);
3705 ZeroMemory(pDriverInfo, cbBuf);
3707 if (!(name = get_opened_printer_name(hPrinter))) {
3708 SetLastError(ERROR_INVALID_HANDLE);
3711 if(Level < 1 || Level > 6) {
3712 SetLastError(ERROR_INVALID_LEVEL);
3715 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3717 ERR("Can't create Printers key\n");
3720 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3722 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3723 RegCloseKey(hkeyPrinters);
3724 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3727 size = sizeof(DriverName);
3729 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3730 (LPBYTE)DriverName, &size);
3731 RegCloseKey(hkeyPrinter);
3732 RegCloseKey(hkeyPrinters);
3733 if(ret != ERROR_SUCCESS) {
3734 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3738 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3740 ERR("Can't create Drivers key\n");
3746 size = sizeof(DRIVER_INFO_1W);
3749 size = sizeof(DRIVER_INFO_2W);
3752 size = sizeof(DRIVER_INFO_3W);
3755 size = sizeof(DRIVER_INFO_4W);
3758 size = sizeof(DRIVER_INFO_5W);
3761 size = sizeof(DRIVER_INFO_6W);
3764 ERR("Invalid level\n");
3769 ptr = pDriverInfo + size;
3771 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3772 pEnvironment, Level, pDriverInfo,
3773 (cbBuf < size) ? NULL : ptr,
3774 (cbBuf < size) ? 0 : cbBuf - size,
3775 &needed, unicode)) {
3776 RegCloseKey(hkeyDrivers);
3780 RegCloseKey(hkeyDrivers);
3782 if(pcbNeeded) *pcbNeeded = size + needed;
3783 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3784 if(cbBuf >= needed) return TRUE;
3785 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3789 /*****************************************************************************
3790 * GetPrinterDriverA [WINSPOOL.@]
3792 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3793 DWORD Level, LPBYTE pDriverInfo,
3794 DWORD cbBuf, LPDWORD pcbNeeded)
3797 UNICODE_STRING pEnvW;
3800 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3801 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3802 cbBuf, pcbNeeded, FALSE);
3803 RtlFreeUnicodeString(&pEnvW);
3806 /*****************************************************************************
3807 * GetPrinterDriverW [WINSPOOL.@]
3809 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3810 DWORD Level, LPBYTE pDriverInfo,
3811 DWORD cbBuf, LPDWORD pcbNeeded)
3813 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3814 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3817 /*****************************************************************************
3818 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3820 * Return the PATH for the Printer-Drivers (UNICODE)
3823 * pName [I] Servername (NT only) or NULL (local Computer)
3824 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3825 * Level [I] Structure-Level (must be 1)
3826 * pDriverDirectory [O] PTR to Buffer that receives the Result
3827 * cbBuf [I] Size of Buffer at pDriverDirectory
3828 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3829 * required for pDriverDirectory
3832 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3833 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3834 * if cbBuf is too small
3836 * Native Values returned in pDriverDirectory on Success:
3837 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3838 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3839 *| win9x(Windows 4.0): "%winsysdir%"
3841 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3844 *- Only NULL or "" is supported for pName
3847 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3848 DWORD Level, LPBYTE pDriverDirectory,
3849 DWORD cbBuf, LPDWORD pcbNeeded)
3852 const printenv_t * env;
3854 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3855 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3856 if(pName != NULL && pName[0]) {
3857 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3858 SetLastError(ERROR_INVALID_PARAMETER);
3862 env = validate_envW(pEnvironment);
3863 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3866 WARN("(Level: %ld) is ignored in win9x\n", Level);
3867 SetLastError(ERROR_INVALID_LEVEL);
3871 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3872 needed = GetSystemDirectoryW(NULL, 0);
3873 /* add the Size for the Subdirectories */
3874 needed += lstrlenW(spooldriversW);
3875 needed += lstrlenW(env->subdir);
3876 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3879 *pcbNeeded = needed;
3880 TRACE("required: 0x%lx/%ld\n", needed, needed);
3881 if(needed > cbBuf) {
3882 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3885 if(pcbNeeded == NULL) {
3886 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3887 SetLastError(RPC_X_NULL_REF_POINTER);
3890 if(pDriverDirectory == NULL) {
3891 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3892 SetLastError(ERROR_INVALID_USER_BUFFER);
3896 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3897 /* add the Subdirectories */
3898 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3899 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3900 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3905 /*****************************************************************************
3906 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3908 * Return the PATH for the Printer-Drivers (ANSI)
3910 * See GetPrinterDriverDirectoryW.
3913 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3916 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3917 DWORD Level, LPBYTE pDriverDirectory,
3918 DWORD cbBuf, LPDWORD pcbNeeded)
3920 UNICODE_STRING nameW, environmentW;
3923 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3924 WCHAR *driverDirectoryW = NULL;
3926 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3927 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3929 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3931 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3932 else nameW.Buffer = NULL;
3933 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3934 else environmentW.Buffer = NULL;
3936 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3937 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3940 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3941 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3943 *pcbNeeded = needed;
3944 ret = (needed <= cbBuf) ? TRUE : FALSE;
3946 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3948 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3950 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3951 RtlFreeUnicodeString(&environmentW);
3952 RtlFreeUnicodeString(&nameW);
3957 /*****************************************************************************
3958 * AddPrinterDriverA [WINSPOOL.@]
3960 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3963 HKEY hkeyDrivers, hkeyName;
3964 static CHAR empty[] = "",
3967 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3969 if(level != 2 && level != 3) {
3970 SetLastError(ERROR_INVALID_LEVEL);
3973 if ((pName) && (pName[0])) {
3974 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3975 SetLastError(ERROR_INVALID_PARAMETER);
3979 WARN("pDriverInfo == NULL\n");
3980 SetLastError(ERROR_INVALID_PARAMETER);
3985 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3987 memset(&di3, 0, sizeof(di3));
3988 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3991 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3993 SetLastError(ERROR_INVALID_PARAMETER);
3997 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
3998 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
3999 if(!di3.pHelpFile) di3.pHelpFile = empty;
4000 if(!di3.pMonitorName) di3.pMonitorName = empty;
4002 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4005 ERR("Can't create Drivers key\n");
4009 if(level == 2) { /* apparently can't overwrite with level2 */
4010 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4011 RegCloseKey(hkeyName);
4012 RegCloseKey(hkeyDrivers);
4013 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4014 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4018 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4019 RegCloseKey(hkeyDrivers);
4020 ERR("Can't create Name key\n");
4023 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4025 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
4026 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
4027 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4029 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4030 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4031 (LPBYTE) di3.pDependentFiles, 0);
4032 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4033 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4034 RegCloseKey(hkeyName);
4035 RegCloseKey(hkeyDrivers);
4040 /*****************************************************************************
4041 * AddPrinterDriverW [WINSPOOL.@]
4043 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4046 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4051 /*****************************************************************************
4052 * AddPrintProcessorA [WINSPOOL.@]
4054 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4055 LPSTR pPrintProcessorName)
4057 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4058 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4062 /*****************************************************************************
4063 * AddPrintProcessorW [WINSPOOL.@]
4065 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4066 LPWSTR pPrintProcessorName)
4068 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4069 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4073 /*****************************************************************************
4074 * AddPrintProvidorA [WINSPOOL.@]
4076 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4078 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4082 /*****************************************************************************
4083 * AddPrintProvidorW [WINSPOOL.@]
4085 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4087 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4091 /*****************************************************************************
4092 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4094 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4095 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4097 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4098 pDevModeOutput, pDevModeInput);
4102 /*****************************************************************************
4103 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4105 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4106 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4108 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4109 pDevModeOutput, pDevModeInput);
4113 /*****************************************************************************
4114 * PrinterProperties [WINSPOOL.@]
4116 * Displays a dialog to set the properties of the printer.
4119 * nonzero on success or zero on failure
4122 * implemented as stub only
4124 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4125 HANDLE hPrinter /* [in] handle to printer object */
4127 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4128 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4132 /*****************************************************************************
4133 * EnumJobsA [WINSPOOL.@]
4136 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4137 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4140 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4141 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4143 if(pcbNeeded) *pcbNeeded = 0;
4144 if(pcReturned) *pcReturned = 0;
4149 /*****************************************************************************
4150 * EnumJobsW [WINSPOOL.@]
4153 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4154 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4157 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4158 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4160 if(pcbNeeded) *pcbNeeded = 0;
4161 if(pcReturned) *pcReturned = 0;
4165 /*****************************************************************************
4166 * WINSPOOL_EnumPrinterDrivers [internal]
4168 * Delivers information about all printer drivers installed on the
4169 * localhost or a given server
4172 * nonzero on success or zero on failure. If the buffer for the returned
4173 * information is too small the function will return an error
4176 * - only implemented for localhost, foreign hosts will return an error
4178 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4179 DWORD Level, LPBYTE pDriverInfo,
4180 DWORD cbBuf, LPDWORD pcbNeeded,
4181 LPDWORD pcReturned, BOOL unicode)
4184 DWORD i, needed, number = 0, size = 0;
4185 WCHAR DriverNameW[255];
4188 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4189 debugstr_w(pName), debugstr_w(pEnvironment),
4190 Level, pDriverInfo, cbBuf, unicode);
4192 /* check for local drivers */
4193 if((pName) && (pName[0])) {
4194 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4195 SetLastError(ERROR_ACCESS_DENIED);
4199 /* check input parameter */
4200 if((Level < 1) || (Level > 3)) {
4201 ERR("unsupported level %ld\n", Level);
4202 SetLastError(ERROR_INVALID_LEVEL);
4206 /* initialize return values */
4208 memset( pDriverInfo, 0, cbBuf);
4212 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4214 ERR("Can't open Drivers key\n");
4218 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4219 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4220 RegCloseKey(hkeyDrivers);
4221 ERR("Can't query Drivers key\n");
4224 TRACE("Found %ld Drivers\n", number);
4226 /* get size of single struct
4227 * unicode and ascii structure have the same size
4231 size = sizeof(DRIVER_INFO_1A);
4234 size = sizeof(DRIVER_INFO_2A);
4237 size = sizeof(DRIVER_INFO_3A);
4241 /* calculate required buffer size */
4242 *pcbNeeded = size * number;
4244 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4246 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4247 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4249 ERR("Can't enum key number %ld\n", i);
4250 RegCloseKey(hkeyDrivers);
4253 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4254 pEnvironment, Level, ptr,
4255 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4256 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4257 &needed, unicode)) {
4258 RegCloseKey(hkeyDrivers);
4261 (*pcbNeeded) += needed;
4264 RegCloseKey(hkeyDrivers);
4266 if(cbBuf < *pcbNeeded){
4267 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4271 *pcReturned = number;
4275 /*****************************************************************************
4276 * EnumPrinterDriversW [WINSPOOL.@]
4278 * see function EnumPrinterDrivers for RETURNS, BUGS
4280 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4281 LPBYTE pDriverInfo, DWORD cbBuf,
4282 LPDWORD pcbNeeded, LPDWORD pcReturned)
4284 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4285 cbBuf, pcbNeeded, pcReturned, TRUE);
4288 /*****************************************************************************
4289 * EnumPrinterDriversA [WINSPOOL.@]
4291 * see function EnumPrinterDrivers for RETURNS, BUGS
4293 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4294 LPBYTE pDriverInfo, DWORD cbBuf,
4295 LPDWORD pcbNeeded, LPDWORD pcReturned)
4297 UNICODE_STRING pNameW, pEnvironmentW;
4298 PWSTR pwstrNameW, pwstrEnvironmentW;
4300 pwstrNameW = asciitounicode(&pNameW, pName);
4301 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4303 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4304 Level, pDriverInfo, cbBuf, pcbNeeded,
4306 RtlFreeUnicodeString(&pNameW);
4307 RtlFreeUnicodeString(&pEnvironmentW);
4312 static CHAR PortMonitor[] = "Wine Port Monitor";
4313 static CHAR PortDescription[] = "Wine Port";
4315 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4319 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4320 NULL, OPEN_EXISTING, 0, NULL );
4321 if (handle == INVALID_HANDLE_VALUE)
4323 TRACE("Checking %s exists\n", name );
4324 CloseHandle( handle );
4328 static DWORD WINSPOOL_CountSerialPorts(void)
4335 strcpy( name, "COMx:" );
4337 if (WINSPOOL_ComPortExists( name ))
4344 /******************************************************************************
4345 * EnumPortsA (WINSPOOL.@)
4350 * ANSI-Version did not call the UNICODE-Version
4353 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4354 LPDWORD bufneeded,LPDWORD bufreturned)
4357 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4358 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4362 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4363 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4368 info_size = sizeof (PORT_INFO_1A);
4371 info_size = sizeof (PORT_INFO_2A);
4374 SetLastError(ERROR_INVALID_LEVEL);
4378 /* see how many exist */
4381 serial_count = WINSPOOL_CountSerialPorts();
4384 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4385 if ( r == ERROR_SUCCESS )
4387 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4388 &printer_count, NULL, NULL, NULL, NULL);
4390 count = serial_count + printer_count;
4392 /* then fill in the structure info structure once
4393 we know the offset to the first string */
4395 memset( buffer, 0, bufsize );
4397 ofs = info_size*count;
4398 for ( i=0; i<count; i++)
4400 DWORD vallen = sizeof(portname) - 1;
4402 /* get the serial port values, then the printer values */
4403 if ( i < serial_count )
4405 strcpy( portname, "COMx:" );
4406 portname[3] = '1' + i;
4407 if (!WINSPOOL_ComPortExists( portname ))
4410 TRACE("Found %s\n", portname );
4411 vallen = strlen( portname );
4415 r = RegEnumValueA( hkey_printer, i-serial_count,
4416 portname, &vallen, NULL, NULL, NULL, 0 );
4421 /* add a colon if necessary, and make it upper case */
4422 CharUpperBuffA(portname,vallen);
4423 if (strcasecmp(portname,"nul")!=0)
4424 if (vallen && (portname[vallen-1] != ':') )
4425 lstrcatA(portname,":");
4427 /* add the port info structure if we can fit it */
4428 if ( info_size*(n+1) < bufsize )
4432 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4433 info->pName = (LPSTR) &buffer[ofs];
4435 else if ( level == 2)
4437 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4438 info->pPortName = (LPSTR) &buffer[ofs];
4439 /* FIXME: fill in more stuff here */
4440 info->pMonitorName = PortMonitor;
4441 info->pDescription = PortDescription;
4442 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4445 /* add the name of the port if we can fit it */
4446 if ( ofs < bufsize )
4447 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4453 ofs += lstrlenA(portname)+1;
4456 RegCloseKey(hkey_printer);
4467 /******************************************************************************
4468 * EnumPortsW (WINSPOOL.@)
4470 * Enumerate available Ports
4473 * name [I] Servername or NULL (local Computer)
4474 * level [I] Structure-Level (1 or 2)
4475 * buffer [O] PTR to Buffer that receives the Result
4476 * bufsize [I] Size of Buffer at buffer
4477 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4478 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4482 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4485 * UNICODE-Version is a stub
4488 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4489 LPDWORD bufneeded,LPDWORD bufreturned)
4491 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4492 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4496 /******************************************************************************
4497 * GetDefaultPrinterW (WINSPOOL.@)
4500 * This function must read the value from data 'device' of key
4501 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4503 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4507 WCHAR *buffer, *ptr;
4511 SetLastError(ERROR_INVALID_PARAMETER);
4515 /* make the buffer big enough for the stuff from the profile/registry,
4516 * the content must fit into the local buffer to compute the correct
4517 * size even if the extern buffer is too small or not given.
4518 * (20 for ,driver,port) */
4520 len = max(100, (insize + 20));
4521 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4523 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4525 SetLastError (ERROR_FILE_NOT_FOUND);
4529 TRACE("%s\n", debugstr_w(buffer));
4531 if ((ptr = strchrW(buffer, ',')) == NULL)
4533 SetLastError(ERROR_INVALID_NAME);
4539 *namesize = strlenW(buffer) + 1;
4540 if(!name || (*namesize > insize))
4542 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4546 strcpyW(name, buffer);
4549 HeapFree( GetProcessHeap(), 0, buffer);
4554 /******************************************************************************
4555 * GetDefaultPrinterA (WINSPOOL.@)
4557 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4561 WCHAR *bufferW = NULL;
4565 SetLastError(ERROR_INVALID_PARAMETER);
4569 if(name && *namesize) {
4571 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4574 if(!GetDefaultPrinterW( bufferW, namesize)) {
4579 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4583 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4586 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4589 HeapFree( GetProcessHeap(), 0, bufferW);
4594 /******************************************************************************
4595 * SetDefaultPrinterW (WINSPOOL.204)
4597 * Set the Name of the Default Printer
4600 * pszPrinter [I] Name of the Printer or NULL
4607 * When the Parameter is NULL or points to an Empty String and
4608 * a Default Printer was already present, then this Function changes nothing.
4609 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4610 * the First enumerated local Printer is used.
4613 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4616 TRACE("(%s)\n", debugstr_w(pszPrinter));
4618 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4622 /******************************************************************************
4623 * SetDefaultPrinterA (WINSPOOL.202)
4625 * See SetDefaultPrinterW.
4628 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4631 TRACE("(%s)\n", debugstr_a(pszPrinter));
4633 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4638 /******************************************************************************
4639 * SetPrinterDataExA (WINSPOOL.@)
4641 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4642 LPCSTR pValueName, DWORD Type,
4643 LPBYTE pData, DWORD cbData)
4645 HKEY hkeyPrinter, hkeySubkey;
4648 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4649 debugstr_a(pValueName), Type, pData, cbData);
4651 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4655 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4657 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4658 RegCloseKey(hkeyPrinter);
4661 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4662 RegCloseKey(hkeySubkey);
4663 RegCloseKey(hkeyPrinter);
4667 /******************************************************************************
4668 * SetPrinterDataExW (WINSPOOL.@)
4670 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4671 LPCWSTR pValueName, DWORD Type,
4672 LPBYTE pData, DWORD cbData)
4674 HKEY hkeyPrinter, hkeySubkey;
4677 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4678 debugstr_w(pValueName), Type, pData, cbData);
4680 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4684 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4686 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4687 RegCloseKey(hkeyPrinter);
4690 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4691 RegCloseKey(hkeySubkey);
4692 RegCloseKey(hkeyPrinter);
4696 /******************************************************************************
4697 * SetPrinterDataA (WINSPOOL.@)
4699 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4700 LPBYTE pData, DWORD cbData)
4702 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4706 /******************************************************************************
4707 * SetPrinterDataW (WINSPOOL.@)
4709 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4710 LPBYTE pData, DWORD cbData)
4712 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4716 /******************************************************************************
4717 * GetPrinterDataExA (WINSPOOL.@)
4719 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4720 LPCSTR pValueName, LPDWORD pType,
4721 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4723 HKEY hkeyPrinter, hkeySubkey;
4726 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4727 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4730 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4734 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4736 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4737 RegCloseKey(hkeyPrinter);
4741 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4742 RegCloseKey(hkeySubkey);
4743 RegCloseKey(hkeyPrinter);
4747 /******************************************************************************
4748 * GetPrinterDataExW (WINSPOOL.@)
4750 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4751 LPCWSTR pValueName, LPDWORD pType,
4752 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4754 HKEY hkeyPrinter, hkeySubkey;
4757 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4758 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4761 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4765 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4767 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4768 RegCloseKey(hkeyPrinter);
4772 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4773 RegCloseKey(hkeySubkey);
4774 RegCloseKey(hkeyPrinter);
4778 /******************************************************************************
4779 * GetPrinterDataA (WINSPOOL.@)
4781 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4782 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4784 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4785 pData, nSize, pcbNeeded);
4788 /******************************************************************************
4789 * GetPrinterDataW (WINSPOOL.@)
4791 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4792 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4794 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4795 pData, nSize, pcbNeeded);
4798 /*******************************************************************************
4799 * EnumPrinterDataExW [WINSPOOL.@]
4801 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4802 LPBYTE pEnumValues, DWORD cbEnumValues,
4803 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4805 HKEY hkPrinter, hkSubKey;
4806 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4807 cbValueNameLen, cbMaxValueLen, cbValueLen,
4812 PPRINTER_ENUM_VALUESW ppev;
4814 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4816 if (pKeyName == NULL || *pKeyName == 0)
4817 return ERROR_INVALID_PARAMETER;
4819 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4820 if (ret != ERROR_SUCCESS)
4822 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4827 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4828 if (ret != ERROR_SUCCESS)
4830 r = RegCloseKey (hkPrinter);
4831 if (r != ERROR_SUCCESS)
4832 WARN ("RegCloseKey returned %li\n", r);
4833 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4834 debugstr_w (pKeyName), ret);
4838 ret = RegCloseKey (hkPrinter);
4839 if (ret != ERROR_SUCCESS)
4841 ERR ("RegCloseKey returned %li\n", ret);
4842 r = RegCloseKey (hkSubKey);
4843 if (r != ERROR_SUCCESS)
4844 WARN ("RegCloseKey returned %li\n", r);
4848 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4849 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4850 if (ret != ERROR_SUCCESS)
4852 r = RegCloseKey (hkSubKey);
4853 if (r != ERROR_SUCCESS)
4854 WARN ("RegCloseKey returned %li\n", r);
4855 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4859 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4860 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4862 if (cValues == 0) /* empty key */
4864 r = RegCloseKey (hkSubKey);
4865 if (r != ERROR_SUCCESS)
4866 WARN ("RegCloseKey returned %li\n", r);
4867 *pcbEnumValues = *pnEnumValues = 0;
4868 return ERROR_SUCCESS;
4871 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4873 hHeap = GetProcessHeap ();
4876 ERR ("GetProcessHeap failed\n");
4877 r = RegCloseKey (hkSubKey);
4878 if (r != ERROR_SUCCESS)
4879 WARN ("RegCloseKey returned %li\n", r);
4880 return ERROR_OUTOFMEMORY;
4883 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4884 if (lpValueName == NULL)
4886 ERR ("Failed to allocate %li bytes from process heap\n",
4887 cbMaxValueNameLen * sizeof (WCHAR));
4888 r = RegCloseKey (hkSubKey);
4889 if (r != ERROR_SUCCESS)
4890 WARN ("RegCloseKey returned %li\n", r);
4891 return ERROR_OUTOFMEMORY;
4894 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4895 if (lpValue == NULL)
4897 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4898 if (HeapFree (hHeap, 0, lpValueName) == 0)
4899 WARN ("HeapFree failed with code %li\n", GetLastError ());
4900 r = RegCloseKey (hkSubKey);
4901 if (r != ERROR_SUCCESS)
4902 WARN ("RegCloseKey returned %li\n", r);
4903 return ERROR_OUTOFMEMORY;
4906 TRACE ("pass 1: calculating buffer required for all names and values\n");
4908 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4910 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4912 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4914 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4915 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4916 NULL, NULL, lpValue, &cbValueLen);
4917 if (ret != ERROR_SUCCESS)
4919 if (HeapFree (hHeap, 0, lpValue) == 0)
4920 WARN ("HeapFree failed with code %li\n", GetLastError ());
4921 if (HeapFree (hHeap, 0, lpValueName) == 0)
4922 WARN ("HeapFree failed with code %li\n", GetLastError ());
4923 r = RegCloseKey (hkSubKey);
4924 if (r != ERROR_SUCCESS)
4925 WARN ("RegCloseKey returned %li\n", r);
4926 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4930 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4931 debugstr_w (lpValueName), dwIndex,
4932 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4934 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4935 cbBufSize += cbValueLen;
4938 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4940 *pcbEnumValues = cbBufSize;
4941 *pnEnumValues = cValues;
4943 if (cbEnumValues < cbBufSize) /* buffer too small */
4945 if (HeapFree (hHeap, 0, lpValue) == 0)
4946 WARN ("HeapFree failed with code %li\n", GetLastError ());
4947 if (HeapFree (hHeap, 0, lpValueName) == 0)
4948 WARN ("HeapFree failed with code %li\n", GetLastError ());
4949 r = RegCloseKey (hkSubKey);
4950 if (r != ERROR_SUCCESS)
4951 WARN ("RegCloseKey returned %li\n", r);
4952 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4953 return ERROR_MORE_DATA;
4956 TRACE ("pass 2: copying all names and values to buffer\n");
4958 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4959 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4961 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4963 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4964 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4965 NULL, &dwType, lpValue, &cbValueLen);
4966 if (ret != ERROR_SUCCESS)
4968 if (HeapFree (hHeap, 0, lpValue) == 0)
4969 WARN ("HeapFree failed with code %li\n", GetLastError ());
4970 if (HeapFree (hHeap, 0, lpValueName) == 0)
4971 WARN ("HeapFree failed with code %li\n", GetLastError ());
4972 r = RegCloseKey (hkSubKey);
4973 if (r != ERROR_SUCCESS)
4974 WARN ("RegCloseKey returned %li\n", r);
4975 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4979 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4980 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4981 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4982 pEnumValues += cbValueNameLen;
4984 /* return # of *bytes* (including trailing \0), not # of chars */
4985 ppev[dwIndex].cbValueName = cbValueNameLen;
4987 ppev[dwIndex].dwType = dwType;
4989 memcpy (pEnumValues, lpValue, cbValueLen);
4990 ppev[dwIndex].pData = pEnumValues;
4991 pEnumValues += cbValueLen;
4993 ppev[dwIndex].cbData = cbValueLen;
4995 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4996 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4999 if (HeapFree (hHeap, 0, lpValue) == 0)
5001 ret = GetLastError ();
5002 ERR ("HeapFree failed with code %li\n", ret);
5003 if (HeapFree (hHeap, 0, lpValueName) == 0)
5004 WARN ("HeapFree failed with code %li\n", GetLastError ());
5005 r = RegCloseKey (hkSubKey);
5006 if (r != ERROR_SUCCESS)
5007 WARN ("RegCloseKey returned %li\n", r);
5011 if (HeapFree (hHeap, 0, lpValueName) == 0)
5013 ret = GetLastError ();
5014 ERR ("HeapFree failed with code %li\n", ret);
5015 r = RegCloseKey (hkSubKey);
5016 if (r != ERROR_SUCCESS)
5017 WARN ("RegCloseKey returned %li\n", r);
5021 ret = RegCloseKey (hkSubKey);
5022 if (ret != ERROR_SUCCESS)
5024 ERR ("RegCloseKey returned %li\n", ret);
5028 return ERROR_SUCCESS;
5031 /*******************************************************************************
5032 * EnumPrinterDataExA [WINSPOOL.@]
5034 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5035 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5036 * what Windows 2000 SP1 does.
5039 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5040 LPBYTE pEnumValues, DWORD cbEnumValues,
5041 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5045 DWORD ret, dwIndex, dwBufSize;
5049 TRACE ("%p %s\n", hPrinter, pKeyName);
5051 if (pKeyName == NULL || *pKeyName == 0)
5052 return ERROR_INVALID_PARAMETER;
5054 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5057 ret = GetLastError ();
5058 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5062 hHeap = GetProcessHeap ();
5065 ERR ("GetProcessHeap failed\n");
5066 return ERROR_OUTOFMEMORY;
5069 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5070 if (pKeyNameW == NULL)
5072 ERR ("Failed to allocate %li bytes from process heap\n",
5073 (LONG) len * sizeof (WCHAR));
5074 return ERROR_OUTOFMEMORY;
5077 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5079 ret = GetLastError ();
5080 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5081 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5082 WARN ("HeapFree failed with code %li\n", GetLastError ());
5086 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5087 pcbEnumValues, pnEnumValues);
5088 if (ret != ERROR_SUCCESS)
5090 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5091 WARN ("HeapFree failed with code %li\n", GetLastError ());
5092 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5096 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5098 ret = GetLastError ();
5099 ERR ("HeapFree failed with code %li\n", ret);
5103 if (*pnEnumValues == 0) /* empty key */
5104 return ERROR_SUCCESS;
5107 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5109 PPRINTER_ENUM_VALUESW ppev =
5110 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5112 if (dwBufSize < ppev->cbValueName)
5113 dwBufSize = ppev->cbValueName;
5115 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5116 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5117 dwBufSize = ppev->cbData;
5120 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5122 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5123 if (pBuffer == NULL)
5125 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5126 return ERROR_OUTOFMEMORY;
5129 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5131 PPRINTER_ENUM_VALUESW ppev =
5132 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5134 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5135 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5139 ret = GetLastError ();
5140 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5141 if (HeapFree (hHeap, 0, pBuffer) == 0)
5142 WARN ("HeapFree failed with code %li\n", GetLastError ());
5146 memcpy (ppev->pValueName, pBuffer, len);
5148 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5150 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5151 ppev->dwType != REG_MULTI_SZ)
5154 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5155 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5158 ret = GetLastError ();
5159 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5160 if (HeapFree (hHeap, 0, pBuffer) == 0)
5161 WARN ("HeapFree failed with code %li\n", GetLastError ());
5165 memcpy (ppev->pData, pBuffer, len);
5167 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5168 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5171 if (HeapFree (hHeap, 0, pBuffer) == 0)
5173 ret = GetLastError ();
5174 ERR ("HeapFree failed with code %li\n", ret);
5178 return ERROR_SUCCESS;
5181 /******************************************************************************
5182 * AbortPrinter (WINSPOOL.@)
5184 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5186 FIXME("(%p), stub!\n", hPrinter);
5190 /******************************************************************************
5191 * AddPortA (WINSPOOL.@)
5196 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5198 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5202 /******************************************************************************
5203 * AddPortW (WINSPOOL.@)
5205 * Add a Port for a specific Monitor
5208 * pName [I] Servername or NULL (local Computer)
5209 * hWnd [I] Handle to parent Window for the Dialog-Box
5210 * pMonitorName [I] Name of the Monitor that manage the Port
5220 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5222 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5226 /******************************************************************************
5227 * AddPortExA (WINSPOOL.@)
5232 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5234 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5235 lpBuffer, debugstr_a(lpMonitorName));
5239 /******************************************************************************
5240 * AddPortExW (WINSPOOL.@)
5242 * Add a Port for a specific Monitor, without presenting a user interface
5245 * hMonitor [I] Handle from InitializePrintMonitor2()
5246 * pName [I] Servername or NULL (local Computer)
5247 * Level [I] Structure-Level (1 or 2) for lpBuffer
5248 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5249 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5259 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5261 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5262 lpBuffer, debugstr_w(lpMonitorName));
5266 /******************************************************************************
5267 * AddPrinterConnectionA (WINSPOOL.@)
5269 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5271 FIXME("%s\n", debugstr_a(pName));
5275 /******************************************************************************
5276 * AddPrinterConnectionW (WINSPOOL.@)
5278 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5280 FIXME("%s\n", debugstr_w(pName));
5284 /******************************************************************************
5285 * AddPrinterDriverExW (WINSPOOL.@)
5287 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5288 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5290 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5291 Level, pDriverInfo, dwFileCopyFlags);
5292 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5296 /******************************************************************************
5297 * AddPrinterDriverExA (WINSPOOL.@)
5299 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5300 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5302 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5303 Level, pDriverInfo, dwFileCopyFlags);
5304 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5308 /******************************************************************************
5309 * ConfigurePortA (WINSPOOL.@)
5311 * See ConfigurePortW.
5314 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5316 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5320 /******************************************************************************
5321 * ConfigurePortW (WINSPOOL.@)
5323 * Display the Configuration-Dialog for a specific Port
5326 * pName [I] Servername or NULL (local Computer)
5327 * hWnd [I] Handle to parent Window for the Dialog-Box
5328 * pPortName [I] Name of the Port, that should be configured
5338 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5340 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5344 /******************************************************************************
5345 * ConnectToPrinterDlg (WINSPOOL.@)
5347 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5349 FIXME("%p %lx\n", hWnd, Flags);
5353 /******************************************************************************
5354 * DeletePrinterConnectionA (WINSPOOL.@)
5356 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5358 FIXME("%s\n", debugstr_a(pName));
5362 /******************************************************************************
5363 * DeletePrinterConnectionW (WINSPOOL.@)
5365 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5367 FIXME("%s\n", debugstr_w(pName));
5371 /******************************************************************************
5372 * DeletePrinterDriverExW (WINSPOOL.@)
5374 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5375 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5377 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5378 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5382 /******************************************************************************
5383 * DeletePrinterDriverExA (WINSPOOL.@)
5385 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5386 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5388 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5389 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5393 /******************************************************************************
5394 * DeletePrinterDataExW (WINSPOOL.@)
5396 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5399 FIXME("%p %s %s\n", hPrinter,
5400 debugstr_w(pKeyName), debugstr_w(pValueName));
5401 return ERROR_INVALID_PARAMETER;
5404 /******************************************************************************
5405 * DeletePrinterDataExA (WINSPOOL.@)
5407 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5410 FIXME("%p %s %s\n", hPrinter,
5411 debugstr_a(pKeyName), debugstr_a(pValueName));
5412 return ERROR_INVALID_PARAMETER;
5415 /******************************************************************************
5416 * DeletePrintProcessorA (WINSPOOL.@)
5418 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5420 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5421 debugstr_a(pPrintProcessorName));
5425 /******************************************************************************
5426 * DeletePrintProcessorW (WINSPOOL.@)
5428 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5430 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5431 debugstr_w(pPrintProcessorName));
5435 /******************************************************************************
5436 * DeletePrintProvidorA (WINSPOOL.@)
5438 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5440 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5441 debugstr_a(pPrintProviderName));
5445 /******************************************************************************
5446 * DeletePrintProvidorW (WINSPOOL.@)
5448 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5450 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5451 debugstr_w(pPrintProviderName));
5455 /******************************************************************************
5456 * EnumFormsA (WINSPOOL.@)
5458 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5459 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5461 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5462 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5466 /******************************************************************************
5467 * EnumFormsW (WINSPOOL.@)
5469 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5470 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5472 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5473 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5477 /*****************************************************************************
5478 * EnumMonitorsA [WINSPOOL.@]
5480 * See EnumMonitorsW.
5483 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5484 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5487 LPBYTE bufferW = NULL;
5488 LPWSTR nameW = NULL;
5490 DWORD numentries = 0;
5493 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5494 cbBuf, pcbNeeded, pcReturned);
5496 /* convert servername to unicode */
5498 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5499 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5500 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5502 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5503 needed = cbBuf * sizeof(WCHAR);
5504 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5505 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5507 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5508 if (pcbNeeded) needed = *pcbNeeded;
5509 /* HeapReAlloc return NULL, when bufferW was NULL */
5510 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5511 HeapAlloc(GetProcessHeap(), 0, needed);
5513 /* Try again with the large Buffer */
5514 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5516 numentries = pcReturned ? *pcReturned : 0;
5519 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5520 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5523 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5524 DWORD entrysize = 0;
5527 LPMONITOR_INFO_2W mi2w;
5528 LPMONITOR_INFO_2A mi2a;
5530 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5531 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5533 /* First pass: calculate the size for all Entries */
5534 mi2w = (LPMONITOR_INFO_2W) bufferW;
5535 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5537 while (index < numentries) {
5539 needed += entrysize; /* MONITOR_INFO_?A */
5540 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5542 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5543 NULL, 0, NULL, NULL);
5545 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5546 NULL, 0, NULL, NULL);
5547 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5548 NULL, 0, NULL, NULL);
5550 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5551 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5552 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5555 /* check for errors and quit on failure */
5556 if (cbBuf < needed) {
5557 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5561 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5562 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5563 cbBuf -= len ; /* free Bytes in the user-Buffer */
5564 mi2w = (LPMONITOR_INFO_2W) bufferW;
5565 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5567 /* Second Pass: Fill the User Buffer (if we have one) */
5568 while ((index < numentries) && pMonitors) {
5570 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5572 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5573 ptr, cbBuf , NULL, NULL);
5577 mi2a->pEnvironment = ptr;
5578 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5579 ptr, cbBuf, NULL, NULL);
5583 mi2a->pDLLName = ptr;
5584 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5585 ptr, cbBuf, NULL, NULL);
5589 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5590 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5591 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5595 if (pcbNeeded) *pcbNeeded = needed;
5596 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5598 HeapFree(GetProcessHeap(), 0, nameW);
5599 HeapFree(GetProcessHeap(), 0, bufferW);
5601 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5602 (res), GetLastError(), needed, numentries);
5608 /*****************************************************************************
5609 * EnumMonitorsW [WINSPOOL.@]
5611 * Enumerate available Port-Monitors
5614 * pName [I] Servername or NULL (local Computer)
5615 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5616 * pMonitors [O] PTR to Buffer that receives the Result
5617 * cbBuf [I] Size of Buffer at pMonitors
5618 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5619 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5623 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5626 * Windows reads the Registry once and cache the Results.
5628 *| Language-Monitors are also installed in the same Registry-Location but
5629 *| they are filtered in Windows (not returned by EnumMonitors).
5630 *| We do no filtering to simplify our Code.
5633 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5634 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5637 DWORD numentries = 0;
5640 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5641 cbBuf, pcbNeeded, pcReturned);
5643 if (pName && (lstrlenW(pName))) {
5644 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5645 SetLastError(ERROR_ACCESS_DENIED);
5649 /* Level is not checked in win9x */
5650 if (!Level || (Level > 2)) {
5651 WARN("level (%ld) is ignored in win9x\n", Level);
5652 SetLastError(ERROR_INVALID_LEVEL);
5656 SetLastError(RPC_X_NULL_REF_POINTER);
5660 /* Scan all Monitor-Keys */
5662 needed = get_local_monitors(Level, NULL, 0, &numentries);
5664 /* we calculated the needed buffersize. now do the error-checks */
5665 if (cbBuf < needed) {
5666 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5669 else if (!pMonitors || !pcReturned) {
5670 SetLastError(RPC_X_NULL_REF_POINTER);
5674 /* fill the Buffer with the Monitor-Keys */
5675 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5679 if (pcbNeeded) *pcbNeeded = needed;
5680 if (pcReturned) *pcReturned = numentries;
5682 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5683 res, GetLastError(), needed, numentries);
5688 /******************************************************************************
5689 * XcvDataW (WINSPOOL.@)
5692 * There doesn't seem to be an A version...
5694 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5695 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5696 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5698 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5699 pInputData, cbInputData, pOutputData,
5700 cbOutputData, pcbOutputNeeded, pdwStatus);
5704 /*****************************************************************************
5705 * EnumPrinterDataA [WINSPOOL.@]
5708 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5709 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5710 DWORD cbData, LPDWORD pcbData )
5712 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5713 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5714 return ERROR_NO_MORE_ITEMS;
5717 /*****************************************************************************
5718 * EnumPrinterDataW [WINSPOOL.@]
5721 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5722 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5723 DWORD cbData, LPDWORD pcbData )
5725 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5726 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5727 return ERROR_NO_MORE_ITEMS;
5730 /*****************************************************************************
5731 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5734 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5735 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5736 LPDWORD pcbNeeded, LPDWORD pcReturned)
5738 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5739 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5740 pcbNeeded, pcReturned);
5744 /*****************************************************************************
5745 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5748 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5749 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5750 LPDWORD pcbNeeded, LPDWORD pcReturned)
5752 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5753 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5754 pcbNeeded, pcReturned);
5758 /*****************************************************************************
5759 * EnumPrintProcessorsA [WINSPOOL.@]
5762 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5763 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5765 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5766 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5770 /*****************************************************************************
5771 * EnumPrintProcessorsW [WINSPOOL.@]
5774 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5775 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5777 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5778 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5779 cbBuf, pcbNeeded, pcbReturned);
5783 /*****************************************************************************
5784 * ExtDeviceMode [WINSPOOL.@]
5787 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5788 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5791 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5792 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5793 debugstr_a(pProfile), fMode);
5797 /*****************************************************************************
5798 * FindClosePrinterChangeNotification [WINSPOOL.@]
5801 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5803 FIXME("Stub: %p\n", hChange);
5807 /*****************************************************************************
5808 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5811 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5812 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5814 FIXME("Stub: %p %lx %lx %p\n",
5815 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5816 return INVALID_HANDLE_VALUE;
5819 /*****************************************************************************
5820 * FindNextPrinterChangeNotification [WINSPOOL.@]
5823 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5824 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5826 FIXME("Stub: %p %p %p %p\n",
5827 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5831 /*****************************************************************************
5832 * FreePrinterNotifyInfo [WINSPOOL.@]
5835 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5837 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5841 /*****************************************************************************
5844 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5845 * ansi depending on the unicode parameter.
5847 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5857 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5860 memcpy(ptr, str, *size);
5867 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5870 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5877 /*****************************************************************************
5880 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5881 LPDWORD pcbNeeded, BOOL unicode)
5883 DWORD size, left = cbBuf;
5884 BOOL space = (cbBuf > 0);
5891 ji1->JobId = job->job_id;
5894 string_to_buf(job->document_title, ptr, left, &size, unicode);
5895 if(space && size <= left)
5897 ji1->pDocument = (LPWSTR)ptr;
5908 /*****************************************************************************
5911 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5912 LPDWORD pcbNeeded, BOOL unicode)
5914 DWORD size, left = cbBuf;
5915 BOOL space = (cbBuf > 0);
5922 ji2->JobId = job->job_id;
5925 string_to_buf(job->document_title, ptr, left, &size, unicode);
5926 if(space && size <= left)
5928 ji2->pDocument = (LPWSTR)ptr;
5939 /*****************************************************************************
5942 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5943 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5946 DWORD needed = 0, size;
5950 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5952 EnterCriticalSection(&printer_handles_cs);
5953 job = get_job(hPrinter, JobId);
5960 size = sizeof(JOB_INFO_1W);
5965 memset(pJob, 0, size);
5969 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5974 size = sizeof(JOB_INFO_2W);
5979 memset(pJob, 0, size);
5983 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5988 size = sizeof(JOB_INFO_3);
5992 memset(pJob, 0, size);
6001 SetLastError(ERROR_INVALID_LEVEL);
6005 *pcbNeeded = needed;
6007 LeaveCriticalSection(&printer_handles_cs);
6011 /*****************************************************************************
6012 * GetJobA [WINSPOOL.@]
6015 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6016 DWORD cbBuf, LPDWORD pcbNeeded)
6018 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6021 /*****************************************************************************
6022 * GetJobW [WINSPOOL.@]
6025 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6026 DWORD cbBuf, LPDWORD pcbNeeded)
6028 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6031 /*****************************************************************************
6034 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6036 char *unixname, *queue, *cmd;
6037 char fmt[] = "lpr -P%s %s";
6040 if(!(unixname = wine_get_unix_file_name(filename)))
6043 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6044 queue = HeapAlloc(GetProcessHeap(), 0, len);
6045 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6047 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6048 sprintf(cmd, fmt, queue, unixname);
6050 TRACE("printing with: %s\n", cmd);
6053 HeapFree(GetProcessHeap(), 0, cmd);
6054 HeapFree(GetProcessHeap(), 0, queue);
6055 HeapFree(GetProcessHeap(), 0, unixname);
6059 /*****************************************************************************
6062 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6064 #if HAVE_CUPS_CUPS_H
6067 char *unixname, *queue, *doc_titleA;
6071 if(!(unixname = wine_get_unix_file_name(filename)))
6074 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6075 queue = HeapAlloc(GetProcessHeap(), 0, len);
6076 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6078 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6079 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6080 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6082 TRACE("printing via cups\n");
6083 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6084 HeapFree(GetProcessHeap(), 0, doc_titleA);
6085 HeapFree(GetProcessHeap(), 0, queue);
6086 HeapFree(GetProcessHeap(), 0, unixname);
6092 return schedule_lpr(printer_name, filename);
6096 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6103 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6107 if(HIWORD(wparam) == BN_CLICKED)
6109 if(LOWORD(wparam) == IDOK)
6112 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6115 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6116 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6118 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6120 WCHAR caption[200], message[200];
6123 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6124 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6125 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6126 if(mb_ret == IDCANCEL)
6128 HeapFree(GetProcessHeap(), 0, filename);
6132 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6133 if(hf == INVALID_HANDLE_VALUE)
6135 WCHAR caption[200], message[200];
6137 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6138 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6139 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6140 HeapFree(GetProcessHeap(), 0, filename);
6144 DeleteFileW(filename);
6145 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6147 EndDialog(hwnd, IDOK);
6150 if(LOWORD(wparam) == IDCANCEL)
6152 EndDialog(hwnd, IDCANCEL);
6161 /*****************************************************************************
6164 static BOOL get_filename(LPWSTR *filename)
6166 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6167 file_dlg_proc, (LPARAM)filename) == IDOK;
6170 /*****************************************************************************
6173 static BOOL schedule_file(LPCWSTR filename)
6175 LPWSTR output = NULL;
6177 if(get_filename(&output))
6179 TRACE("copy to %s\n", debugstr_w(output));
6180 CopyFileW(filename, output, FALSE);
6181 HeapFree(GetProcessHeap(), 0, output);
6187 /*****************************************************************************
6190 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6193 char *unixname, *cmdA;
6195 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6199 if(!(unixname = wine_get_unix_file_name(filename)))
6202 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6203 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6204 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6206 TRACE("printing with: %s\n", cmdA);
6208 if((file_fd = open(unixname, O_RDONLY)) == -1)
6213 ERR("pipe() failed!\n");
6223 /* reset signals that we previously set to SIG_IGN */
6224 signal(SIGPIPE, SIG_DFL);
6225 signal(SIGCHLD, SIG_DFL);
6231 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6232 write(fds[1], buf, no_read);
6237 if(file_fd != -1) close(file_fd);
6238 if(fds[0] != -1) close(fds[0]);
6239 if(fds[1] != -1) close(fds[1]);
6241 HeapFree(GetProcessHeap(), 0, cmdA);
6242 HeapFree(GetProcessHeap(), 0, unixname);
6249 /*****************************************************************************
6252 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6254 int in_fd, out_fd, no_read;
6257 char *unixname, *outputA;
6260 if(!(unixname = wine_get_unix_file_name(filename)))
6263 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6264 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6265 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6267 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6268 in_fd = open(unixname, O_RDONLY);
6269 if(out_fd == -1 || in_fd == -1)
6272 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6273 write(out_fd, buf, no_read);
6277 if(in_fd != -1) close(in_fd);
6278 if(out_fd != -1) close(out_fd);
6279 HeapFree(GetProcessHeap(), 0, outputA);
6280 HeapFree(GetProcessHeap(), 0, unixname);
6284 /*****************************************************************************
6285 * ScheduleJob [WINSPOOL.@]
6288 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6290 opened_printer_t *printer;
6292 struct list *cursor, *cursor2;
6294 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6295 EnterCriticalSection(&printer_handles_cs);
6296 printer = get_opened_printer(hPrinter);
6300 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6302 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6305 if(job->job_id != dwJobID) continue;
6307 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6308 if(hf != INVALID_HANDLE_VALUE)
6310 PRINTER_INFO_5W *pi5;
6314 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6315 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6317 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6318 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6319 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6320 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6321 debugstr_w(pi5->pPortName));
6325 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6326 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6328 DWORD type, count = sizeof(output);
6329 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6332 if(output[0] == '|')
6334 schedule_pipe(output + 1, job->filename);
6338 schedule_unixfile(output, job->filename);
6340 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6342 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6344 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6346 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6348 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6350 schedule_file(job->filename);
6354 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6356 HeapFree(GetProcessHeap(), 0, pi5);
6358 DeleteFileW(job->filename);
6360 list_remove(cursor);
6361 HeapFree(GetProcessHeap(), 0, job->document_title);
6362 HeapFree(GetProcessHeap(), 0, job->filename);
6363 HeapFree(GetProcessHeap(), 0, job);
6368 LeaveCriticalSection(&printer_handles_cs);
6372 /*****************************************************************************
6373 * StartDocDlgA [WINSPOOL.@]
6375 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6377 UNICODE_STRING usBuffer;
6382 docW.cbSize = sizeof(docW);
6383 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6384 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6385 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6386 docW.fwType = doc->fwType;
6388 retW = StartDocDlgW(hPrinter, &docW);
6392 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6393 ret = HeapAlloc(GetProcessHeap(), 0, len);
6394 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6395 HeapFree(GetProcessHeap(), 0, retW);
6398 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6399 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6400 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6405 /*****************************************************************************
6406 * StartDocDlgW [WINSPOOL.@]
6408 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6409 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6410 * port is "FILE:". Also returns the full path if passed a relative path.
6412 * The caller should free the returned string from the process heap.
6414 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6419 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6421 PRINTER_INFO_5W *pi5;
6422 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6423 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6425 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6426 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6427 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6429 HeapFree(GetProcessHeap(), 0, pi5);
6432 HeapFree(GetProcessHeap(), 0, pi5);
6435 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6438 get_filename(&name);
6441 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6443 HeapFree(GetProcessHeap(), 0, name);
6446 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6447 GetFullPathNameW(name, len, ret, NULL);
6448 HeapFree(GetProcessHeap(), 0, name);
6453 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6456 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6457 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6459 attr = GetFileAttributesW(ret);
6460 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6462 HeapFree(GetProcessHeap(), 0, ret);