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-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer;
107 WCHAR *document_title;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
121 /* ############################### */
123 static opened_printer_t **printer_handles;
124 static UINT nb_printer_handles;
125 static LONG next_job_id = 1;
127 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
128 WORD fwCapability, LPSTR lpszOutput,
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
135 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_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 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
186 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
187 static const WCHAR backslashW[] = {'\\',0};
188 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW[] = {'R','A','W',0};
222 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW[] = {',',0};
226 static WCHAR emptyStringW[] = {0};
228 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
230 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
234 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
237 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
238 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
239 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
240 0, sizeof(DRIVER_INFO_8W)};
243 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
244 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
245 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
246 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
247 sizeof(PRINTER_INFO_9W)};
249 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
251 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
253 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
259 * env [I] PTR to Environment-String or NULL
263 * Success: PTR to printenv_t
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
271 static const printenv_t * validate_envW(LPCWSTR env)
273 const printenv_t *result = NULL;
276 TRACE("testing %s\n", debugstr_w(env));
279 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
281 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
283 result = all_printenv[i];
288 if (result == NULL) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env));
290 SetLastError(ERROR_INVALID_ENVIRONMENT);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
296 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
298 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
312 return usBufferPtr->Buffer;
314 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
318 static LPWSTR strdupW(LPCWSTR p)
324 len = (strlenW(p) + 1) * sizeof(WCHAR);
325 ret = HeapAlloc(GetProcessHeap(), 0, len);
330 static LPSTR strdupWtoA( LPCWSTR str )
335 if (!str) return NULL;
336 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
337 ret = HeapAlloc( GetProcessHeap(), 0, len );
338 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
342 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
346 if (!dm) return NULL;
347 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
348 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
352 /***********************************************************
354 * Creates an ansi copy of supplied devmode
356 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
361 if (!dmW) return NULL;
362 size = dmW->dmSize - CCHDEVICENAME -
363 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
365 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
366 if (!dmA) return NULL;
368 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
369 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
371 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
373 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
374 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
378 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
379 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
380 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
381 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
383 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
387 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
392 /******************************************************************
393 * verify, that the filename is a local file
396 static inline BOOL is_local_file(LPWSTR name)
398 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
401 /* ################################ */
403 static int multi_sz_lenA(const char *str)
405 const char *ptr = str;
409 ptr += lstrlenA(ptr) + 1;
412 return ptr - str + 1;
416 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
419 /* If forcing, or no profile string entry for device yet, set the entry
421 * The always change entry if not WINEPS yet is discussable.
424 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
426 !strstr(qbuf,"WINEPS.DRV")
428 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
431 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
432 WriteProfileStringA("windows","device",buf);
433 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
434 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
437 HeapFree(GetProcessHeap(),0,buf);
441 static BOOL add_printer_driver(WCHAR *name)
445 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
448 di3.pEnvironment = envname_x86W;
449 di3.pDriverPath = driver_nt;
450 di3.pDataFile = generic_ppdW;
451 di3.pConfigFile = driver_nt;
452 di3.pDefaultDataType = rawW;
454 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
455 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
458 di3.pEnvironment = envname_win40W;
459 di3.pDriverPath = driver_9x;
460 di3.pConfigFile = driver_9x;
461 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
462 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
467 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
471 #ifdef SONAME_LIBCUPS
473 static void *cupshandle;
476 DO_FUNC(cupsFreeDests); \
477 DO_FUNC(cupsFreeOptions); \
478 DO_FUNC(cupsGetDests); \
479 DO_FUNC(cupsGetPPD); \
480 DO_FUNC(cupsParseOptions); \
481 DO_FUNC(cupsPrintFile);
483 #define DO_FUNC(f) static typeof(f) *p##f
487 static BOOL CUPS_LoadPrinters(void)
490 BOOL hadprinter = FALSE, haddefault = FALSE;
494 HKEY hkeyPrinter, hkeyPrinters;
496 WCHAR nameW[MAX_PATH];
498 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
500 TRACE("%s\n", loaderror);
503 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
505 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
509 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
511 ERR("Can't create Printers key\n");
515 nrofdests = pcupsGetDests(&dests);
516 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
517 for (i=0;i<nrofdests;i++) {
518 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
520 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
521 lstrcpyW(port, CUPS_Port);
522 lstrcatW(port, nameW);
524 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
525 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
526 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
528 TRACE("Printer already exists\n");
529 /* overwrite old LPR:* port */
530 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
531 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
532 RegCloseKey(hkeyPrinter);
534 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
535 ' ','u','s','i','n','g',' ','C','U','P','S',0};
537 add_printer_driver(nameW);
539 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
540 pi2.pPrinterName = nameW;
541 pi2.pDatatype = rawW;
542 pi2.pPrintProcessor = WinPrintW;
543 pi2.pDriverName = nameW;
544 pi2.pComment = comment_cups;
545 pi2.pLocation = emptyStringW;
546 pi2.pPortName = port;
547 pi2.pParameters = emptyStringW;
548 pi2.pShareName = emptyStringW;
549 pi2.pSepFile = emptyStringW;
551 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
552 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
553 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
556 HeapFree(GetProcessHeap(),0,port);
559 if (dests[i].is_default) {
560 SetDefaultPrinterW(nameW);
564 if (hadprinter && !haddefault) {
565 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
566 SetDefaultPrinterW(nameW);
568 pcupsFreeDests(nrofdests, dests);
569 RegCloseKey(hkeyPrinters);
575 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
576 PRINTER_INFO_2A pinfo2a;
579 char *e,*s,*name,*prettyname,*devname;
580 BOOL ret = FALSE, set_default = FALSE;
581 char *port = NULL, *env_default;
582 HKEY hkeyPrinter, hkeyPrinters;
583 WCHAR devnameW[MAX_PATH];
585 while (isspace(*pent)) pent++;
586 r = strchr(pent,':');
590 name_len = strlen(pent);
591 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
592 memcpy(name, pent, name_len);
593 name[name_len] = '\0';
599 TRACE("name=%s entry=%s\n",name, pent);
601 if(ispunct(*name)) { /* a tc entry, not a real printer */
602 TRACE("skipping tc entry\n");
606 if(strstr(pent,":server")) { /* server only version so skip */
607 TRACE("skipping server entry\n");
611 /* Determine whether this is a postscript printer. */
614 env_default = getenv("PRINTER");
616 /* Get longest name, usually the one at the right for later display. */
617 while((s=strchr(prettyname,'|'))) {
620 while(isspace(*--e)) *e = '\0';
621 TRACE("\t%s\n", debugstr_a(prettyname));
622 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
623 for(prettyname = s+1; isspace(*prettyname); prettyname++)
626 e = prettyname + strlen(prettyname);
627 while(isspace(*--e)) *e = '\0';
628 TRACE("\t%s\n", debugstr_a(prettyname));
629 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
631 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
632 * if it is too long, we use it as comment below. */
633 devname = prettyname;
634 if (strlen(devname)>=CCHDEVICENAME-1)
636 if (strlen(devname)>=CCHDEVICENAME-1) {
641 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
642 sprintf(port,"LPR:%s",name);
644 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
646 ERR("Can't create Printers key\n");
651 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
653 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
654 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
656 TRACE("Printer already exists\n");
657 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
658 RegCloseKey(hkeyPrinter);
660 static CHAR data_type[] = "RAW",
661 print_proc[] = "WinPrint",
662 comment[] = "WINEPS Printer using LPR",
663 params[] = "<parameters?>",
664 share_name[] = "<share name?>",
665 sep_file[] = "<sep file?>";
667 add_printer_driver(devnameW);
669 memset(&pinfo2a,0,sizeof(pinfo2a));
670 pinfo2a.pPrinterName = devname;
671 pinfo2a.pDatatype = data_type;
672 pinfo2a.pPrintProcessor = print_proc;
673 pinfo2a.pDriverName = devname;
674 pinfo2a.pComment = comment;
675 pinfo2a.pLocation = prettyname;
676 pinfo2a.pPortName = port;
677 pinfo2a.pParameters = params;
678 pinfo2a.pShareName = share_name;
679 pinfo2a.pSepFile = sep_file;
681 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
682 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
683 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
686 RegCloseKey(hkeyPrinters);
688 if (isfirst || set_default)
689 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
692 HeapFree(GetProcessHeap(), 0, port);
693 HeapFree(GetProcessHeap(), 0, name);
698 PRINTCAP_LoadPrinters(void) {
699 BOOL hadprinter = FALSE;
703 BOOL had_bash = FALSE;
705 f = fopen("/etc/printcap","r");
709 while(fgets(buf,sizeof(buf),f)) {
712 end=strchr(buf,'\n');
716 while(isspace(*start)) start++;
717 if(*start == '#' || *start == '\0')
720 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
721 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
722 HeapFree(GetProcessHeap(),0,pent);
726 if (end && *--end == '\\') {
733 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
736 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
742 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
743 HeapFree(GetProcessHeap(),0,pent);
749 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
752 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
753 (lstrlenW(value) + 1) * sizeof(WCHAR));
755 return ERROR_FILE_NOT_FOUND;
758 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
760 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
761 DWORD ret = ERROR_FILE_NOT_FOUND;
763 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
764 and we support these drivers. NT writes DEVMODEW so somehow
765 we'll need to distinguish between these when we support NT
770 ret = RegSetValueExW( key, name, 0, REG_BINARY,
771 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
772 HeapFree( GetProcessHeap(), 0, dmA );
778 /******************************************************************
779 * get_servername_from_name (internal)
781 * for an external server, a copy of the serverpart from the full name is returned
784 static LPWSTR get_servername_from_name(LPCWSTR name)
788 WCHAR buffer[MAX_PATH];
791 if (name == NULL) return NULL;
792 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
794 server = strdupW(&name[2]); /* skip over both backslash */
795 if (server == NULL) return NULL;
797 /* strip '\' and the printername */
798 ptr = strchrW(server, '\\');
799 if (ptr) ptr[0] = '\0';
801 TRACE("found %s\n", debugstr_w(server));
803 len = sizeof(buffer)/sizeof(buffer[0]);
804 if (GetComputerNameW(buffer, &len)) {
805 if (lstrcmpW(buffer, server) == 0) {
806 /* The requested Servername is our computername */
807 HeapFree(GetProcessHeap(), 0, server);
814 /******************************************************************
815 * get_basename_from_name (internal)
817 * skip over the serverpart from the full name
820 static LPCWSTR get_basename_from_name(LPCWSTR name)
822 if (name == NULL) return NULL;
823 if ((name[0] == '\\') && (name[1] == '\\')) {
824 /* skip over the servername and search for the following '\' */
825 name = strchrW(&name[2], '\\');
826 if ((name) && (name[1])) {
827 /* found a separator ('\') followed by a name:
828 skip over the separator and return the rest */
833 /* no basename present (we found only a servername) */
840 static void free_printer_entry( opened_printer_t *printer )
842 /* the queue is shared, so don't free that here */
843 HeapFree( GetProcessHeap(), 0, printer->printername );
844 HeapFree( GetProcessHeap(), 0, printer->name );
845 HeapFree( GetProcessHeap(), 0, printer->devmode );
846 HeapFree( GetProcessHeap(), 0, printer );
849 /******************************************************************
850 * get_opened_printer_entry
851 * Get the first place empty in the opened printer table
854 * - pDefault is ignored
856 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
858 UINT_PTR handle = nb_printer_handles, i;
859 jobqueue_t *queue = NULL;
860 opened_printer_t *printer = NULL;
864 if ((backend == NULL) && !load_backend()) return NULL;
866 servername = get_servername_from_name(name);
868 FIXME("server %s not supported\n", debugstr_w(servername));
869 HeapFree(GetProcessHeap(), 0, servername);
870 SetLastError(ERROR_INVALID_PRINTER_NAME);
874 printername = get_basename_from_name(name);
875 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
877 /* an empty printername is invalid */
878 if (printername && (!printername[0])) {
879 SetLastError(ERROR_INVALID_PARAMETER);
883 EnterCriticalSection(&printer_handles_cs);
885 for (i = 0; i < nb_printer_handles; i++)
887 if (!printer_handles[i])
889 if(handle == nb_printer_handles)
894 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
895 queue = printer_handles[i]->queue;
899 if (handle >= nb_printer_handles)
901 opened_printer_t **new_array;
903 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
904 (nb_printer_handles + 16) * sizeof(*new_array) );
906 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
907 (nb_printer_handles + 16) * sizeof(*new_array) );
914 printer_handles = new_array;
915 nb_printer_handles += 16;
918 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
924 /* get a printer handle from the backend */
925 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
930 /* clone the base name. This is NULL for the printserver */
931 printer->printername = strdupW(printername);
933 /* clone the full name */
934 printer->name = strdupW(name);
935 if (name && (!printer->name)) {
940 if (pDefault && pDefault->pDevMode)
941 printer->devmode = dup_devmode( pDefault->pDevMode );
944 printer->queue = queue;
947 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
948 if (!printer->queue) {
952 list_init(&printer->queue->jobs);
953 printer->queue->ref = 0;
955 InterlockedIncrement(&printer->queue->ref);
957 printer_handles[handle] = printer;
960 LeaveCriticalSection(&printer_handles_cs);
961 if (!handle && printer) {
962 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
963 free_printer_entry( printer );
966 return (HANDLE)handle;
969 /******************************************************************
971 * Get the pointer to the opened printer referred by the handle
973 static opened_printer_t *get_opened_printer(HANDLE hprn)
975 UINT_PTR idx = (UINT_PTR)hprn;
976 opened_printer_t *ret = NULL;
978 EnterCriticalSection(&printer_handles_cs);
980 if ((idx > 0) && (idx <= nb_printer_handles)) {
981 ret = printer_handles[idx - 1];
983 LeaveCriticalSection(&printer_handles_cs);
987 /******************************************************************
988 * get_opened_printer_name
989 * Get the pointer to the opened printer name referred by the handle
991 static LPCWSTR get_opened_printer_name(HANDLE hprn)
993 opened_printer_t *printer = get_opened_printer(hprn);
994 if(!printer) return NULL;
995 return printer->name;
998 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1004 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1005 if (err) return err;
1007 err = RegOpenKeyW( printers, name, key );
1008 if (err) err = ERROR_INVALID_PRINTER_NAME;
1009 RegCloseKey( printers );
1013 /******************************************************************
1014 * WINSPOOL_GetOpenedPrinterRegKey
1017 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1019 LPCWSTR name = get_opened_printer_name(hPrinter);
1021 if(!name) return ERROR_INVALID_HANDLE;
1022 return open_printer_reg_key( name, phkey );
1025 static void old_printer_check( BOOL delete_phase )
1027 PRINTER_INFO_5W* pi;
1028 DWORD needed, type, num, delete, i, size;
1029 const DWORD one = 1;
1033 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1034 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1036 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1037 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1038 for (i = 0; i < num; i++)
1040 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1041 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1044 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1048 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1054 size = sizeof( delete );
1055 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1059 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1060 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1062 DeletePrinter( hprn );
1063 ClosePrinter( hprn );
1065 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1069 HeapFree(GetProcessHeap(), 0, pi);
1072 void WINSPOOL_LoadSystemPrinters(void)
1074 HKEY hkey, hkeyPrinters;
1075 DWORD needed, num, i;
1076 WCHAR PrinterName[256];
1079 /* This ensures that all printer entries have a valid Name value. If causes
1080 problems later if they don't. If one is found to be missed we create one
1081 and set it equal to the name of the key */
1082 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1083 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1084 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1085 for(i = 0; i < num; i++) {
1086 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1087 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1088 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1089 set_reg_szW(hkey, NameW, PrinterName);
1096 RegCloseKey(hkeyPrinters);
1099 old_printer_check( FALSE );
1101 #ifdef SONAME_LIBCUPS
1102 done = CUPS_LoadPrinters();
1105 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1106 PRINTCAP_LoadPrinters();
1108 old_printer_check( TRUE );
1113 /******************************************************************
1116 * Get the pointer to the specified job.
1117 * Should hold the printer_handles_cs before calling.
1119 static job_t *get_job(HANDLE hprn, DWORD JobId)
1121 opened_printer_t *printer = get_opened_printer(hprn);
1124 if(!printer) return NULL;
1125 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1127 if(job->job_id == JobId)
1133 /***********************************************************
1136 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1139 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1142 Formname = (dmA->dmSize > off_formname);
1143 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1144 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1145 dmW->dmDeviceName, CCHDEVICENAME);
1147 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1148 dmA->dmSize - CCHDEVICENAME);
1150 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1151 off_formname - CCHDEVICENAME);
1152 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1153 dmW->dmFormName, CCHFORMNAME);
1154 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1155 (off_formname + CCHFORMNAME));
1158 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1159 dmA->dmDriverExtra);
1163 /******************************************************************
1164 * convert_printerinfo_W_to_A [internal]
1167 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1168 DWORD level, DWORD outlen, DWORD numentries)
1174 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1176 len = pi_sizeof[level] * numentries;
1177 ptr = (LPSTR) out + len;
1180 /* copy the numbers of all PRINTER_INFO_* first */
1181 memcpy(out, pPrintersW, len);
1183 while (id < numentries) {
1187 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1188 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1190 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1191 if (piW->pDescription) {
1192 piA->pDescription = ptr;
1193 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1194 ptr, outlen, NULL, NULL);
1200 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1201 ptr, outlen, NULL, NULL);
1205 if (piW->pComment) {
1206 piA->pComment = ptr;
1207 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1208 ptr, outlen, NULL, NULL);
1217 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1218 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1221 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1222 if (piW->pServerName) {
1223 piA->pServerName = ptr;
1224 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1225 ptr, outlen, NULL, NULL);
1229 if (piW->pPrinterName) {
1230 piA->pPrinterName = ptr;
1231 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1232 ptr, outlen, NULL, NULL);
1236 if (piW->pShareName) {
1237 piA->pShareName = ptr;
1238 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1239 ptr, outlen, NULL, NULL);
1243 if (piW->pPortName) {
1244 piA->pPortName = ptr;
1245 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1246 ptr, outlen, NULL, NULL);
1250 if (piW->pDriverName) {
1251 piA->pDriverName = ptr;
1252 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1253 ptr, outlen, NULL, NULL);
1257 if (piW->pComment) {
1258 piA->pComment = ptr;
1259 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1260 ptr, outlen, NULL, NULL);
1264 if (piW->pLocation) {
1265 piA->pLocation = ptr;
1266 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1267 ptr, outlen, NULL, NULL);
1272 dmA = DEVMODEdupWtoA(piW->pDevMode);
1274 /* align DEVMODEA to a DWORD boundary */
1275 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1279 piA->pDevMode = (LPDEVMODEA) ptr;
1280 len = dmA->dmSize + dmA->dmDriverExtra;
1281 memcpy(ptr, dmA, len);
1282 HeapFree(GetProcessHeap(), 0, dmA);
1288 if (piW->pSepFile) {
1289 piA->pSepFile = ptr;
1290 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1291 ptr, outlen, NULL, NULL);
1295 if (piW->pPrintProcessor) {
1296 piA->pPrintProcessor = ptr;
1297 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1298 ptr, outlen, NULL, NULL);
1302 if (piW->pDatatype) {
1303 piA->pDatatype = ptr;
1304 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1305 ptr, outlen, NULL, NULL);
1309 if (piW->pParameters) {
1310 piA->pParameters = ptr;
1311 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1312 ptr, outlen, NULL, NULL);
1316 if (piW->pSecurityDescriptor) {
1317 piA->pSecurityDescriptor = NULL;
1318 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1325 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1326 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1328 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1330 if (piW->pPrinterName) {
1331 piA->pPrinterName = ptr;
1332 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1333 ptr, outlen, NULL, NULL);
1337 if (piW->pServerName) {
1338 piA->pServerName = ptr;
1339 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1340 ptr, outlen, NULL, NULL);
1349 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1350 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1352 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1354 if (piW->pPrinterName) {
1355 piA->pPrinterName = ptr;
1356 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1357 ptr, outlen, NULL, NULL);
1361 if (piW->pPortName) {
1362 piA->pPortName = ptr;
1363 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1364 ptr, outlen, NULL, NULL);
1371 case 6: /* 6A and 6W are the same structure */
1376 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1377 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1379 TRACE("(%u) #%u\n", level, id);
1380 if (piW->pszObjectGUID) {
1381 piA->pszObjectGUID = ptr;
1382 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1383 ptr, outlen, NULL, NULL);
1392 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1393 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1396 TRACE("(%u) #%u\n", level, id);
1397 dmA = DEVMODEdupWtoA(piW->pDevMode);
1399 /* align DEVMODEA to a DWORD boundary */
1400 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1404 piA->pDevMode = (LPDEVMODEA) ptr;
1405 len = dmA->dmSize + dmA->dmDriverExtra;
1406 memcpy(ptr, dmA, len);
1407 HeapFree(GetProcessHeap(), 0, dmA);
1417 FIXME("for level %u\n", level);
1419 pPrintersW += pi_sizeof[level];
1420 out += pi_sizeof[level];
1425 /******************************************************************
1426 * convert_driverinfo_W_to_A [internal]
1429 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1430 DWORD level, DWORD outlen, DWORD numentries)
1436 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1438 len = di_sizeof[level] * numentries;
1439 ptr = (LPSTR) out + len;
1442 /* copy the numbers of all PRINTER_INFO_* first */
1443 memcpy(out, pDriversW, len);
1445 #define COPY_STRING(fld) \
1448 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1449 ptr += len; outlen -= len;\
1451 #define COPY_MULTIZ_STRING(fld) \
1452 { LPWSTR p = diW->fld; if (p){ \
1455 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1456 ptr += len; outlen -= len; p += len;\
1458 while(len > 1 && outlen > 0); \
1461 while (id < numentries)
1467 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1468 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1470 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1477 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1478 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1480 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1483 COPY_STRING(pEnvironment);
1484 COPY_STRING(pDriverPath);
1485 COPY_STRING(pDataFile);
1486 COPY_STRING(pConfigFile);
1491 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1492 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1494 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1497 COPY_STRING(pEnvironment);
1498 COPY_STRING(pDriverPath);
1499 COPY_STRING(pDataFile);
1500 COPY_STRING(pConfigFile);
1501 COPY_STRING(pHelpFile);
1502 COPY_MULTIZ_STRING(pDependentFiles);
1503 COPY_STRING(pMonitorName);
1504 COPY_STRING(pDefaultDataType);
1509 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1510 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1512 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1515 COPY_STRING(pEnvironment);
1516 COPY_STRING(pDriverPath);
1517 COPY_STRING(pDataFile);
1518 COPY_STRING(pConfigFile);
1519 COPY_STRING(pHelpFile);
1520 COPY_MULTIZ_STRING(pDependentFiles);
1521 COPY_STRING(pMonitorName);
1522 COPY_STRING(pDefaultDataType);
1523 COPY_MULTIZ_STRING(pszzPreviousNames);
1528 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1529 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1531 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1534 COPY_STRING(pEnvironment);
1535 COPY_STRING(pDriverPath);
1536 COPY_STRING(pDataFile);
1537 COPY_STRING(pConfigFile);
1542 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1543 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1545 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1548 COPY_STRING(pEnvironment);
1549 COPY_STRING(pDriverPath);
1550 COPY_STRING(pDataFile);
1551 COPY_STRING(pConfigFile);
1552 COPY_STRING(pHelpFile);
1553 COPY_MULTIZ_STRING(pDependentFiles);
1554 COPY_STRING(pMonitorName);
1555 COPY_STRING(pDefaultDataType);
1556 COPY_MULTIZ_STRING(pszzPreviousNames);
1557 COPY_STRING(pszMfgName);
1558 COPY_STRING(pszOEMUrl);
1559 COPY_STRING(pszHardwareID);
1560 COPY_STRING(pszProvider);
1565 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1566 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1568 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1571 COPY_STRING(pEnvironment);
1572 COPY_STRING(pDriverPath);
1573 COPY_STRING(pDataFile);
1574 COPY_STRING(pConfigFile);
1575 COPY_STRING(pHelpFile);
1576 COPY_MULTIZ_STRING(pDependentFiles);
1577 COPY_STRING(pMonitorName);
1578 COPY_STRING(pDefaultDataType);
1579 COPY_MULTIZ_STRING(pszzPreviousNames);
1580 COPY_STRING(pszMfgName);
1581 COPY_STRING(pszOEMUrl);
1582 COPY_STRING(pszHardwareID);
1583 COPY_STRING(pszProvider);
1584 COPY_STRING(pszPrintProcessor);
1585 COPY_STRING(pszVendorSetup);
1586 COPY_MULTIZ_STRING(pszzColorProfiles);
1587 COPY_STRING(pszInfPath);
1588 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1594 FIXME("for level %u\n", level);
1597 pDriversW += di_sizeof[level];
1598 out += di_sizeof[level];
1603 #undef COPY_MULTIZ_STRING
1607 /***********************************************************
1610 static void *printer_info_AtoW( const void *data, DWORD level )
1613 UNICODE_STRING usBuffer;
1615 if (!data) return NULL;
1617 if (level < 1 || level > 9) return NULL;
1619 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1620 if (!ret) return NULL;
1622 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1628 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1629 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1631 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1632 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1633 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1634 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1635 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1636 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1637 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1638 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1639 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1640 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1641 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1642 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1649 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1650 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1652 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1657 FIXME( "Unhandled level %d\n", level );
1658 HeapFree( GetProcessHeap(), 0, ret );
1665 /***********************************************************
1668 static void free_printer_info( void *data, DWORD level )
1676 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1678 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1679 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1680 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1681 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1682 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1683 HeapFree( GetProcessHeap(), 0, piW->pComment );
1684 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1685 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1686 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1687 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1688 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1689 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1696 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1698 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1703 FIXME( "Unhandled level %d\n", level );
1706 HeapFree( GetProcessHeap(), 0, data );
1710 /******************************************************************
1711 * DeviceCapabilities [WINSPOOL.@]
1712 * DeviceCapabilitiesA [WINSPOOL.@]
1715 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1716 LPSTR pOutput, LPDEVMODEA lpdm)
1720 if (!GDI_CallDeviceCapabilities16)
1722 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1724 if (!GDI_CallDeviceCapabilities16) return -1;
1726 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1728 /* If DC_PAPERSIZE map POINT16s to POINTs */
1729 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1730 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1731 POINT *pt = (POINT *)pOutput;
1733 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1734 for(i = 0; i < ret; i++, pt++)
1739 HeapFree( GetProcessHeap(), 0, tmp );
1745 /*****************************************************************************
1746 * DeviceCapabilitiesW [WINSPOOL.@]
1748 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1751 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1752 WORD fwCapability, LPWSTR pOutput,
1753 const DEVMODEW *pDevMode)
1755 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1756 LPSTR pDeviceA = strdupWtoA(pDevice);
1757 LPSTR pPortA = strdupWtoA(pPort);
1760 if(pOutput && (fwCapability == DC_BINNAMES ||
1761 fwCapability == DC_FILEDEPENDENCIES ||
1762 fwCapability == DC_PAPERNAMES)) {
1763 /* These need A -> W translation */
1766 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1770 switch(fwCapability) {
1775 case DC_FILEDEPENDENCIES:
1779 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1780 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1782 for(i = 0; i < ret; i++)
1783 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1784 pOutput + (i * size), size);
1785 HeapFree(GetProcessHeap(), 0, pOutputA);
1787 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1788 (LPSTR)pOutput, dmA);
1790 HeapFree(GetProcessHeap(),0,pPortA);
1791 HeapFree(GetProcessHeap(),0,pDeviceA);
1792 HeapFree(GetProcessHeap(),0,dmA);
1796 /******************************************************************
1797 * DocumentPropertiesA [WINSPOOL.@]
1799 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1801 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1802 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1803 LPDEVMODEA pDevModeInput,DWORD fMode )
1805 LPSTR lpName = pDeviceName;
1806 static CHAR port[] = "LPT1:";
1809 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1810 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1814 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1816 ERR("no name from hPrinter?\n");
1817 SetLastError(ERROR_INVALID_HANDLE);
1820 lpName = strdupWtoA(lpNameW);
1823 if (!GDI_CallExtDeviceMode16)
1825 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1827 if (!GDI_CallExtDeviceMode16) {
1828 ERR("No CallExtDeviceMode16?\n");
1832 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1833 pDevModeInput, NULL, fMode);
1836 HeapFree(GetProcessHeap(),0,lpName);
1841 /*****************************************************************************
1842 * DocumentPropertiesW (WINSPOOL.@)
1844 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1846 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1848 LPDEVMODEW pDevModeOutput,
1849 LPDEVMODEW pDevModeInput, DWORD fMode)
1852 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1853 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1854 LPDEVMODEA pDevModeOutputA = NULL;
1857 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1858 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1860 if(pDevModeOutput) {
1861 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1862 if(ret < 0) return ret;
1863 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1865 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1866 pDevModeInputA, fMode);
1867 if(pDevModeOutput) {
1868 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1869 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1871 if(fMode == 0 && ret > 0)
1872 ret += (CCHDEVICENAME + CCHFORMNAME);
1873 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1874 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1878 /*****************************************************************************
1879 * IsValidDevmodeA [WINSPOOL.@]
1881 * Validate a DEVMODE structure and fix errors if possible.
1884 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1886 FIXME("(%p,%ld): stub\n", pDevMode, size);
1894 /*****************************************************************************
1895 * IsValidDevmodeW [WINSPOOL.@]
1897 * Validate a DEVMODE structure and fix errors if possible.
1900 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1902 FIXME("(%p,%ld): stub\n", pDevMode, size);
1910 /******************************************************************
1911 * OpenPrinterA [WINSPOOL.@]
1916 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1917 LPPRINTER_DEFAULTSA pDefault)
1919 UNICODE_STRING lpPrinterNameW;
1920 UNICODE_STRING usBuffer;
1921 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1922 PWSTR pwstrPrinterNameW;
1925 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1928 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1929 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1930 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1931 pDefaultW = &DefaultW;
1933 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1935 RtlFreeUnicodeString(&usBuffer);
1936 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1938 RtlFreeUnicodeString(&lpPrinterNameW);
1942 /******************************************************************
1943 * OpenPrinterW [WINSPOOL.@]
1945 * Open a Printer / Printserver or a Printer-Object
1948 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1949 * phPrinter [O] The resulting Handle is stored here
1950 * pDefault [I] PTR to Default Printer Settings or NULL
1957 * lpPrinterName is one of:
1958 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1959 *| Printer: "PrinterName"
1960 *| Printer-Object: "PrinterName,Job xxx"
1961 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1962 *| XcvPort: "Servername,XcvPort PortName"
1965 *| Printer-Object not supported
1966 *| pDefaults is ignored
1969 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1972 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1975 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1976 SetLastError(ERROR_INVALID_PARAMETER);
1980 /* Get the unique handle of the printer or Printserver */
1981 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1982 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1983 return (*phPrinter != 0);
1986 /******************************************************************
1987 * AddMonitorA [WINSPOOL.@]
1992 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1994 LPWSTR nameW = NULL;
1997 LPMONITOR_INFO_2A mi2a;
1998 MONITOR_INFO_2W mi2w;
2000 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2001 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2002 debugstr_a(mi2a ? mi2a->pName : NULL),
2003 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2004 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2007 SetLastError(ERROR_INVALID_LEVEL);
2011 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2017 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2018 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2019 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2022 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2024 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2025 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2026 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2028 if (mi2a->pEnvironment) {
2029 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2030 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2031 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2033 if (mi2a->pDLLName) {
2034 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2035 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2036 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2039 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2041 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2042 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2043 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2045 HeapFree(GetProcessHeap(), 0, nameW);
2049 /******************************************************************************
2050 * AddMonitorW [WINSPOOL.@]
2052 * Install a Printmonitor
2055 * pName [I] Servername or NULL (local Computer)
2056 * Level [I] Structure-Level (Must be 2)
2057 * pMonitors [I] PTR to MONITOR_INFO_2
2064 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2067 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2069 LPMONITOR_INFO_2W mi2w;
2071 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2072 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2073 debugstr_w(mi2w ? mi2w->pName : NULL),
2074 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2075 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2077 if ((backend == NULL) && !load_backend()) return FALSE;
2080 SetLastError(ERROR_INVALID_LEVEL);
2084 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2089 return backend->fpAddMonitor(pName, Level, pMonitors);
2092 /******************************************************************
2093 * DeletePrinterDriverA [WINSPOOL.@]
2096 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2098 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2101 /******************************************************************
2102 * DeletePrinterDriverW [WINSPOOL.@]
2105 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2107 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2110 /******************************************************************
2111 * DeleteMonitorA [WINSPOOL.@]
2113 * See DeleteMonitorW.
2116 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2118 LPWSTR nameW = NULL;
2119 LPWSTR EnvironmentW = NULL;
2120 LPWSTR MonitorNameW = NULL;
2125 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2126 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2127 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2131 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2132 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2133 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2136 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2137 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2138 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2141 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2143 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2144 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2145 HeapFree(GetProcessHeap(), 0, nameW);
2149 /******************************************************************
2150 * DeleteMonitorW [WINSPOOL.@]
2152 * Delete a specific Printmonitor from a Printing-Environment
2155 * pName [I] Servername or NULL (local Computer)
2156 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2157 * pMonitorName [I] Name of the Monitor, that should be deleted
2164 * pEnvironment is ignored in Windows for the local Computer.
2167 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2170 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2171 debugstr_w(pMonitorName));
2173 if ((backend == NULL) && !load_backend()) return FALSE;
2175 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2179 /******************************************************************
2180 * DeletePortA [WINSPOOL.@]
2185 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2187 LPWSTR nameW = NULL;
2188 LPWSTR portW = NULL;
2192 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2194 /* convert servername to unicode */
2196 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2197 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2198 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2201 /* convert portname to unicode */
2203 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2204 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2205 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2208 res = DeletePortW(nameW, hWnd, portW);
2209 HeapFree(GetProcessHeap(), 0, nameW);
2210 HeapFree(GetProcessHeap(), 0, portW);
2214 /******************************************************************
2215 * DeletePortW [WINSPOOL.@]
2217 * Delete a specific Port
2220 * pName [I] Servername or NULL (local Computer)
2221 * hWnd [I] Handle to parent Window for the Dialog-Box
2222 * pPortName [I] Name of the Port, that should be deleted
2229 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2231 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2233 if ((backend == NULL) && !load_backend()) return FALSE;
2236 SetLastError(RPC_X_NULL_REF_POINTER);
2240 return backend->fpDeletePort(pName, hWnd, pPortName);
2243 /******************************************************************************
2244 * WritePrinter [WINSPOOL.@]
2246 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2248 opened_printer_t *printer;
2251 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2253 EnterCriticalSection(&printer_handles_cs);
2254 printer = get_opened_printer(hPrinter);
2257 SetLastError(ERROR_INVALID_HANDLE);
2263 SetLastError(ERROR_SPL_NO_STARTDOC);
2267 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2269 LeaveCriticalSection(&printer_handles_cs);
2273 /*****************************************************************************
2274 * AddFormA [WINSPOOL.@]
2276 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2278 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2282 /*****************************************************************************
2283 * AddFormW [WINSPOOL.@]
2285 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2287 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2291 /*****************************************************************************
2292 * AddJobA [WINSPOOL.@]
2294 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2297 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2301 SetLastError(ERROR_INVALID_LEVEL);
2305 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2308 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2309 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2310 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2311 if(*pcbNeeded > cbBuf) {
2312 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2315 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2316 addjobA->JobId = addjobW->JobId;
2317 addjobA->Path = (char *)(addjobA + 1);
2318 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2324 /*****************************************************************************
2325 * AddJobW [WINSPOOL.@]
2327 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2329 opened_printer_t *printer;
2332 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2333 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2334 WCHAR path[MAX_PATH], filename[MAX_PATH];
2336 ADDJOB_INFO_1W *addjob;
2338 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2340 EnterCriticalSection(&printer_handles_cs);
2342 printer = get_opened_printer(hPrinter);
2345 SetLastError(ERROR_INVALID_HANDLE);
2350 SetLastError(ERROR_INVALID_LEVEL);
2354 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2358 job->job_id = InterlockedIncrement(&next_job_id);
2360 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2361 if(path[len - 1] != '\\')
2363 memcpy(path + len, spool_path, sizeof(spool_path));
2364 sprintfW(filename, fmtW, path, job->job_id);
2366 len = strlenW(filename);
2367 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2368 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2369 job->portname = NULL;
2370 job->document_title = strdupW(default_doc_title);
2371 job->printer_name = strdupW(printer->name);
2372 job->devmode = dup_devmode( printer->devmode );
2373 list_add_tail(&printer->queue->jobs, &job->entry);
2375 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2376 if(*pcbNeeded <= cbBuf) {
2377 addjob = (ADDJOB_INFO_1W*)pData;
2378 addjob->JobId = job->job_id;
2379 addjob->Path = (WCHAR *)(addjob + 1);
2380 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2383 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2386 LeaveCriticalSection(&printer_handles_cs);
2390 /*****************************************************************************
2391 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2393 * Return the PATH for the Print-Processors
2395 * See GetPrintProcessorDirectoryW.
2399 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2400 DWORD level, LPBYTE Info,
2401 DWORD cbBuf, LPDWORD pcbNeeded)
2403 LPWSTR serverW = NULL;
2408 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2409 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2413 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2414 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2415 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2419 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2420 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2421 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2424 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2425 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2427 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2430 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2431 cbBuf, NULL, NULL) > 0;
2434 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2435 HeapFree(GetProcessHeap(), 0, envW);
2436 HeapFree(GetProcessHeap(), 0, serverW);
2440 /*****************************************************************************
2441 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2443 * Return the PATH for the Print-Processors
2446 * server [I] Servername (NT only) or NULL (local Computer)
2447 * env [I] Printing-Environment (see below) or NULL (Default)
2448 * level [I] Structure-Level (must be 1)
2449 * Info [O] PTR to Buffer that receives the Result
2450 * cbBuf [I] Size of Buffer at "Info"
2451 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2452 * required for the Buffer at "Info"
2455 * Success: TRUE and in pcbNeeded the Bytes used in Info
2456 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2457 * if cbBuf is too small
2459 * Native Values returned in Info on Success:
2460 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2461 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2462 *| win9x(Windows 4.0): "%winsysdir%"
2464 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2467 * Only NULL or "" is supported for server
2470 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2471 DWORD level, LPBYTE Info,
2472 DWORD cbBuf, LPDWORD pcbNeeded)
2475 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2476 Info, cbBuf, pcbNeeded);
2478 if ((backend == NULL) && !load_backend()) return FALSE;
2481 /* (Level != 1) is ignored in win9x */
2482 SetLastError(ERROR_INVALID_LEVEL);
2486 if (pcbNeeded == NULL) {
2487 /* (pcbNeeded == NULL) is ignored in win9x */
2488 SetLastError(RPC_X_NULL_REF_POINTER);
2492 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2495 /*****************************************************************************
2496 * WINSPOOL_OpenDriverReg [internal]
2498 * opens the registry for the printer drivers depending on the given input
2499 * variable pEnvironment
2502 * the opened hkey on success
2505 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2509 const printenv_t * env;
2511 TRACE("(%s)\n", debugstr_w(pEnvironment));
2513 env = validate_envW(pEnvironment);
2514 if (!env) return NULL;
2516 buffer = HeapAlloc( GetProcessHeap(), 0,
2517 (strlenW(DriversW) + strlenW(env->envname) +
2518 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2520 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2521 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2522 HeapFree(GetProcessHeap(), 0, buffer);
2527 /*****************************************************************************
2528 * set_devices_and_printerports [internal]
2530 * set the [Devices] and [PrinterPorts] entries for a printer.
2533 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2535 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2539 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2541 /* FIXME: the driver must change to "winspool" */
2542 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2544 lstrcpyW(devline, driver_nt);
2545 lstrcatW(devline, commaW);
2546 lstrcatW(devline, pi->pPortName);
2548 TRACE("using %s\n", debugstr_w(devline));
2549 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2550 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2551 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2552 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2556 lstrcatW(devline, timeout_15_45);
2557 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2558 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2559 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2560 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2563 HeapFree(GetProcessHeap(), 0, devline);
2567 /*****************************************************************************
2568 * AddPrinterW [WINSPOOL.@]
2570 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2572 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2575 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2577 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2578 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2579 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2580 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2581 statusW[] = {'S','t','a','t','u','s',0},
2582 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2584 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2587 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2588 SetLastError(ERROR_INVALID_PARAMETER);
2592 ERR("Level = %d, unsupported!\n", Level);
2593 SetLastError(ERROR_INVALID_LEVEL);
2597 SetLastError(ERROR_INVALID_PARAMETER);
2600 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2602 ERR("Can't create Printers key\n");
2605 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2606 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2607 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2608 RegCloseKey(hkeyPrinter);
2609 RegCloseKey(hkeyPrinters);
2612 RegCloseKey(hkeyPrinter);
2614 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2616 ERR("Can't create Drivers key\n");
2617 RegCloseKey(hkeyPrinters);
2620 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2622 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2623 RegCloseKey(hkeyPrinters);
2624 RegCloseKey(hkeyDrivers);
2625 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2628 RegCloseKey(hkeyDriver);
2629 RegCloseKey(hkeyDrivers);
2631 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2632 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2633 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2634 RegCloseKey(hkeyPrinters);
2638 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2640 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2641 SetLastError(ERROR_INVALID_PRINTER_NAME);
2642 RegCloseKey(hkeyPrinters);
2646 set_devices_and_printerports(pi);
2647 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2648 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2649 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2651 /* See if we can load the driver. We may need the devmode structure anyway
2654 * Note that DocumentPropertiesW will briefly try to open the printer we
2655 * just create to find a DEVMODE struct (it will use the WINEPS default
2656 * one in case it is not there, so we are ok).
2658 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2661 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2662 size = sizeof(DEVMODEW);
2668 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2670 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2672 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2673 HeapFree( GetProcessHeap(), 0, dm );
2678 /* set devmode to printer name */
2679 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2683 set_reg_devmode( hkeyPrinter, default_devmodeW, dm );
2684 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2686 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2687 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2688 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2689 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2691 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2692 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2693 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2694 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2695 (LPBYTE)&pi->Priority, sizeof(DWORD));
2696 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2697 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2698 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2699 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2700 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2701 (LPBYTE)&pi->Status, sizeof(DWORD));
2702 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2703 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2705 RegCloseKey(hkeyPrinter);
2706 RegCloseKey(hkeyPrinters);
2707 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2708 ERR("OpenPrinter failing\n");
2714 /*****************************************************************************
2715 * AddPrinterA [WINSPOOL.@]
2717 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2719 UNICODE_STRING pNameW;
2721 PRINTER_INFO_2W *piW;
2722 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2725 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2727 ERR("Level = %d, unsupported!\n", Level);
2728 SetLastError(ERROR_INVALID_LEVEL);
2731 pwstrNameW = asciitounicode(&pNameW,pName);
2732 piW = printer_info_AtoW( piA, Level );
2734 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2736 free_printer_info( piW, Level );
2737 RtlFreeUnicodeString(&pNameW);
2742 /*****************************************************************************
2743 * ClosePrinter [WINSPOOL.@]
2745 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2747 UINT_PTR i = (UINT_PTR)hPrinter;
2748 opened_printer_t *printer = NULL;
2751 TRACE("(%p)\n", hPrinter);
2753 EnterCriticalSection(&printer_handles_cs);
2755 if ((i > 0) && (i <= nb_printer_handles))
2756 printer = printer_handles[i - 1];
2761 struct list *cursor, *cursor2;
2763 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2765 if (printer->backend_printer) {
2766 backend->fpClosePrinter(printer->backend_printer);
2770 EndDocPrinter(hPrinter);
2772 if(InterlockedDecrement(&printer->queue->ref) == 0)
2774 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2776 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2777 ScheduleJob(hPrinter, job->job_id);
2779 HeapFree(GetProcessHeap(), 0, printer->queue);
2782 free_printer_entry( printer );
2783 printer_handles[i - 1] = NULL;
2786 LeaveCriticalSection(&printer_handles_cs);
2790 /*****************************************************************************
2791 * DeleteFormA [WINSPOOL.@]
2793 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2795 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2799 /*****************************************************************************
2800 * DeleteFormW [WINSPOOL.@]
2802 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2804 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2808 /*****************************************************************************
2809 * DeletePrinter [WINSPOOL.@]
2811 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2813 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2814 HKEY hkeyPrinters, hkey;
2815 WCHAR def[MAX_PATH];
2816 DWORD size = sizeof( def ) / sizeof( def[0] );
2819 SetLastError(ERROR_INVALID_HANDLE);
2822 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2823 RegDeleteTreeW(hkeyPrinters, lpNameW);
2824 RegCloseKey(hkeyPrinters);
2826 WriteProfileStringW(devicesW, lpNameW, NULL);
2827 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2829 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2830 RegDeleteValueW(hkey, lpNameW);
2834 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2835 RegDeleteValueW(hkey, lpNameW);
2839 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2841 WriteProfileStringW( windowsW, deviceW, NULL );
2842 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2844 RegDeleteValueW( hkey, deviceW );
2845 RegCloseKey( hkey );
2847 SetDefaultPrinterW( NULL );
2853 /*****************************************************************************
2854 * SetPrinterA [WINSPOOL.@]
2856 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2863 dataW = printer_info_AtoW( data, level );
2864 if (!dataW) return FALSE;
2867 ret = SetPrinterW( printer, level, dataW, command );
2869 if (dataW != data) free_printer_info( dataW, level );
2874 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2876 if (!pi->pDevMode) return FALSE;
2878 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2882 /******************************************************************************
2883 * SetPrinterW [WINSPOOL.@]
2885 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2890 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2892 if (command != 0) FIXME( "Ignoring command %d\n", command );
2894 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2901 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2902 ret = set_printer_9( key, pi );
2907 FIXME( "Unimplemented level %d\n", level );
2908 SetLastError( ERROR_INVALID_LEVEL );
2915 /*****************************************************************************
2916 * SetJobA [WINSPOOL.@]
2918 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2919 LPBYTE pJob, DWORD Command)
2923 UNICODE_STRING usBuffer;
2925 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2927 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2928 are all ignored by SetJob, so we don't bother copying them */
2936 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2937 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2939 JobW = (LPBYTE)info1W;
2940 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2941 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2942 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2943 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2944 info1W->Status = info1A->Status;
2945 info1W->Priority = info1A->Priority;
2946 info1W->Position = info1A->Position;
2947 info1W->PagesPrinted = info1A->PagesPrinted;
2952 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2953 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2955 JobW = (LPBYTE)info2W;
2956 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2957 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2958 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2959 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2960 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2961 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2962 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2963 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2964 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2965 info2W->Status = info2A->Status;
2966 info2W->Priority = info2A->Priority;
2967 info2W->Position = info2A->Position;
2968 info2W->StartTime = info2A->StartTime;
2969 info2W->UntilTime = info2A->UntilTime;
2970 info2W->PagesPrinted = info2A->PagesPrinted;
2974 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2975 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2978 SetLastError(ERROR_INVALID_LEVEL);
2982 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2988 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2989 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2990 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2991 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2992 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2997 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2998 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2999 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3000 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3001 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3002 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3003 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3004 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3005 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3009 HeapFree(GetProcessHeap(), 0, JobW);
3014 /*****************************************************************************
3015 * SetJobW [WINSPOOL.@]
3017 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3018 LPBYTE pJob, DWORD Command)
3023 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3024 FIXME("Ignoring everything other than document title\n");
3026 EnterCriticalSection(&printer_handles_cs);
3027 job = get_job(hPrinter, JobId);
3037 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3038 HeapFree(GetProcessHeap(), 0, job->document_title);
3039 job->document_title = strdupW(info1->pDocument);
3044 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3045 HeapFree(GetProcessHeap(), 0, job->document_title);
3046 job->document_title = strdupW(info2->pDocument);
3047 HeapFree(GetProcessHeap(), 0, job->devmode);
3048 job->devmode = dup_devmode( info2->pDevMode );
3054 SetLastError(ERROR_INVALID_LEVEL);
3059 LeaveCriticalSection(&printer_handles_cs);
3063 /*****************************************************************************
3064 * EndDocPrinter [WINSPOOL.@]
3066 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3068 opened_printer_t *printer;
3070 TRACE("(%p)\n", hPrinter);
3072 EnterCriticalSection(&printer_handles_cs);
3074 printer = get_opened_printer(hPrinter);
3077 SetLastError(ERROR_INVALID_HANDLE);
3083 SetLastError(ERROR_SPL_NO_STARTDOC);
3087 CloseHandle(printer->doc->hf);
3088 ScheduleJob(hPrinter, printer->doc->job_id);
3089 HeapFree(GetProcessHeap(), 0, printer->doc);
3090 printer->doc = NULL;
3093 LeaveCriticalSection(&printer_handles_cs);
3097 /*****************************************************************************
3098 * EndPagePrinter [WINSPOOL.@]
3100 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3102 FIXME("(%p): stub\n", hPrinter);
3106 /*****************************************************************************
3107 * StartDocPrinterA [WINSPOOL.@]
3109 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3111 UNICODE_STRING usBuffer;
3113 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3116 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3117 or one (DOC_INFO_3) extra DWORDs */
3121 doc2W.JobId = doc2->JobId;
3124 doc2W.dwMode = doc2->dwMode;
3127 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3128 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3129 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3133 SetLastError(ERROR_INVALID_LEVEL);
3137 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3139 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3140 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3141 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3146 /*****************************************************************************
3147 * StartDocPrinterW [WINSPOOL.@]
3149 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3151 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3152 opened_printer_t *printer;
3153 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3154 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3155 JOB_INFO_1W job_info;
3156 DWORD needed, ret = 0;
3161 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3162 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3163 debugstr_w(doc->pDatatype));
3165 if(Level < 1 || Level > 3)
3167 SetLastError(ERROR_INVALID_LEVEL);
3171 EnterCriticalSection(&printer_handles_cs);
3172 printer = get_opened_printer(hPrinter);
3175 SetLastError(ERROR_INVALID_HANDLE);
3181 SetLastError(ERROR_INVALID_PRINTER_STATE);
3185 /* Even if we're printing to a file we still add a print job, we'll
3186 just ignore the spool file name */
3188 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3190 ERR("AddJob failed gle %u\n", GetLastError());
3194 /* use pOutputFile only, when it is a real filename */
3195 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3196 filename = doc->pOutputFile;
3198 filename = addjob->Path;
3200 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3201 if(hf == INVALID_HANDLE_VALUE)
3204 memset(&job_info, 0, sizeof(job_info));
3205 job_info.pDocument = doc->pDocName;
3206 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3208 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3209 printer->doc->hf = hf;
3210 ret = printer->doc->job_id = addjob->JobId;
3211 job = get_job(hPrinter, ret);
3212 job->portname = strdupW(doc->pOutputFile);
3215 LeaveCriticalSection(&printer_handles_cs);
3220 /*****************************************************************************
3221 * StartPagePrinter [WINSPOOL.@]
3223 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3225 FIXME("(%p): stub\n", hPrinter);
3229 /*****************************************************************************
3230 * GetFormA [WINSPOOL.@]
3232 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3233 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3235 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3236 Level,pForm,cbBuf,pcbNeeded);
3240 /*****************************************************************************
3241 * GetFormW [WINSPOOL.@]
3243 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3244 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3246 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3247 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3251 /*****************************************************************************
3252 * SetFormA [WINSPOOL.@]
3254 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3257 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3261 /*****************************************************************************
3262 * SetFormW [WINSPOOL.@]
3264 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3267 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3271 /*****************************************************************************
3272 * ReadPrinter [WINSPOOL.@]
3274 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3275 LPDWORD pNoBytesRead)
3277 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3281 /*****************************************************************************
3282 * ResetPrinterA [WINSPOOL.@]
3284 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3286 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3290 /*****************************************************************************
3291 * ResetPrinterW [WINSPOOL.@]
3293 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3295 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3299 /*****************************************************************************
3300 * WINSPOOL_GetDWORDFromReg
3302 * Return DWORD associated with ValueName from hkey.
3304 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3306 DWORD sz = sizeof(DWORD), type, value = 0;
3309 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3311 if(ret != ERROR_SUCCESS) {
3312 WARN("Got ret = %d on name %s\n", ret, ValueName);
3315 if(type != REG_DWORD) {
3316 ERR("Got type %d\n", type);
3323 /*****************************************************************************
3324 * get_filename_from_reg [internal]
3326 * Get ValueName from hkey storing result in out
3327 * when the Value in the registry has only a filename, use driverdir as prefix
3328 * outlen is space left in out
3329 * String is stored either as unicode or ascii
3333 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3334 LPBYTE out, DWORD outlen, LPDWORD needed)
3336 WCHAR filename[MAX_PATH];
3340 LPWSTR buffer = filename;
3344 size = sizeof(filename);
3346 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3347 if (ret == ERROR_MORE_DATA) {
3348 TRACE("need dynamic buffer: %u\n", size);
3349 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3351 /* No Memory is bad */
3355 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3358 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3359 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3365 /* do we have a full path ? */
3366 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3367 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3370 /* we must build the full Path */
3372 if ((out) && (outlen > dirlen)) {
3373 lstrcpyW((LPWSTR)out, driverdir);
3381 /* write the filename */
3382 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3383 if ((out) && (outlen >= size)) {
3384 lstrcpyW((LPWSTR)out, ptr);
3391 ptr += lstrlenW(ptr)+1;
3392 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3395 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3397 /* write the multisz-termination */
3398 if (type == REG_MULTI_SZ) {
3399 size = sizeof(WCHAR);
3402 if (out && (outlen >= size)) {
3403 memset (out, 0, size);
3409 /*****************************************************************************
3410 * WINSPOOL_GetStringFromReg
3412 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3413 * String is stored as unicode.
3415 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3416 DWORD buflen, DWORD *needed)
3418 DWORD sz = buflen, type;
3421 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3422 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3423 WARN("Got ret = %d\n", ret);
3427 /* add space for terminating '\0' */
3428 sz += sizeof(WCHAR);
3432 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3437 /*****************************************************************************
3438 * WINSPOOL_GetDefaultDevMode
3440 * Get a default DevMode values for wineps.
3444 static void WINSPOOL_GetDefaultDevMode(
3446 DWORD buflen, DWORD *needed)
3449 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3451 /* fill default DEVMODE - should be read from ppd... */
3452 ZeroMemory( &dm, sizeof(dm) );
3453 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3454 dm.dmSpecVersion = DM_SPECVERSION;
3455 dm.dmDriverVersion = 1;
3456 dm.dmSize = sizeof(DEVMODEW);
3457 dm.dmDriverExtra = 0;
3459 DM_ORIENTATION | DM_PAPERSIZE |
3460 DM_PAPERLENGTH | DM_PAPERWIDTH |
3463 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3464 DM_YRESOLUTION | DM_TTOPTION;
3466 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3467 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3468 dm.u1.s1.dmPaperLength = 2970;
3469 dm.u1.s1.dmPaperWidth = 2100;
3471 dm.u1.s1.dmScale = 100;
3472 dm.u1.s1.dmCopies = 1;
3473 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3474 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3477 dm.dmYResolution = 300; /* 300dpi */
3478 dm.dmTTOption = DMTT_BITMAP;
3481 /* dm.dmLogPixels */
3482 /* dm.dmBitsPerPel */
3483 /* dm.dmPelsWidth */
3484 /* dm.dmPelsHeight */
3485 /* dm.u2.dmDisplayFlags */
3486 /* dm.dmDisplayFrequency */
3487 /* dm.dmICMMethod */
3488 /* dm.dmICMIntent */
3489 /* dm.dmMediaType */
3490 /* dm.dmDitherType */
3491 /* dm.dmReserved1 */
3492 /* dm.dmReserved2 */
3493 /* dm.dmPanningWidth */
3494 /* dm.dmPanningHeight */
3496 if(buflen >= sizeof(DEVMODEW))
3497 memcpy(ptr, &dm, sizeof(DEVMODEW));
3498 *needed = sizeof(DEVMODEW);
3501 /*****************************************************************************
3502 * WINSPOOL_GetDevModeFromReg
3504 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3505 * DevMode is stored either as unicode or ascii.
3507 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3509 DWORD buflen, DWORD *needed)
3511 DWORD sz = buflen, type;
3514 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3515 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3516 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3517 if (sz < sizeof(DEVMODEA))
3519 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3522 /* ensures that dmSize is not erratically bogus if registry is invalid */
3523 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3524 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3525 sz += (CCHDEVICENAME + CCHFORMNAME);
3526 if (ptr && (buflen >= sz)) {
3527 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3528 memcpy(ptr, dmW, sz);
3529 HeapFree(GetProcessHeap(),0,dmW);
3535 /*********************************************************************
3536 * WINSPOOL_GetPrinter_1
3538 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3540 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3541 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3543 DWORD size, left = cbBuf;
3544 BOOL space = (cbBuf > 0);
3549 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3550 if(space && size <= left) {
3551 pi1->pName = (LPWSTR)ptr;
3559 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3560 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3561 if(space && size <= left) {
3562 pi1->pDescription = (LPWSTR)ptr;
3570 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3571 if(space && size <= left) {
3572 pi1->pComment = (LPWSTR)ptr;
3580 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3582 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3583 memset(pi1, 0, sizeof(*pi1));
3587 /*********************************************************************
3588 * WINSPOOL_GetPrinter_2
3590 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3592 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3593 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3595 DWORD size, left = cbBuf;
3596 BOOL space = (cbBuf > 0);
3601 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3602 if(space && size <= left) {
3603 pi2->pPrinterName = (LPWSTR)ptr;
3610 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3611 if(space && size <= left) {
3612 pi2->pShareName = (LPWSTR)ptr;
3619 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3620 if(space && size <= left) {
3621 pi2->pPortName = (LPWSTR)ptr;
3628 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3629 if(space && size <= left) {
3630 pi2->pDriverName = (LPWSTR)ptr;
3637 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3638 if(space && size <= left) {
3639 pi2->pComment = (LPWSTR)ptr;
3646 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3647 if(space && size <= left) {
3648 pi2->pLocation = (LPWSTR)ptr;
3655 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3656 if(space && size <= left) {
3657 pi2->pDevMode = (LPDEVMODEW)ptr;
3666 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3667 if(space && size <= left) {
3668 pi2->pDevMode = (LPDEVMODEW)ptr;
3675 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3676 if(space && size <= left) {
3677 pi2->pSepFile = (LPWSTR)ptr;
3684 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3685 if(space && size <= left) {
3686 pi2->pPrintProcessor = (LPWSTR)ptr;
3693 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3694 if(space && size <= left) {
3695 pi2->pDatatype = (LPWSTR)ptr;
3702 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3703 if(space && size <= left) {
3704 pi2->pParameters = (LPWSTR)ptr;
3712 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3713 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3714 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3715 "Default Priority");
3716 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3717 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3720 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3721 memset(pi2, 0, sizeof(*pi2));
3726 /*********************************************************************
3727 * WINSPOOL_GetPrinter_4
3729 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3731 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3732 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3734 DWORD size, left = cbBuf;
3735 BOOL space = (cbBuf > 0);
3740 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3741 if(space && size <= left) {
3742 pi4->pPrinterName = (LPWSTR)ptr;
3750 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3753 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3754 memset(pi4, 0, sizeof(*pi4));
3759 /*********************************************************************
3760 * WINSPOOL_GetPrinter_5
3762 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3764 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3765 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3767 DWORD size, left = cbBuf;
3768 BOOL space = (cbBuf > 0);
3773 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3774 if(space && size <= left) {
3775 pi5->pPrinterName = (LPWSTR)ptr;
3782 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3783 if(space && size <= left) {
3784 pi5->pPortName = (LPWSTR)ptr;
3792 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3793 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3795 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3799 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3800 memset(pi5, 0, sizeof(*pi5));
3805 /*********************************************************************
3806 * WINSPOOL_GetPrinter_7
3808 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3810 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3811 DWORD cbBuf, LPDWORD pcbNeeded)
3813 DWORD size, left = cbBuf;
3814 BOOL space = (cbBuf > 0);
3819 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3822 size = sizeof(pi7->pszObjectGUID);
3824 if (space && size <= left) {
3825 pi7->pszObjectGUID = (LPWSTR)ptr;
3832 /* We do not have a Directory Service */
3833 pi7->dwAction = DSPRINT_UNPUBLISH;
3836 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3837 memset(pi7, 0, sizeof(*pi7));
3842 /*********************************************************************
3843 * WINSPOOL_GetPrinter_9
3845 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3847 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3848 DWORD cbBuf, LPDWORD pcbNeeded)
3851 BOOL space = (cbBuf > 0);
3855 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3856 if(space && size <= cbBuf) {
3857 pi9->pDevMode = (LPDEVMODEW)buf;
3864 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3865 if(space && size <= cbBuf) {
3866 pi9->pDevMode = (LPDEVMODEW)buf;
3872 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3873 memset(pi9, 0, sizeof(*pi9));
3878 /*****************************************************************************
3879 * GetPrinterW [WINSPOOL.@]
3881 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3882 DWORD cbBuf, LPDWORD pcbNeeded)
3884 DWORD size, needed = 0, err;
3889 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3891 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3894 SetLastError( err );
3901 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3903 size = sizeof(PRINTER_INFO_2W);
3905 ptr = pPrinter + size;
3907 memset(pPrinter, 0, size);
3912 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3919 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3921 size = sizeof(PRINTER_INFO_4W);
3923 ptr = pPrinter + size;
3925 memset(pPrinter, 0, size);
3930 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3938 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3940 size = sizeof(PRINTER_INFO_5W);
3942 ptr = pPrinter + size;
3944 memset(pPrinter, 0, size);
3950 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3958 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3960 size = sizeof(PRINTER_INFO_6);
3961 if (size <= cbBuf) {
3962 /* FIXME: We do not update the status yet */
3963 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3975 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3977 size = sizeof(PRINTER_INFO_7W);
3978 if (size <= cbBuf) {
3979 ptr = pPrinter + size;
3981 memset(pPrinter, 0, size);
3987 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3995 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3997 size = sizeof(PRINTER_INFO_9W);
3999 ptr = pPrinter + size;
4001 memset(pPrinter, 0, size);
4007 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4014 FIXME("Unimplemented level %d\n", Level);
4015 SetLastError(ERROR_INVALID_LEVEL);
4016 RegCloseKey(hkeyPrinter);
4020 RegCloseKey(hkeyPrinter);
4022 TRACE("returning %d needed = %d\n", ret, needed);
4023 if(pcbNeeded) *pcbNeeded = needed;
4025 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4029 /*****************************************************************************
4030 * GetPrinterA [WINSPOOL.@]
4032 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4033 DWORD cbBuf, LPDWORD pcbNeeded)
4039 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4041 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4043 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4044 HeapFree(GetProcessHeap(), 0, buf);
4049 /*****************************************************************************
4050 * WINSPOOL_EnumPrintersW
4052 * Implementation of EnumPrintersW
4054 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4055 DWORD dwLevel, LPBYTE lpbPrinters,
4056 DWORD cbBuf, LPDWORD lpdwNeeded,
4057 LPDWORD lpdwReturned)
4060 HKEY hkeyPrinters, hkeyPrinter;
4061 WCHAR PrinterName[255];
4062 DWORD needed = 0, number = 0;
4063 DWORD used, i, left;
4067 memset(lpbPrinters, 0, cbBuf);
4073 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4074 if(dwType == PRINTER_ENUM_DEFAULT)
4077 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4078 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4079 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4081 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4087 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4088 FIXME("dwType = %08x\n", dwType);
4089 SetLastError(ERROR_INVALID_FLAGS);
4093 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4095 ERR("Can't create Printers key\n");
4099 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4100 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4101 RegCloseKey(hkeyPrinters);
4102 ERR("Can't query Printers key\n");
4105 TRACE("Found %d printers\n", number);
4109 used = number * sizeof(PRINTER_INFO_1W);
4112 used = number * sizeof(PRINTER_INFO_2W);
4115 used = number * sizeof(PRINTER_INFO_4W);
4118 used = number * sizeof(PRINTER_INFO_5W);
4122 SetLastError(ERROR_INVALID_LEVEL);
4123 RegCloseKey(hkeyPrinters);
4126 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4128 for(i = 0; i < number; i++) {
4129 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4131 ERR("Can't enum key number %d\n", i);
4132 RegCloseKey(hkeyPrinters);
4135 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4136 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4138 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4139 RegCloseKey(hkeyPrinters);
4144 buf = lpbPrinters + used;
4145 left = cbBuf - used;
4153 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4156 if(pi) pi += sizeof(PRINTER_INFO_1W);
4159 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4162 if(pi) pi += sizeof(PRINTER_INFO_2W);
4165 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4168 if(pi) pi += sizeof(PRINTER_INFO_4W);
4171 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4174 if(pi) pi += sizeof(PRINTER_INFO_5W);
4177 ERR("Shouldn't be here!\n");
4178 RegCloseKey(hkeyPrinter);
4179 RegCloseKey(hkeyPrinters);
4182 RegCloseKey(hkeyPrinter);
4184 RegCloseKey(hkeyPrinters);
4191 memset(lpbPrinters, 0, cbBuf);
4192 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4196 *lpdwReturned = number;
4197 SetLastError(ERROR_SUCCESS);
4202 /******************************************************************
4203 * EnumPrintersW [WINSPOOL.@]
4205 * Enumerates the available printers, print servers and print
4206 * providers, depending on the specified flags, name and level.
4210 * If level is set to 1:
4211 * Returns an array of PRINTER_INFO_1 data structures in the
4212 * lpbPrinters buffer.
4214 * If level is set to 2:
4215 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4216 * Returns an array of PRINTER_INFO_2 data structures in the
4217 * lpbPrinters buffer. Note that according to MSDN also an
4218 * OpenPrinter should be performed on every remote printer.
4220 * If level is set to 4 (officially WinNT only):
4221 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4222 * Fast: Only the registry is queried to retrieve printer names,
4223 * no connection to the driver is made.
4224 * Returns an array of PRINTER_INFO_4 data structures in the
4225 * lpbPrinters buffer.
4227 * If level is set to 5 (officially WinNT4/Win9x only):
4228 * Fast: Only the registry is queried to retrieve printer names,
4229 * no connection to the driver is made.
4230 * Returns an array of PRINTER_INFO_5 data structures in the
4231 * lpbPrinters buffer.
4233 * If level set to 3 or 6+:
4234 * returns zero (failure!)
4236 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4240 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4241 * - Only levels 2, 4 and 5 are implemented at the moment.
4242 * - 16-bit printer drivers are not enumerated.
4243 * - Returned amount of bytes used/needed does not match the real Windoze
4244 * implementation (as in this implementation, all strings are part
4245 * of the buffer, whereas Win32 keeps them somewhere else)
4246 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4249 * - In a regular Wine installation, no registry settings for printers
4250 * exist, which makes this function return an empty list.
4252 BOOL WINAPI EnumPrintersW(
4253 DWORD dwType, /* [in] Types of print objects to enumerate */
4254 LPWSTR lpszName, /* [in] name of objects to enumerate */
4255 DWORD dwLevel, /* [in] type of printer info structure */
4256 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4257 DWORD cbBuf, /* [in] max size of buffer in bytes */
4258 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4259 LPDWORD lpdwReturned /* [out] number of entries returned */
4262 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4263 lpdwNeeded, lpdwReturned);
4266 /******************************************************************
4267 * EnumPrintersA [WINSPOOL.@]
4272 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4273 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4276 UNICODE_STRING pNameU;
4280 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4281 pPrinters, cbBuf, pcbNeeded, pcReturned);
4283 pNameW = asciitounicode(&pNameU, pName);
4285 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4286 MS Office need this */
4287 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4289 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4291 RtlFreeUnicodeString(&pNameU);
4293 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4295 HeapFree(GetProcessHeap(), 0, pPrintersW);
4299 /*****************************************************************************
4300 * WINSPOOL_GetDriverInfoFromReg [internal]
4302 * Enters the information from the registry into the DRIVER_INFO struct
4305 * zero if the printer driver does not exist in the registry
4306 * (only if Level > 1) otherwise nonzero
4308 static BOOL WINSPOOL_GetDriverInfoFromReg(
4311 const printenv_t * env,
4313 LPBYTE ptr, /* DRIVER_INFO */
4314 LPBYTE pDriverStrings, /* strings buffer */
4315 DWORD cbBuf, /* size of string buffer */
4316 LPDWORD pcbNeeded) /* space needed for str. */
4320 WCHAR driverdir[MAX_PATH];
4322 LPBYTE strPtr = pDriverStrings;
4323 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4325 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4326 debugstr_w(DriverName), env,
4327 Level, di, pDriverStrings, cbBuf);
4329 if (di) ZeroMemory(di, di_sizeof[Level]);
4331 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4332 if (*pcbNeeded <= cbBuf)
4333 strcpyW((LPWSTR)strPtr, DriverName);
4335 /* pName for level 1 has a different offset! */
4337 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4341 /* .cVersion and .pName for level > 1 */
4343 di->cVersion = env->driverversion;
4344 di->pName = (LPWSTR) strPtr;
4345 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4348 /* Reserve Space for the largest subdir and a Backslash*/
4349 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4350 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4351 /* Should never Fail */
4354 lstrcatW(driverdir, env->versionsubdir);
4355 lstrcatW(driverdir, backslashW);
4357 /* dirlen must not include the terminating zero */
4358 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4360 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4361 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4362 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4367 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4370 if (*pcbNeeded <= cbBuf) {
4371 lstrcpyW((LPWSTR)strPtr, env->envname);
4372 if (di) di->pEnvironment = (LPWSTR)strPtr;
4373 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4376 /* .pDriverPath is the Graphics rendering engine.
4377 The full Path is required to avoid a crash in some apps */
4378 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4380 if (*pcbNeeded <= cbBuf)
4381 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4383 if (di) di->pDriverPath = (LPWSTR)strPtr;
4384 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4387 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4388 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4390 if (*pcbNeeded <= cbBuf)
4391 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4393 if (di) di->pDataFile = (LPWSTR)strPtr;
4394 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4397 /* .pConfigFile is the Driver user Interface */
4398 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4400 if (*pcbNeeded <= cbBuf)
4401 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4403 if (di) di->pConfigFile = (LPWSTR)strPtr;
4404 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4408 RegCloseKey(hkeyDriver);
4409 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4414 RegCloseKey(hkeyDriver);
4415 FIXME("level 5: incomplete\n");
4420 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4422 if (*pcbNeeded <= cbBuf)
4423 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4425 if (di) di->pHelpFile = (LPWSTR)strPtr;
4426 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4429 /* .pDependentFiles */
4430 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4432 if (*pcbNeeded <= cbBuf)
4433 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4435 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4436 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4438 else if (GetVersion() & 0x80000000) {
4439 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4440 size = 2 * sizeof(WCHAR);
4442 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4444 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4445 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4448 /* .pMonitorName is the optional Language Monitor */
4449 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4451 if (*pcbNeeded <= cbBuf)
4452 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4454 if (di) di->pMonitorName = (LPWSTR)strPtr;
4455 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4458 /* .pDefaultDataType */
4459 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4461 if(*pcbNeeded <= cbBuf)
4462 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4464 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4465 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4469 RegCloseKey(hkeyDriver);
4470 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4474 /* .pszzPreviousNames */
4475 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4477 if(*pcbNeeded <= cbBuf)
4478 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4480 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4481 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4485 RegCloseKey(hkeyDriver);
4486 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4490 /* support is missing, but not important enough for a FIXME */
4491 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4494 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4496 if(*pcbNeeded <= cbBuf)
4497 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4499 if (di) di->pszMfgName = (LPWSTR)strPtr;
4500 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4504 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4506 if(*pcbNeeded <= cbBuf)
4507 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4509 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4510 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4513 /* .pszHardwareID */
4514 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4516 if(*pcbNeeded <= cbBuf)
4517 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4519 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4520 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4524 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4526 if(*pcbNeeded <= cbBuf)
4527 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4529 if (di) di->pszProvider = (LPWSTR)strPtr;
4530 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4534 RegCloseKey(hkeyDriver);
4538 /* support is missing, but not important enough for a FIXME */
4539 TRACE("level 8: incomplete\n");
4541 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4542 RegCloseKey(hkeyDriver);
4546 /*****************************************************************************
4547 * GetPrinterDriverW [WINSPOOL.@]
4549 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4550 DWORD Level, LPBYTE pDriverInfo,
4551 DWORD cbBuf, LPDWORD pcbNeeded)
4554 WCHAR DriverName[100];
4555 DWORD ret, type, size, needed = 0;
4557 HKEY hkeyPrinter, hkeyDrivers;
4558 const printenv_t * env;
4560 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4561 Level,pDriverInfo,cbBuf, pcbNeeded);
4564 ZeroMemory(pDriverInfo, cbBuf);
4566 if (!(name = get_opened_printer_name(hPrinter))) {
4567 SetLastError(ERROR_INVALID_HANDLE);
4571 if (Level < 1 || Level == 7 || Level > 8) {
4572 SetLastError(ERROR_INVALID_LEVEL);
4576 env = validate_envW(pEnvironment);
4577 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4579 ret = open_printer_reg_key( name, &hkeyPrinter );
4582 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4583 SetLastError( ret );
4587 size = sizeof(DriverName);
4589 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4590 (LPBYTE)DriverName, &size);
4591 RegCloseKey(hkeyPrinter);
4592 if(ret != ERROR_SUCCESS) {
4593 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4597 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4599 ERR("Can't create Drivers key\n");
4603 size = di_sizeof[Level];
4604 if ((size <= cbBuf) && pDriverInfo)
4605 ptr = pDriverInfo + size;
4607 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4608 env, Level, pDriverInfo, ptr,
4609 (cbBuf < size) ? 0 : cbBuf - size,
4611 RegCloseKey(hkeyDrivers);
4615 RegCloseKey(hkeyDrivers);
4617 if(pcbNeeded) *pcbNeeded = size + needed;
4618 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4619 if(cbBuf >= size + needed) return TRUE;
4620 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4624 /*****************************************************************************
4625 * GetPrinterDriverA [WINSPOOL.@]
4627 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4628 DWORD Level, LPBYTE pDriverInfo,
4629 DWORD cbBuf, LPDWORD pcbNeeded)
4632 UNICODE_STRING pEnvW;
4638 ZeroMemory(pDriverInfo, cbBuf);
4639 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4642 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4643 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4646 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4648 HeapFree(GetProcessHeap(), 0, buf);
4650 RtlFreeUnicodeString(&pEnvW);
4654 /*****************************************************************************
4655 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4657 * Return the PATH for the Printer-Drivers (UNICODE)
4660 * pName [I] Servername (NT only) or NULL (local Computer)
4661 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4662 * Level [I] Structure-Level (must be 1)
4663 * pDriverDirectory [O] PTR to Buffer that receives the Result
4664 * cbBuf [I] Size of Buffer at pDriverDirectory
4665 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4666 * required for pDriverDirectory
4669 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4670 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4671 * if cbBuf is too small
4673 * Native Values returned in pDriverDirectory on Success:
4674 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4675 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4676 *| win9x(Windows 4.0): "%winsysdir%"
4678 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4681 *- Only NULL or "" is supported for pName
4684 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4685 DWORD Level, LPBYTE pDriverDirectory,
4686 DWORD cbBuf, LPDWORD pcbNeeded)
4688 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4689 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4691 if ((backend == NULL) && !load_backend()) return FALSE;
4694 /* (Level != 1) is ignored in win9x */
4695 SetLastError(ERROR_INVALID_LEVEL);
4698 if (pcbNeeded == NULL) {
4699 /* (pcbNeeded == NULL) is ignored in win9x */
4700 SetLastError(RPC_X_NULL_REF_POINTER);
4704 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4705 pDriverDirectory, cbBuf, pcbNeeded);
4710 /*****************************************************************************
4711 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4713 * Return the PATH for the Printer-Drivers (ANSI)
4715 * See GetPrinterDriverDirectoryW.
4718 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4721 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4722 DWORD Level, LPBYTE pDriverDirectory,
4723 DWORD cbBuf, LPDWORD pcbNeeded)
4725 UNICODE_STRING nameW, environmentW;
4728 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4729 WCHAR *driverDirectoryW = NULL;
4731 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4732 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4734 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4736 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4737 else nameW.Buffer = NULL;
4738 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4739 else environmentW.Buffer = NULL;
4741 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4742 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4745 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4746 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4748 *pcbNeeded = needed;
4749 ret = (needed <= cbBuf) ? TRUE : FALSE;
4751 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4753 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4755 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4756 RtlFreeUnicodeString(&environmentW);
4757 RtlFreeUnicodeString(&nameW);
4762 /*****************************************************************************
4763 * AddPrinterDriverA [WINSPOOL.@]
4765 * See AddPrinterDriverW.
4768 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4770 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4771 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4774 /******************************************************************************
4775 * AddPrinterDriverW (WINSPOOL.@)
4777 * Install a Printer Driver
4780 * pName [I] Servername or NULL (local Computer)
4781 * level [I] Level for the supplied DRIVER_INFO_*W struct
4782 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4789 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4791 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4792 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4795 /*****************************************************************************
4796 * AddPrintProcessorA [WINSPOOL.@]
4798 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4799 LPSTR pPrintProcessorName)
4801 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4802 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4806 /*****************************************************************************
4807 * AddPrintProcessorW [WINSPOOL.@]
4809 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4810 LPWSTR pPrintProcessorName)
4812 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4813 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4817 /*****************************************************************************
4818 * AddPrintProvidorA [WINSPOOL.@]
4820 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4822 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4826 /*****************************************************************************
4827 * AddPrintProvidorW [WINSPOOL.@]
4829 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4831 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4835 /*****************************************************************************
4836 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4838 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4839 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4841 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4842 pDevModeOutput, pDevModeInput);
4846 /*****************************************************************************
4847 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4849 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4850 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4852 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4853 pDevModeOutput, pDevModeInput);
4857 /*****************************************************************************
4858 * PrinterProperties [WINSPOOL.@]
4860 * Displays a dialog to set the properties of the printer.
4863 * nonzero on success or zero on failure
4866 * implemented as stub only
4868 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4869 HANDLE hPrinter /* [in] handle to printer object */
4871 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4872 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4876 /*****************************************************************************
4877 * EnumJobsA [WINSPOOL.@]
4880 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4881 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4884 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4885 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4887 if(pcbNeeded) *pcbNeeded = 0;
4888 if(pcReturned) *pcReturned = 0;
4893 /*****************************************************************************
4894 * EnumJobsW [WINSPOOL.@]
4897 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4898 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4901 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4902 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4904 if(pcbNeeded) *pcbNeeded = 0;
4905 if(pcReturned) *pcReturned = 0;
4909 /*****************************************************************************
4910 * WINSPOOL_EnumPrinterDrivers [internal]
4912 * Delivers information about all printer drivers installed on the
4913 * localhost or a given server
4916 * nonzero on success or zero on failure. If the buffer for the returned
4917 * information is too small the function will return an error
4920 * - only implemented for localhost, foreign hosts will return an error
4922 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4923 DWORD Level, LPBYTE pDriverInfo,
4925 DWORD cbBuf, LPDWORD pcbNeeded,
4926 LPDWORD pcFound, DWORD data_offset)
4930 const printenv_t * env;
4932 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4933 debugstr_w(pName), debugstr_w(pEnvironment),
4934 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4936 env = validate_envW(pEnvironment);
4937 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4941 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4943 ERR("Can't open Drivers key\n");
4947 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4948 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4949 RegCloseKey(hkeyDrivers);
4950 ERR("Can't query Drivers key\n");
4953 TRACE("Found %d Drivers\n", *pcFound);
4955 /* get size of single struct
4956 * unicode and ascii structure have the same size
4958 size = di_sizeof[Level];
4960 if (data_offset == 0)
4961 data_offset = size * (*pcFound);
4962 *pcbNeeded = data_offset;
4964 for( i = 0; i < *pcFound; i++) {
4965 WCHAR DriverNameW[255];
4966 PBYTE table_ptr = NULL;
4967 PBYTE data_ptr = NULL;
4970 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4972 ERR("Can't enum key number %d\n", i);
4973 RegCloseKey(hkeyDrivers);
4977 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4978 table_ptr = pDriverInfo + (driver_index + i) * size;
4979 if (pDriverInfo && *pcbNeeded <= cbBuf)
4980 data_ptr = pDriverInfo + *pcbNeeded;
4982 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4983 env, Level, table_ptr, data_ptr,
4984 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4986 RegCloseKey(hkeyDrivers);
4990 *pcbNeeded += needed;
4993 RegCloseKey(hkeyDrivers);
4995 if(cbBuf < *pcbNeeded){
4996 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5003 /*****************************************************************************
5004 * EnumPrinterDriversW [WINSPOOL.@]
5006 * see function EnumPrinterDrivers for RETURNS, BUGS
5008 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5009 LPBYTE pDriverInfo, DWORD cbBuf,
5010 LPDWORD pcbNeeded, LPDWORD pcReturned)
5012 static const WCHAR allW[] = {'a','l','l',0};
5016 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5018 SetLastError(RPC_X_NULL_REF_POINTER);
5022 /* check for local drivers */
5023 if((pName) && (pName[0])) {
5024 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5025 SetLastError(ERROR_ACCESS_DENIED);
5029 /* check input parameter */
5030 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5031 SetLastError(ERROR_INVALID_LEVEL);
5035 if(pDriverInfo && cbBuf > 0)
5036 memset( pDriverInfo, 0, cbBuf);
5038 /* Exception: pull all printers */
5039 if (pEnvironment && !strcmpW(pEnvironment, allW))
5041 DWORD i, needed, bufsize = cbBuf;
5042 DWORD total_needed = 0;
5043 DWORD total_found = 0;
5046 /* Precompute the overall total; we need this to know
5047 where pointers end and data begins (i.e. data_offset) */
5048 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5051 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5052 NULL, 0, 0, &needed, &found, 0);
5053 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5054 total_needed += needed;
5055 total_found += found;
5058 data_offset = di_sizeof[Level] * total_found;
5063 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5066 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5067 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5068 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5070 *pcReturned += found;
5071 *pcbNeeded = needed;
5072 data_offset = needed;
5073 total_found += found;
5078 /* Normal behavior */
5079 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5080 0, cbBuf, pcbNeeded, &found, 0);
5082 *pcReturned = found;
5087 /*****************************************************************************
5088 * EnumPrinterDriversA [WINSPOOL.@]
5090 * see function EnumPrinterDrivers for RETURNS, BUGS
5092 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5093 LPBYTE pDriverInfo, DWORD cbBuf,
5094 LPDWORD pcbNeeded, LPDWORD pcReturned)
5097 UNICODE_STRING pNameW, pEnvironmentW;
5098 PWSTR pwstrNameW, pwstrEnvironmentW;
5102 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5104 pwstrNameW = asciitounicode(&pNameW, pName);
5105 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5107 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5108 buf, cbBuf, pcbNeeded, pcReturned);
5110 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5112 HeapFree(GetProcessHeap(), 0, buf);
5114 RtlFreeUnicodeString(&pNameW);
5115 RtlFreeUnicodeString(&pEnvironmentW);
5120 /******************************************************************************
5121 * EnumPortsA (WINSPOOL.@)
5126 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5127 LPDWORD pcbNeeded, LPDWORD pcReturned)
5130 LPBYTE bufferW = NULL;
5131 LPWSTR nameW = NULL;
5133 DWORD numentries = 0;
5136 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5137 cbBuf, pcbNeeded, pcReturned);
5139 /* convert servername to unicode */
5141 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5142 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5143 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5145 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5146 needed = cbBuf * sizeof(WCHAR);
5147 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5148 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5150 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5151 if (pcbNeeded) needed = *pcbNeeded;
5152 /* HeapReAlloc return NULL, when bufferW was NULL */
5153 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5154 HeapAlloc(GetProcessHeap(), 0, needed);
5156 /* Try again with the large Buffer */
5157 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5159 needed = pcbNeeded ? *pcbNeeded : 0;
5160 numentries = pcReturned ? *pcReturned : 0;
5163 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5164 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5167 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5168 DWORD entrysize = 0;
5171 LPPORT_INFO_2W pi2w;
5172 LPPORT_INFO_2A pi2a;
5175 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5177 /* First pass: calculate the size for all Entries */
5178 pi2w = (LPPORT_INFO_2W) bufferW;
5179 pi2a = (LPPORT_INFO_2A) pPorts;
5181 while (index < numentries) {
5183 needed += entrysize; /* PORT_INFO_?A */
5184 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5186 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5187 NULL, 0, NULL, NULL);
5189 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5190 NULL, 0, NULL, NULL);
5191 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5192 NULL, 0, NULL, NULL);
5194 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5195 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5196 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5199 /* check for errors and quit on failure */
5200 if (cbBuf < needed) {
5201 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5205 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5206 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5207 cbBuf -= len ; /* free Bytes in the user-Buffer */
5208 pi2w = (LPPORT_INFO_2W) bufferW;
5209 pi2a = (LPPORT_INFO_2A) pPorts;
5211 /* Second Pass: Fill the User Buffer (if we have one) */
5212 while ((index < numentries) && pPorts) {
5214 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5215 pi2a->pPortName = ptr;
5216 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5217 ptr, cbBuf , NULL, NULL);
5221 pi2a->pMonitorName = ptr;
5222 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5223 ptr, cbBuf, NULL, NULL);
5227 pi2a->pDescription = ptr;
5228 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5229 ptr, cbBuf, NULL, NULL);
5233 pi2a->fPortType = pi2w->fPortType;
5234 pi2a->Reserved = 0; /* documented: "must be zero" */
5237 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5238 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5239 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5244 if (pcbNeeded) *pcbNeeded = needed;
5245 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5247 HeapFree(GetProcessHeap(), 0, nameW);
5248 HeapFree(GetProcessHeap(), 0, bufferW);
5250 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5251 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5257 /******************************************************************************
5258 * EnumPortsW (WINSPOOL.@)
5260 * Enumerate available Ports
5263 * pName [I] Servername or NULL (local Computer)
5264 * Level [I] Structure-Level (1 or 2)
5265 * pPorts [O] PTR to Buffer that receives the Result
5266 * cbBuf [I] Size of Buffer at pPorts
5267 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5268 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5272 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5275 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5278 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5279 cbBuf, pcbNeeded, pcReturned);
5281 if ((backend == NULL) && !load_backend()) return FALSE;
5283 /* Level is not checked in win9x */
5284 if (!Level || (Level > 2)) {
5285 WARN("level (%d) is ignored in win9x\n", Level);
5286 SetLastError(ERROR_INVALID_LEVEL);
5289 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5290 SetLastError(RPC_X_NULL_REF_POINTER);
5294 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5297 /******************************************************************************
5298 * GetDefaultPrinterW (WINSPOOL.@)
5301 * This function must read the value from data 'device' of key
5302 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5304 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5308 WCHAR *buffer, *ptr;
5312 SetLastError(ERROR_INVALID_PARAMETER);
5316 /* make the buffer big enough for the stuff from the profile/registry,
5317 * the content must fit into the local buffer to compute the correct
5318 * size even if the extern buffer is too small or not given.
5319 * (20 for ,driver,port) */
5321 len = max(100, (insize + 20));
5322 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5324 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5326 SetLastError (ERROR_FILE_NOT_FOUND);
5330 TRACE("%s\n", debugstr_w(buffer));
5332 if ((ptr = strchrW(buffer, ',')) == NULL)
5334 SetLastError(ERROR_INVALID_NAME);
5340 *namesize = strlenW(buffer) + 1;
5341 if(!name || (*namesize > insize))
5343 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5347 strcpyW(name, buffer);
5350 HeapFree( GetProcessHeap(), 0, buffer);
5355 /******************************************************************************
5356 * GetDefaultPrinterA (WINSPOOL.@)
5358 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5362 WCHAR *bufferW = NULL;
5366 SetLastError(ERROR_INVALID_PARAMETER);
5370 if(name && *namesize) {
5372 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5375 if(!GetDefaultPrinterW( bufferW, namesize)) {
5380 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5384 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5387 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5390 HeapFree( GetProcessHeap(), 0, bufferW);
5395 /******************************************************************************
5396 * SetDefaultPrinterW (WINSPOOL.204)
5398 * Set the Name of the Default Printer
5401 * pszPrinter [I] Name of the Printer or NULL
5408 * When the Parameter is NULL or points to an Empty String and
5409 * a Default Printer was already present, then this Function changes nothing.
5410 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5411 * the First enumerated local Printer is used.
5414 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5416 WCHAR default_printer[MAX_PATH];
5417 LPWSTR buffer = NULL;
5423 TRACE("(%s)\n", debugstr_w(pszPrinter));
5424 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5426 default_printer[0] = '\0';
5427 size = sizeof(default_printer)/sizeof(WCHAR);
5429 /* if we have a default Printer, do nothing. */
5430 if (GetDefaultPrinterW(default_printer, &size))
5434 /* we have no default Printer: search local Printers and use the first */
5435 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5437 default_printer[0] = '\0';
5438 size = sizeof(default_printer)/sizeof(WCHAR);
5439 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5441 pszPrinter = default_printer;
5442 TRACE("using %s\n", debugstr_w(pszPrinter));
5447 if (pszPrinter == NULL) {
5448 TRACE("no local printer found\n");
5449 SetLastError(ERROR_FILE_NOT_FOUND);
5454 /* "pszPrinter" is never empty or NULL here. */
5455 namelen = lstrlenW(pszPrinter);
5456 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5457 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5459 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5460 HeapFree(GetProcessHeap(), 0, buffer);
5461 SetLastError(ERROR_FILE_NOT_FOUND);
5465 /* read the devices entry for the printer (driver,port) to build the string for the
5466 default device entry (printer,driver,port) */
5467 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5468 buffer[namelen] = ',';
5469 namelen++; /* move index to the start of the driver */
5471 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5472 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5474 TRACE("set device to %s\n", debugstr_w(buffer));
5476 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5477 TRACE("failed to set the device entry: %d\n", GetLastError());
5478 lres = ERROR_INVALID_PRINTER_NAME;
5481 /* remove the next section, when INIFileMapping is implemented */
5484 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5485 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5492 if (lres != ERROR_FILE_NOT_FOUND)
5493 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5495 SetLastError(ERROR_INVALID_PRINTER_NAME);
5499 HeapFree(GetProcessHeap(), 0, buffer);
5500 return (lres == ERROR_SUCCESS);
5503 /******************************************************************************
5504 * SetDefaultPrinterA (WINSPOOL.202)
5506 * See SetDefaultPrinterW.
5509 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5511 LPWSTR bufferW = NULL;
5514 TRACE("(%s)\n", debugstr_a(pszPrinter));
5516 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5517 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5518 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5520 res = SetDefaultPrinterW(bufferW);
5521 HeapFree(GetProcessHeap(), 0, bufferW);
5525 /******************************************************************************
5526 * SetPrinterDataExA (WINSPOOL.@)
5528 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5529 LPCSTR pValueName, DWORD Type,
5530 LPBYTE pData, DWORD cbData)
5532 HKEY hkeyPrinter, hkeySubkey;
5535 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5536 debugstr_a(pValueName), Type, pData, cbData);
5538 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5542 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5544 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5545 RegCloseKey(hkeyPrinter);
5548 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5549 RegCloseKey(hkeySubkey);
5550 RegCloseKey(hkeyPrinter);
5554 /******************************************************************************
5555 * SetPrinterDataExW (WINSPOOL.@)
5557 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5558 LPCWSTR pValueName, DWORD Type,
5559 LPBYTE pData, DWORD cbData)
5561 HKEY hkeyPrinter, hkeySubkey;
5564 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5565 debugstr_w(pValueName), Type, pData, cbData);
5567 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5571 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5573 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5574 RegCloseKey(hkeyPrinter);
5577 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5578 RegCloseKey(hkeySubkey);
5579 RegCloseKey(hkeyPrinter);
5583 /******************************************************************************
5584 * SetPrinterDataA (WINSPOOL.@)
5586 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5587 LPBYTE pData, DWORD cbData)
5589 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5593 /******************************************************************************
5594 * SetPrinterDataW (WINSPOOL.@)
5596 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5597 LPBYTE pData, DWORD cbData)
5599 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5603 /******************************************************************************
5604 * GetPrinterDataExA (WINSPOOL.@)
5606 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5607 LPCSTR pValueName, LPDWORD pType,
5608 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5610 opened_printer_t *printer;
5611 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5614 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5615 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5617 printer = get_opened_printer(hPrinter);
5618 if(!printer) return ERROR_INVALID_HANDLE;
5620 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5621 if (ret) return ret;
5623 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5625 if (printer->name) {
5627 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5629 RegCloseKey(hkeyPrinters);
5632 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5633 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5634 RegCloseKey(hkeyPrinter);
5635 RegCloseKey(hkeyPrinters);
5640 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5641 0, pType, pData, pcbNeeded);
5643 if (!ret && !pData) ret = ERROR_MORE_DATA;
5645 RegCloseKey(hkeySubkey);
5646 RegCloseKey(hkeyPrinter);
5647 RegCloseKey(hkeyPrinters);
5649 TRACE("--> %d\n", ret);
5653 /******************************************************************************
5654 * GetPrinterDataExW (WINSPOOL.@)
5656 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5657 LPCWSTR pValueName, LPDWORD pType,
5658 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5660 opened_printer_t *printer;
5661 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5664 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5665 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5667 printer = get_opened_printer(hPrinter);
5668 if(!printer) return ERROR_INVALID_HANDLE;
5670 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5671 if (ret) return ret;
5673 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5675 if (printer->name) {
5677 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5679 RegCloseKey(hkeyPrinters);
5682 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5683 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5684 RegCloseKey(hkeyPrinter);
5685 RegCloseKey(hkeyPrinters);
5690 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5691 0, pType, pData, pcbNeeded);
5693 if (!ret && !pData) ret = ERROR_MORE_DATA;
5695 RegCloseKey(hkeySubkey);
5696 RegCloseKey(hkeyPrinter);
5697 RegCloseKey(hkeyPrinters);
5699 TRACE("--> %d\n", ret);
5703 /******************************************************************************
5704 * GetPrinterDataA (WINSPOOL.@)
5706 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5707 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5709 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5710 pData, nSize, pcbNeeded);
5713 /******************************************************************************
5714 * GetPrinterDataW (WINSPOOL.@)
5716 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5717 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5719 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5720 pData, nSize, pcbNeeded);
5723 /*******************************************************************************
5724 * EnumPrinterDataExW [WINSPOOL.@]
5726 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5727 LPBYTE pEnumValues, DWORD cbEnumValues,
5728 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5730 HKEY hkPrinter, hkSubKey;
5731 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5732 cbValueNameLen, cbMaxValueLen, cbValueLen,
5737 PPRINTER_ENUM_VALUESW ppev;
5739 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5741 if (pKeyName == NULL || *pKeyName == 0)
5742 return ERROR_INVALID_PARAMETER;
5744 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5745 if (ret != ERROR_SUCCESS)
5747 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5752 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5753 if (ret != ERROR_SUCCESS)
5755 r = RegCloseKey (hkPrinter);
5756 if (r != ERROR_SUCCESS)
5757 WARN ("RegCloseKey returned %i\n", r);
5758 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5759 debugstr_w (pKeyName), ret);
5763 ret = RegCloseKey (hkPrinter);
5764 if (ret != ERROR_SUCCESS)
5766 ERR ("RegCloseKey returned %i\n", ret);
5767 r = RegCloseKey (hkSubKey);
5768 if (r != ERROR_SUCCESS)
5769 WARN ("RegCloseKey returned %i\n", r);
5773 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5774 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5775 if (ret != ERROR_SUCCESS)
5777 r = RegCloseKey (hkSubKey);
5778 if (r != ERROR_SUCCESS)
5779 WARN ("RegCloseKey returned %i\n", r);
5780 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5784 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5785 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5787 if (cValues == 0) /* empty key */
5789 r = RegCloseKey (hkSubKey);
5790 if (r != ERROR_SUCCESS)
5791 WARN ("RegCloseKey returned %i\n", r);
5792 *pcbEnumValues = *pnEnumValues = 0;
5793 return ERROR_SUCCESS;
5796 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5798 hHeap = GetProcessHeap ();
5801 ERR ("GetProcessHeap failed\n");
5802 r = RegCloseKey (hkSubKey);
5803 if (r != ERROR_SUCCESS)
5804 WARN ("RegCloseKey returned %i\n", r);
5805 return ERROR_OUTOFMEMORY;
5808 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5809 if (lpValueName == NULL)
5811 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5812 r = RegCloseKey (hkSubKey);
5813 if (r != ERROR_SUCCESS)
5814 WARN ("RegCloseKey returned %i\n", r);
5815 return ERROR_OUTOFMEMORY;
5818 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5819 if (lpValue == NULL)
5821 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5822 if (HeapFree (hHeap, 0, lpValueName) == 0)
5823 WARN ("HeapFree failed with code %i\n", GetLastError ());
5824 r = RegCloseKey (hkSubKey);
5825 if (r != ERROR_SUCCESS)
5826 WARN ("RegCloseKey returned %i\n", r);
5827 return ERROR_OUTOFMEMORY;
5830 TRACE ("pass 1: calculating buffer required for all names and values\n");
5832 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5834 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5836 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5838 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5839 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5840 NULL, NULL, lpValue, &cbValueLen);
5841 if (ret != ERROR_SUCCESS)
5843 if (HeapFree (hHeap, 0, lpValue) == 0)
5844 WARN ("HeapFree failed with code %i\n", GetLastError ());
5845 if (HeapFree (hHeap, 0, lpValueName) == 0)
5846 WARN ("HeapFree failed with code %i\n", GetLastError ());
5847 r = RegCloseKey (hkSubKey);
5848 if (r != ERROR_SUCCESS)
5849 WARN ("RegCloseKey returned %i\n", r);
5850 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5854 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5855 debugstr_w (lpValueName), dwIndex,
5856 cbValueNameLen + 1, cbValueLen);
5858 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5859 cbBufSize += cbValueLen;
5862 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5864 *pcbEnumValues = cbBufSize;
5865 *pnEnumValues = cValues;
5867 if (cbEnumValues < cbBufSize) /* buffer too small */
5869 if (HeapFree (hHeap, 0, lpValue) == 0)
5870 WARN ("HeapFree failed with code %i\n", GetLastError ());
5871 if (HeapFree (hHeap, 0, lpValueName) == 0)
5872 WARN ("HeapFree failed with code %i\n", GetLastError ());
5873 r = RegCloseKey (hkSubKey);
5874 if (r != ERROR_SUCCESS)
5875 WARN ("RegCloseKey returned %i\n", r);
5876 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5877 return ERROR_MORE_DATA;
5880 TRACE ("pass 2: copying all names and values to buffer\n");
5882 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5883 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5885 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5887 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5888 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5889 NULL, &dwType, lpValue, &cbValueLen);
5890 if (ret != ERROR_SUCCESS)
5892 if (HeapFree (hHeap, 0, lpValue) == 0)
5893 WARN ("HeapFree failed with code %i\n", GetLastError ());
5894 if (HeapFree (hHeap, 0, lpValueName) == 0)
5895 WARN ("HeapFree failed with code %i\n", GetLastError ());
5896 r = RegCloseKey (hkSubKey);
5897 if (r != ERROR_SUCCESS)
5898 WARN ("RegCloseKey returned %i\n", r);
5899 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5903 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5904 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5905 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5906 pEnumValues += cbValueNameLen;
5908 /* return # of *bytes* (including trailing \0), not # of chars */
5909 ppev[dwIndex].cbValueName = cbValueNameLen;
5911 ppev[dwIndex].dwType = dwType;
5913 memcpy (pEnumValues, lpValue, cbValueLen);
5914 ppev[dwIndex].pData = pEnumValues;
5915 pEnumValues += cbValueLen;
5917 ppev[dwIndex].cbData = cbValueLen;
5919 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5920 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5923 if (HeapFree (hHeap, 0, lpValue) == 0)
5925 ret = GetLastError ();
5926 ERR ("HeapFree failed with code %i\n", ret);
5927 if (HeapFree (hHeap, 0, lpValueName) == 0)
5928 WARN ("HeapFree failed with code %i\n", GetLastError ());
5929 r = RegCloseKey (hkSubKey);
5930 if (r != ERROR_SUCCESS)
5931 WARN ("RegCloseKey returned %i\n", r);
5935 if (HeapFree (hHeap, 0, lpValueName) == 0)
5937 ret = GetLastError ();
5938 ERR ("HeapFree failed with code %i\n", ret);
5939 r = RegCloseKey (hkSubKey);
5940 if (r != ERROR_SUCCESS)
5941 WARN ("RegCloseKey returned %i\n", r);
5945 ret = RegCloseKey (hkSubKey);
5946 if (ret != ERROR_SUCCESS)
5948 ERR ("RegCloseKey returned %i\n", ret);
5952 return ERROR_SUCCESS;
5955 /*******************************************************************************
5956 * EnumPrinterDataExA [WINSPOOL.@]
5958 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5959 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5960 * what Windows 2000 SP1 does.
5963 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5964 LPBYTE pEnumValues, DWORD cbEnumValues,
5965 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5969 DWORD ret, dwIndex, dwBufSize;
5973 TRACE ("%p %s\n", hPrinter, pKeyName);
5975 if (pKeyName == NULL || *pKeyName == 0)
5976 return ERROR_INVALID_PARAMETER;
5978 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5981 ret = GetLastError ();
5982 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5986 hHeap = GetProcessHeap ();
5989 ERR ("GetProcessHeap failed\n");
5990 return ERROR_OUTOFMEMORY;
5993 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5994 if (pKeyNameW == NULL)
5996 ERR ("Failed to allocate %i bytes from process heap\n",
5997 (LONG)(len * sizeof (WCHAR)));
5998 return ERROR_OUTOFMEMORY;
6001 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6003 ret = GetLastError ();
6004 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6005 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6006 WARN ("HeapFree failed with code %i\n", GetLastError ());
6010 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6011 pcbEnumValues, pnEnumValues);
6012 if (ret != ERROR_SUCCESS)
6014 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6015 WARN ("HeapFree failed with code %i\n", GetLastError ());
6016 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6020 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6022 ret = GetLastError ();
6023 ERR ("HeapFree failed with code %i\n", ret);
6027 if (*pnEnumValues == 0) /* empty key */
6028 return ERROR_SUCCESS;
6031 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6033 PPRINTER_ENUM_VALUESW ppev =
6034 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6036 if (dwBufSize < ppev->cbValueName)
6037 dwBufSize = ppev->cbValueName;
6039 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6040 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6041 dwBufSize = ppev->cbData;
6044 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6046 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6047 if (pBuffer == NULL)
6049 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6050 return ERROR_OUTOFMEMORY;
6053 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6055 PPRINTER_ENUM_VALUESW ppev =
6056 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6058 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6059 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6063 ret = GetLastError ();
6064 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6065 if (HeapFree (hHeap, 0, pBuffer) == 0)
6066 WARN ("HeapFree failed with code %i\n", GetLastError ());
6070 memcpy (ppev->pValueName, pBuffer, len);
6072 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6074 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6075 ppev->dwType != REG_MULTI_SZ)
6078 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6079 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6082 ret = GetLastError ();
6083 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6084 if (HeapFree (hHeap, 0, pBuffer) == 0)
6085 WARN ("HeapFree failed with code %i\n", GetLastError ());
6089 memcpy (ppev->pData, pBuffer, len);
6091 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6092 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6095 if (HeapFree (hHeap, 0, pBuffer) == 0)
6097 ret = GetLastError ();
6098 ERR ("HeapFree failed with code %i\n", ret);
6102 return ERROR_SUCCESS;
6105 /******************************************************************************
6106 * AbortPrinter (WINSPOOL.@)
6108 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6110 FIXME("(%p), stub!\n", hPrinter);
6114 /******************************************************************************
6115 * AddPortA (WINSPOOL.@)
6120 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6122 LPWSTR nameW = NULL;
6123 LPWSTR monitorW = NULL;
6127 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6130 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6131 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6132 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6136 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6137 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6138 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6140 res = AddPortW(nameW, hWnd, monitorW);
6141 HeapFree(GetProcessHeap(), 0, nameW);
6142 HeapFree(GetProcessHeap(), 0, monitorW);
6146 /******************************************************************************
6147 * AddPortW (WINSPOOL.@)
6149 * Add a Port for a specific Monitor
6152 * pName [I] Servername or NULL (local Computer)
6153 * hWnd [I] Handle to parent Window for the Dialog-Box
6154 * pMonitorName [I] Name of the Monitor that manage the Port
6161 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6163 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6165 if ((backend == NULL) && !load_backend()) return FALSE;
6167 if (!pMonitorName) {
6168 SetLastError(RPC_X_NULL_REF_POINTER);
6172 return backend->fpAddPort(pName, hWnd, pMonitorName);
6175 /******************************************************************************
6176 * AddPortExA (WINSPOOL.@)
6181 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6184 PORT_INFO_2A * pi2A;
6185 LPWSTR nameW = NULL;
6186 LPWSTR monitorW = NULL;
6190 pi2A = (PORT_INFO_2A *) pBuffer;
6192 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6193 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6195 if ((level < 1) || (level > 2)) {
6196 SetLastError(ERROR_INVALID_LEVEL);
6201 SetLastError(ERROR_INVALID_PARAMETER);
6206 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6207 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6208 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6212 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6213 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6214 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6217 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6219 if (pi2A->pPortName) {
6220 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6221 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6222 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6226 if (pi2A->pMonitorName) {
6227 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6228 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6229 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6232 if (pi2A->pDescription) {
6233 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6234 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6235 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6237 pi2W.fPortType = pi2A->fPortType;
6238 pi2W.Reserved = pi2A->Reserved;
6241 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6243 HeapFree(GetProcessHeap(), 0, nameW);
6244 HeapFree(GetProcessHeap(), 0, monitorW);
6245 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6246 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6247 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6252 /******************************************************************************
6253 * AddPortExW (WINSPOOL.@)
6255 * Add a Port for a specific Monitor, without presenting a user interface
6258 * pName [I] Servername or NULL (local Computer)
6259 * level [I] Structure-Level (1 or 2) for pBuffer
6260 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6261 * pMonitorName [I] Name of the Monitor that manage the Port
6268 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6272 pi2 = (PORT_INFO_2W *) pBuffer;
6274 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6275 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6276 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6277 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6279 if ((backend == NULL) && !load_backend()) return FALSE;
6281 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6282 SetLastError(ERROR_INVALID_PARAMETER);
6286 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6289 /******************************************************************************
6290 * AddPrinterConnectionA (WINSPOOL.@)
6292 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6294 FIXME("%s\n", debugstr_a(pName));
6298 /******************************************************************************
6299 * AddPrinterConnectionW (WINSPOOL.@)
6301 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6303 FIXME("%s\n", debugstr_w(pName));
6307 /******************************************************************************
6308 * AddPrinterDriverExW (WINSPOOL.@)
6310 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6313 * pName [I] Servername or NULL (local Computer)
6314 * level [I] Level for the supplied DRIVER_INFO_*W struct
6315 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6316 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6323 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6325 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6327 if ((backend == NULL) && !load_backend()) return FALSE;
6329 if (level < 2 || level == 5 || level == 7 || level > 8) {
6330 SetLastError(ERROR_INVALID_LEVEL);
6335 SetLastError(ERROR_INVALID_PARAMETER);
6339 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6342 /******************************************************************************
6343 * AddPrinterDriverExA (WINSPOOL.@)
6345 * See AddPrinterDriverExW.
6348 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6350 DRIVER_INFO_8A *diA;
6352 LPWSTR nameW = NULL;
6357 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6359 diA = (DRIVER_INFO_8A *) pDriverInfo;
6360 ZeroMemory(&diW, sizeof(diW));
6362 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6363 SetLastError(ERROR_INVALID_LEVEL);
6368 SetLastError(ERROR_INVALID_PARAMETER);
6372 /* convert servername to unicode */
6374 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6375 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6376 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6380 diW.cVersion = diA->cVersion;
6383 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6384 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6385 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6388 if (diA->pEnvironment) {
6389 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6390 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6391 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6394 if (diA->pDriverPath) {
6395 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6396 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6397 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6400 if (diA->pDataFile) {
6401 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6402 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6403 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6406 if (diA->pConfigFile) {
6407 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6408 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6409 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6412 if ((Level > 2) && diA->pDependentFiles) {
6413 lenA = multi_sz_lenA(diA->pDependentFiles);
6414 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6415 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6416 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6419 if ((Level > 2) && diA->pMonitorName) {
6420 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6421 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6422 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6425 if ((Level > 3) && diA->pDefaultDataType) {
6426 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6427 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6428 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6431 if ((Level > 3) && diA->pszzPreviousNames) {
6432 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6433 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6434 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6435 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6438 if ((Level > 5) && diA->pszMfgName) {
6439 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6440 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6441 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6444 if ((Level > 5) && diA->pszOEMUrl) {
6445 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6446 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6447 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6450 if ((Level > 5) && diA->pszHardwareID) {
6451 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6452 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6453 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6456 if ((Level > 5) && diA->pszProvider) {
6457 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6458 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6459 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6463 FIXME("level %u is incomplete\n", Level);
6466 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6467 TRACE("got %u with %u\n", res, GetLastError());
6468 HeapFree(GetProcessHeap(), 0, nameW);
6469 HeapFree(GetProcessHeap(), 0, diW.pName);
6470 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6471 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6472 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6473 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6474 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6475 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6476 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6477 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6478 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6479 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6480 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6481 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6483 TRACE("=> %u with %u\n", res, GetLastError());
6487 /******************************************************************************
6488 * ConfigurePortA (WINSPOOL.@)
6490 * See ConfigurePortW.
6493 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6495 LPWSTR nameW = NULL;
6496 LPWSTR portW = NULL;
6500 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6502 /* convert servername to unicode */
6504 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6505 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6506 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6509 /* convert portname to unicode */
6511 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6512 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6513 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6516 res = ConfigurePortW(nameW, hWnd, portW);
6517 HeapFree(GetProcessHeap(), 0, nameW);
6518 HeapFree(GetProcessHeap(), 0, portW);
6522 /******************************************************************************
6523 * ConfigurePortW (WINSPOOL.@)
6525 * Display the Configuration-Dialog for a specific Port
6528 * pName [I] Servername or NULL (local Computer)
6529 * hWnd [I] Handle to parent Window for the Dialog-Box
6530 * pPortName [I] Name of the Port, that should be configured
6537 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6540 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6542 if ((backend == NULL) && !load_backend()) return FALSE;
6545 SetLastError(RPC_X_NULL_REF_POINTER);
6549 return backend->fpConfigurePort(pName, hWnd, pPortName);
6552 /******************************************************************************
6553 * ConnectToPrinterDlg (WINSPOOL.@)
6555 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6557 FIXME("%p %x\n", hWnd, Flags);
6561 /******************************************************************************
6562 * DeletePrinterConnectionA (WINSPOOL.@)
6564 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6566 FIXME("%s\n", debugstr_a(pName));
6570 /******************************************************************************
6571 * DeletePrinterConnectionW (WINSPOOL.@)
6573 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6575 FIXME("%s\n", debugstr_w(pName));
6579 /******************************************************************************
6580 * DeletePrinterDriverExW (WINSPOOL.@)
6582 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6583 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6588 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6589 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6591 if(pName && pName[0])
6593 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6594 SetLastError(ERROR_INVALID_PARAMETER);
6600 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6601 SetLastError(ERROR_INVALID_PARAMETER);
6605 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6609 ERR("Can't open drivers key\n");
6613 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6616 RegCloseKey(hkey_drivers);
6621 /******************************************************************************
6622 * DeletePrinterDriverExA (WINSPOOL.@)
6624 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6625 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6627 UNICODE_STRING NameW, EnvW, DriverW;
6630 asciitounicode(&NameW, pName);
6631 asciitounicode(&EnvW, pEnvironment);
6632 asciitounicode(&DriverW, pDriverName);
6634 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6636 RtlFreeUnicodeString(&DriverW);
6637 RtlFreeUnicodeString(&EnvW);
6638 RtlFreeUnicodeString(&NameW);
6643 /******************************************************************************
6644 * DeletePrinterDataExW (WINSPOOL.@)
6646 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6649 FIXME("%p %s %s\n", hPrinter,
6650 debugstr_w(pKeyName), debugstr_w(pValueName));
6651 return ERROR_INVALID_PARAMETER;
6654 /******************************************************************************
6655 * DeletePrinterDataExA (WINSPOOL.@)
6657 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6660 FIXME("%p %s %s\n", hPrinter,
6661 debugstr_a(pKeyName), debugstr_a(pValueName));
6662 return ERROR_INVALID_PARAMETER;
6665 /******************************************************************************
6666 * DeletePrintProcessorA (WINSPOOL.@)
6668 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6670 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6671 debugstr_a(pPrintProcessorName));
6675 /******************************************************************************
6676 * DeletePrintProcessorW (WINSPOOL.@)
6678 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6680 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6681 debugstr_w(pPrintProcessorName));
6685 /******************************************************************************
6686 * DeletePrintProvidorA (WINSPOOL.@)
6688 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6690 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6691 debugstr_a(pPrintProviderName));
6695 /******************************************************************************
6696 * DeletePrintProvidorW (WINSPOOL.@)
6698 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6700 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6701 debugstr_w(pPrintProviderName));
6705 /******************************************************************************
6706 * EnumFormsA (WINSPOOL.@)
6708 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6709 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6711 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6712 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6716 /******************************************************************************
6717 * EnumFormsW (WINSPOOL.@)
6719 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6720 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6722 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6723 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6727 /*****************************************************************************
6728 * EnumMonitorsA [WINSPOOL.@]
6730 * See EnumMonitorsW.
6733 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6734 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6737 LPBYTE bufferW = NULL;
6738 LPWSTR nameW = NULL;
6740 DWORD numentries = 0;
6743 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6744 cbBuf, pcbNeeded, pcReturned);
6746 /* convert servername to unicode */
6748 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6749 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6750 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6752 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6753 needed = cbBuf * sizeof(WCHAR);
6754 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6755 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6757 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6758 if (pcbNeeded) needed = *pcbNeeded;
6759 /* HeapReAlloc return NULL, when bufferW was NULL */
6760 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6761 HeapAlloc(GetProcessHeap(), 0, needed);
6763 /* Try again with the large Buffer */
6764 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6766 numentries = pcReturned ? *pcReturned : 0;
6769 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6770 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6773 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6774 DWORD entrysize = 0;
6777 LPMONITOR_INFO_2W mi2w;
6778 LPMONITOR_INFO_2A mi2a;
6780 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6781 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6783 /* First pass: calculate the size for all Entries */
6784 mi2w = (LPMONITOR_INFO_2W) bufferW;
6785 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6787 while (index < numentries) {
6789 needed += entrysize; /* MONITOR_INFO_?A */
6790 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6792 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6793 NULL, 0, NULL, NULL);
6795 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6796 NULL, 0, NULL, NULL);
6797 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6798 NULL, 0, NULL, NULL);
6800 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6801 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6802 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6805 /* check for errors and quit on failure */
6806 if (cbBuf < needed) {
6807 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6811 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6812 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6813 cbBuf -= len ; /* free Bytes in the user-Buffer */
6814 mi2w = (LPMONITOR_INFO_2W) bufferW;
6815 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6817 /* Second Pass: Fill the User Buffer (if we have one) */
6818 while ((index < numentries) && pMonitors) {
6820 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6822 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6823 ptr, cbBuf , NULL, NULL);
6827 mi2a->pEnvironment = ptr;
6828 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6829 ptr, cbBuf, NULL, NULL);
6833 mi2a->pDLLName = ptr;
6834 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6835 ptr, cbBuf, NULL, NULL);
6839 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6840 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6841 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6845 if (pcbNeeded) *pcbNeeded = needed;
6846 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6848 HeapFree(GetProcessHeap(), 0, nameW);
6849 HeapFree(GetProcessHeap(), 0, bufferW);
6851 TRACE("returning %d with %d (%d byte for %d entries)\n",
6852 (res), GetLastError(), needed, numentries);
6858 /*****************************************************************************
6859 * EnumMonitorsW [WINSPOOL.@]
6861 * Enumerate available Port-Monitors
6864 * pName [I] Servername or NULL (local Computer)
6865 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6866 * pMonitors [O] PTR to Buffer that receives the Result
6867 * cbBuf [I] Size of Buffer at pMonitors
6868 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6869 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6873 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6876 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6877 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6880 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6881 cbBuf, pcbNeeded, pcReturned);
6883 if ((backend == NULL) && !load_backend()) return FALSE;
6885 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6886 SetLastError(RPC_X_NULL_REF_POINTER);
6890 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6893 /******************************************************************************
6894 * SpoolerInit (WINSPOOL.@)
6896 * Initialize the Spooler
6903 * The function fails on windows, when the spooler service is not running
6906 BOOL WINAPI SpoolerInit(void)
6909 if ((backend == NULL) && !load_backend()) return FALSE;
6913 /******************************************************************************
6914 * XcvDataW (WINSPOOL.@)
6916 * Execute commands in the Printmonitor DLL
6919 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6920 * pszDataName [i] Name of the command to execute
6921 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6922 * cbInputData [i] Size in Bytes of Buffer at pInputData
6923 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6924 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6925 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6926 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6933 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6934 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6936 * Minimal List of commands, that a Printmonitor DLL should support:
6938 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6939 *| "AddPort" : Add a Port
6940 *| "DeletePort": Delete a Port
6942 * Many Printmonitors support additional commands. Examples for localspl.dll:
6943 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6944 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6947 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6948 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6949 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6951 opened_printer_t *printer;
6953 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6954 pInputData, cbInputData, pOutputData,
6955 cbOutputData, pcbOutputNeeded, pdwStatus);
6957 if ((backend == NULL) && !load_backend()) return FALSE;
6959 printer = get_opened_printer(hXcv);
6960 if (!printer || (!printer->backend_printer)) {
6961 SetLastError(ERROR_INVALID_HANDLE);
6965 if (!pcbOutputNeeded) {
6966 SetLastError(ERROR_INVALID_PARAMETER);
6970 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6971 SetLastError(RPC_X_NULL_REF_POINTER);
6975 *pcbOutputNeeded = 0;
6977 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6978 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6982 /*****************************************************************************
6983 * EnumPrinterDataA [WINSPOOL.@]
6986 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6987 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6988 DWORD cbData, LPDWORD pcbData )
6990 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6991 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6992 return ERROR_NO_MORE_ITEMS;
6995 /*****************************************************************************
6996 * EnumPrinterDataW [WINSPOOL.@]
6999 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7000 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7001 DWORD cbData, LPDWORD pcbData )
7003 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7004 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7005 return ERROR_NO_MORE_ITEMS;
7008 /*****************************************************************************
7009 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7012 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7013 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7014 LPDWORD pcbNeeded, LPDWORD pcReturned)
7016 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7017 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7018 pcbNeeded, pcReturned);
7022 /*****************************************************************************
7023 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7026 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7027 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7028 LPDWORD pcbNeeded, LPDWORD pcReturned)
7030 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7031 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7032 pcbNeeded, pcReturned);
7036 /*****************************************************************************
7037 * EnumPrintProcessorsA [WINSPOOL.@]
7039 * See EnumPrintProcessorsW.
7042 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7043 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7046 LPBYTE bufferW = NULL;
7047 LPWSTR nameW = NULL;
7050 DWORD numentries = 0;
7053 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7054 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7056 /* convert names to unicode */
7058 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7059 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7060 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7063 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7064 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7065 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7068 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7069 needed = cbBuf * sizeof(WCHAR);
7070 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7071 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7073 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7074 if (pcbNeeded) needed = *pcbNeeded;
7075 /* HeapReAlloc return NULL, when bufferW was NULL */
7076 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7077 HeapAlloc(GetProcessHeap(), 0, needed);
7079 /* Try again with the large Buffer */
7080 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7082 numentries = pcReturned ? *pcReturned : 0;
7086 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7089 PPRINTPROCESSOR_INFO_1W ppiw;
7090 PPRINTPROCESSOR_INFO_1A ppia;
7092 /* First pass: calculate the size for all Entries */
7093 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7094 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7096 while (index < numentries) {
7098 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7099 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7101 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7102 NULL, 0, NULL, NULL);
7104 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7105 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7108 /* check for errors and quit on failure */
7109 if (cbBuf < needed) {
7110 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7115 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7116 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7117 cbBuf -= len ; /* free Bytes in the user-Buffer */
7118 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7119 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7121 /* Second Pass: Fill the User Buffer (if we have one) */
7122 while ((index < numentries) && pPPInfo) {
7124 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7126 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7127 ptr, cbBuf , NULL, NULL);
7131 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7132 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7137 if (pcbNeeded) *pcbNeeded = needed;
7138 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7140 HeapFree(GetProcessHeap(), 0, nameW);
7141 HeapFree(GetProcessHeap(), 0, envW);
7142 HeapFree(GetProcessHeap(), 0, bufferW);
7144 TRACE("returning %d with %d (%d byte for %d entries)\n",
7145 (res), GetLastError(), needed, numentries);
7150 /*****************************************************************************
7151 * EnumPrintProcessorsW [WINSPOOL.@]
7153 * Enumerate available Print Processors
7156 * pName [I] Servername or NULL (local Computer)
7157 * pEnvironment [I] Printing-Environment or NULL (Default)
7158 * Level [I] Structure-Level (Only 1 is allowed)
7159 * pPPInfo [O] PTR to Buffer that receives the Result
7160 * cbBuf [I] Size of Buffer at pPPInfo
7161 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7162 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7166 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7169 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7170 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7173 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7174 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7176 if ((backend == NULL) && !load_backend()) return FALSE;
7178 if (!pcbNeeded || !pcReturned) {
7179 SetLastError(RPC_X_NULL_REF_POINTER);
7183 if (!pPPInfo && (cbBuf > 0)) {
7184 SetLastError(ERROR_INVALID_USER_BUFFER);
7188 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7189 cbBuf, pcbNeeded, pcReturned);
7192 /*****************************************************************************
7193 * ExtDeviceMode [WINSPOOL.@]
7196 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7197 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7200 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7201 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7202 debugstr_a(pProfile), fMode);
7206 /*****************************************************************************
7207 * FindClosePrinterChangeNotification [WINSPOOL.@]
7210 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7212 FIXME("Stub: %p\n", hChange);
7216 /*****************************************************************************
7217 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7220 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7221 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7223 FIXME("Stub: %p %x %x %p\n",
7224 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7225 return INVALID_HANDLE_VALUE;
7228 /*****************************************************************************
7229 * FindNextPrinterChangeNotification [WINSPOOL.@]
7232 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7233 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7235 FIXME("Stub: %p %p %p %p\n",
7236 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7240 /*****************************************************************************
7241 * FreePrinterNotifyInfo [WINSPOOL.@]
7244 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7246 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7250 /*****************************************************************************
7253 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7254 * ansi depending on the unicode parameter.
7256 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7266 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7269 memcpy(ptr, str, *size);
7276 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7279 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7286 /*****************************************************************************
7289 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7290 LPDWORD pcbNeeded, BOOL unicode)
7292 DWORD size, left = cbBuf;
7293 BOOL space = (cbBuf > 0);
7300 ji1->JobId = job->job_id;
7303 string_to_buf(job->document_title, ptr, left, &size, unicode);
7304 if(space && size <= left)
7306 ji1->pDocument = (LPWSTR)ptr;
7314 if (job->printer_name)
7316 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7317 if(space && size <= left)
7319 ji1->pPrinterName = (LPWSTR)ptr;
7331 /*****************************************************************************
7334 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7335 LPDWORD pcbNeeded, BOOL unicode)
7337 DWORD size, left = cbBuf;
7339 BOOL space = (cbBuf > 0);
7341 LPDEVMODEA dmA = NULL;
7348 ji2->JobId = job->job_id;
7351 string_to_buf(job->document_title, ptr, left, &size, unicode);
7352 if(space && size <= left)
7354 ji2->pDocument = (LPWSTR)ptr;
7362 if (job->printer_name)
7364 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7365 if(space && size <= left)
7367 ji2->pPrinterName = (LPWSTR)ptr;
7380 dmA = DEVMODEdupWtoA(job->devmode);
7381 devmode = (LPDEVMODEW) dmA;
7382 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7386 devmode = job->devmode;
7387 size = devmode->dmSize + devmode->dmDriverExtra;
7391 FIXME("Can't convert DEVMODE W to A\n");
7394 /* align DEVMODE to a DWORD boundary */
7395 shift = (4 - (*pcbNeeded & 3)) & 3;
7401 memcpy(ptr, devmode, size-shift);
7402 ji2->pDevMode = (LPDEVMODEW)ptr;
7403 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7416 /*****************************************************************************
7419 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7420 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7423 DWORD needed = 0, size;
7427 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7429 EnterCriticalSection(&printer_handles_cs);
7430 job = get_job(hPrinter, JobId);
7437 size = sizeof(JOB_INFO_1W);
7442 memset(pJob, 0, size);
7446 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7451 size = sizeof(JOB_INFO_2W);
7456 memset(pJob, 0, size);
7460 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7465 size = sizeof(JOB_INFO_3);
7469 memset(pJob, 0, size);
7478 SetLastError(ERROR_INVALID_LEVEL);
7482 *pcbNeeded = needed;
7484 LeaveCriticalSection(&printer_handles_cs);
7488 /*****************************************************************************
7489 * GetJobA [WINSPOOL.@]
7492 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7493 DWORD cbBuf, LPDWORD pcbNeeded)
7495 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7498 /*****************************************************************************
7499 * GetJobW [WINSPOOL.@]
7502 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7503 DWORD cbBuf, LPDWORD pcbNeeded)
7505 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7508 /*****************************************************************************
7511 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7514 char *unixname, *cmdA;
7516 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7522 if(!(unixname = wine_get_unix_file_name(filename)))
7525 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7526 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7527 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7529 TRACE("printing with: %s\n", cmdA);
7531 if((file_fd = open(unixname, O_RDONLY)) == -1)
7536 ERR("pipe() failed!\n");
7540 if ((pid = fork()) == 0)
7546 /* reset signals that we previously set to SIG_IGN */
7547 signal(SIGPIPE, SIG_DFL);
7549 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7554 ERR("fork() failed!\n");
7558 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7559 write(fds[1], buf, no_read);
7566 wret = waitpid(pid, &status, 0);
7567 } while (wret < 0 && errno == EINTR);
7570 ERR("waitpid() failed!\n");
7573 if (!WIFEXITED(status) || WEXITSTATUS(status))
7575 ERR("child process failed! %d\n", status);
7582 if(file_fd != -1) close(file_fd);
7583 if(fds[0] != -1) close(fds[0]);
7584 if(fds[1] != -1) close(fds[1]);
7586 HeapFree(GetProcessHeap(), 0, cmdA);
7587 HeapFree(GetProcessHeap(), 0, unixname);
7594 /*****************************************************************************
7597 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7600 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7603 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7604 sprintfW(cmd, fmtW, printer_name);
7606 r = schedule_pipe(cmd, filename);
7608 HeapFree(GetProcessHeap(), 0, cmd);
7612 #ifdef SONAME_LIBCUPS
7613 /*****************************************************************************
7614 * get_cups_jobs_ticket_options
7616 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7617 * The CUPS scheduler only looks for these in Print-File requests, and since
7618 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7621 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7623 FILE *fp = fopen( file, "r" );
7624 char buf[257]; /* DSC max of 256 + '\0' */
7625 const char *ps_adobe = "%!PS-Adobe-";
7626 const char *cups_job = "%cupsJobTicket:";
7628 if (!fp) return num_options;
7629 if (!fgets( buf, sizeof(buf), fp )) goto end;
7630 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7631 while (fgets( buf, sizeof(buf), fp ))
7633 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7634 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7643 /*****************************************************************************
7646 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7648 #ifdef SONAME_LIBCUPS
7651 char *unixname, *queue, *unix_doc_title;
7654 int num_options = 0, i;
7655 cups_option_t *options = NULL;
7657 if(!(unixname = wine_get_unix_file_name(filename)))
7660 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7661 queue = HeapAlloc(GetProcessHeap(), 0, len);
7662 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7664 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7665 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7666 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7668 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7670 TRACE( "printing via cups with options:\n" );
7671 for (i = 0; i < num_options; i++)
7672 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7674 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7676 pcupsFreeOptions( num_options, options );
7678 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7679 HeapFree(GetProcessHeap(), 0, queue);
7680 HeapFree(GetProcessHeap(), 0, unixname);
7686 return schedule_lpr(printer_name, filename);
7690 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7697 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7701 if(HIWORD(wparam) == BN_CLICKED)
7703 if(LOWORD(wparam) == IDOK)
7706 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7709 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7710 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7712 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7714 WCHAR caption[200], message[200];
7717 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7718 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7719 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7720 if(mb_ret == IDCANCEL)
7722 HeapFree(GetProcessHeap(), 0, filename);
7726 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7727 if(hf == INVALID_HANDLE_VALUE)
7729 WCHAR caption[200], message[200];
7731 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7732 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7733 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7734 HeapFree(GetProcessHeap(), 0, filename);
7738 DeleteFileW(filename);
7739 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7741 EndDialog(hwnd, IDOK);
7744 if(LOWORD(wparam) == IDCANCEL)
7746 EndDialog(hwnd, IDCANCEL);
7755 /*****************************************************************************
7758 static BOOL get_filename(LPWSTR *filename)
7760 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7761 file_dlg_proc, (LPARAM)filename) == IDOK;
7764 /*****************************************************************************
7767 static BOOL schedule_file(LPCWSTR filename)
7769 LPWSTR output = NULL;
7771 if(get_filename(&output))
7774 TRACE("copy to %s\n", debugstr_w(output));
7775 r = CopyFileW(filename, output, FALSE);
7776 HeapFree(GetProcessHeap(), 0, output);
7782 /*****************************************************************************
7785 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7787 int in_fd, out_fd, no_read;
7790 char *unixname, *outputA;
7793 if(!(unixname = wine_get_unix_file_name(filename)))
7796 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7797 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7798 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7800 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7801 in_fd = open(unixname, O_RDONLY);
7802 if(out_fd == -1 || in_fd == -1)
7805 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7806 write(out_fd, buf, no_read);
7810 if(in_fd != -1) close(in_fd);
7811 if(out_fd != -1) close(out_fd);
7812 HeapFree(GetProcessHeap(), 0, outputA);
7813 HeapFree(GetProcessHeap(), 0, unixname);
7817 /*****************************************************************************
7818 * ScheduleJob [WINSPOOL.@]
7821 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7823 opened_printer_t *printer;
7825 struct list *cursor, *cursor2;
7827 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7828 EnterCriticalSection(&printer_handles_cs);
7829 printer = get_opened_printer(hPrinter);
7833 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7835 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7838 if(job->job_id != dwJobID) continue;
7840 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7841 if(hf != INVALID_HANDLE_VALUE)
7843 PRINTER_INFO_5W *pi5 = NULL;
7844 LPWSTR portname = job->portname;
7848 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7849 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7853 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7854 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7855 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7856 portname = pi5->pPortName;
7858 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7859 debugstr_w(portname));
7863 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7864 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7866 DWORD type, count = sizeof(output);
7867 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7870 if(output[0] == '|')
7872 ret = schedule_pipe(output + 1, job->filename);
7876 ret = schedule_unixfile(output, job->filename);
7878 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7880 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7882 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7884 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7886 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7888 ret = schedule_file(job->filename);
7892 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7894 HeapFree(GetProcessHeap(), 0, pi5);
7896 DeleteFileW(job->filename);
7898 list_remove(cursor);
7899 HeapFree(GetProcessHeap(), 0, job->document_title);
7900 HeapFree(GetProcessHeap(), 0, job->printer_name);
7901 HeapFree(GetProcessHeap(), 0, job->portname);
7902 HeapFree(GetProcessHeap(), 0, job->filename);
7903 HeapFree(GetProcessHeap(), 0, job->devmode);
7904 HeapFree(GetProcessHeap(), 0, job);
7908 LeaveCriticalSection(&printer_handles_cs);
7912 /*****************************************************************************
7913 * StartDocDlgA [WINSPOOL.@]
7915 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7917 UNICODE_STRING usBuffer;
7920 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7923 docW.cbSize = sizeof(docW);
7924 if (doc->lpszDocName)
7926 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7927 if (!(docW.lpszDocName = docnameW)) return NULL;
7929 if (doc->lpszOutput)
7931 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7932 if (!(docW.lpszOutput = outputW)) return NULL;
7934 if (doc->lpszDatatype)
7936 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7937 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7939 docW.fwType = doc->fwType;
7941 retW = StartDocDlgW(hPrinter, &docW);
7945 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7946 ret = HeapAlloc(GetProcessHeap(), 0, len);
7947 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7948 HeapFree(GetProcessHeap(), 0, retW);
7951 HeapFree(GetProcessHeap(), 0, datatypeW);
7952 HeapFree(GetProcessHeap(), 0, outputW);
7953 HeapFree(GetProcessHeap(), 0, docnameW);
7958 /*****************************************************************************
7959 * StartDocDlgW [WINSPOOL.@]
7961 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7962 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7963 * port is "FILE:". Also returns the full path if passed a relative path.
7965 * The caller should free the returned string from the process heap.
7967 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7972 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7974 PRINTER_INFO_5W *pi5;
7975 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7976 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7978 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7979 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7980 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7982 HeapFree(GetProcessHeap(), 0, pi5);
7985 HeapFree(GetProcessHeap(), 0, pi5);
7988 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7992 if (get_filename(&name))
7994 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7996 HeapFree(GetProcessHeap(), 0, name);
7999 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8000 GetFullPathNameW(name, len, ret, NULL);
8001 HeapFree(GetProcessHeap(), 0, name);
8006 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8009 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8010 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8012 attr = GetFileAttributesW(ret);
8013 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8015 HeapFree(GetProcessHeap(), 0, ret);