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];
497 HANDLE added_printer;
499 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
501 TRACE("%s\n", loaderror);
504 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
506 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
510 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
512 ERR("Can't create Printers key\n");
516 nrofdests = pcupsGetDests(&dests);
517 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
518 for (i=0;i<nrofdests;i++) {
519 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
521 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
522 lstrcpyW(port, CUPS_Port);
523 lstrcatW(port, nameW);
525 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
526 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
527 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
529 TRACE("Printer already exists\n");
530 /* overwrite old LPR:* port */
531 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
532 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
533 RegCloseKey(hkeyPrinter);
535 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
536 ' ','u','s','i','n','g',' ','C','U','P','S',0};
538 add_printer_driver(nameW);
540 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
541 pi2.pPrinterName = nameW;
542 pi2.pDatatype = rawW;
543 pi2.pPrintProcessor = WinPrintW;
544 pi2.pDriverName = nameW;
545 pi2.pComment = comment_cups;
546 pi2.pLocation = emptyStringW;
547 pi2.pPortName = port;
548 pi2.pParameters = emptyStringW;
549 pi2.pShareName = emptyStringW;
550 pi2.pSepFile = emptyStringW;
552 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
553 if (added_printer) ClosePrinter( added_printer );
554 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
555 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
557 HeapFree(GetProcessHeap(),0,port);
560 if (dests[i].is_default) {
561 SetDefaultPrinterW(nameW);
565 if (hadprinter && !haddefault) {
566 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
567 SetDefaultPrinterW(nameW);
569 pcupsFreeDests(nrofdests, dests);
570 RegCloseKey(hkeyPrinters);
575 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
577 PRINTER_INFO_2A pinfo2a;
580 char *e,*s,*name,*prettyname,*devname;
581 BOOL ret = FALSE, set_default = FALSE;
582 char *port = NULL, *env_default;
583 HKEY hkeyPrinter, hkeyPrinters;
584 WCHAR devnameW[MAX_PATH];
585 HANDLE added_printer;
587 while (isspace(*pent)) pent++;
588 r = strchr(pent,':');
592 name_len = strlen(pent);
593 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
594 memcpy(name, pent, name_len);
595 name[name_len] = '\0';
601 TRACE("name=%s entry=%s\n",name, pent);
603 if(ispunct(*name)) { /* a tc entry, not a real printer */
604 TRACE("skipping tc entry\n");
608 if(strstr(pent,":server")) { /* server only version so skip */
609 TRACE("skipping server entry\n");
613 /* Determine whether this is a postscript printer. */
616 env_default = getenv("PRINTER");
618 /* Get longest name, usually the one at the right for later display. */
619 while((s=strchr(prettyname,'|'))) {
622 while(isspace(*--e)) *e = '\0';
623 TRACE("\t%s\n", debugstr_a(prettyname));
624 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
625 for(prettyname = s+1; isspace(*prettyname); prettyname++)
628 e = prettyname + strlen(prettyname);
629 while(isspace(*--e)) *e = '\0';
630 TRACE("\t%s\n", debugstr_a(prettyname));
631 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
633 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
634 * if it is too long, we use it as comment below. */
635 devname = prettyname;
636 if (strlen(devname)>=CCHDEVICENAME-1)
638 if (strlen(devname)>=CCHDEVICENAME-1) {
643 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
644 sprintf(port,"LPR:%s",name);
646 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
648 ERR("Can't create Printers key\n");
653 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
655 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
656 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
658 TRACE("Printer already exists\n");
659 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
660 RegCloseKey(hkeyPrinter);
662 static CHAR data_type[] = "RAW",
663 print_proc[] = "WinPrint",
664 comment[] = "WINEPS Printer using LPR",
665 params[] = "<parameters?>",
666 share_name[] = "<share name?>",
667 sep_file[] = "<sep file?>";
669 add_printer_driver(devnameW);
671 memset(&pinfo2a,0,sizeof(pinfo2a));
672 pinfo2a.pPrinterName = devname;
673 pinfo2a.pDatatype = data_type;
674 pinfo2a.pPrintProcessor = print_proc;
675 pinfo2a.pDriverName = devname;
676 pinfo2a.pComment = comment;
677 pinfo2a.pLocation = prettyname;
678 pinfo2a.pPortName = port;
679 pinfo2a.pParameters = params;
680 pinfo2a.pShareName = share_name;
681 pinfo2a.pSepFile = sep_file;
683 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
684 if (added_printer) ClosePrinter( added_printer );
685 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
686 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
688 RegCloseKey(hkeyPrinters);
690 if (isfirst || set_default)
691 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
694 HeapFree(GetProcessHeap(), 0, port);
695 HeapFree(GetProcessHeap(), 0, name);
700 PRINTCAP_LoadPrinters(void) {
701 BOOL hadprinter = FALSE;
705 BOOL had_bash = FALSE;
707 f = fopen("/etc/printcap","r");
711 while(fgets(buf,sizeof(buf),f)) {
714 end=strchr(buf,'\n');
718 while(isspace(*start)) start++;
719 if(*start == '#' || *start == '\0')
722 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
723 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
724 HeapFree(GetProcessHeap(),0,pent);
728 if (end && *--end == '\\') {
735 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
738 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
744 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
745 HeapFree(GetProcessHeap(),0,pent);
751 static inline DWORD set_reg_DWORD(HKEY hkey, LPCSTR keyname, const DWORD value)
753 return RegSetValueExA(hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
756 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
759 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
760 (lstrlenW(value) + 1) * sizeof(WCHAR));
762 return ERROR_FILE_NOT_FOUND;
765 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
767 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
768 DWORD ret = ERROR_FILE_NOT_FOUND;
770 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
771 and we support these drivers. NT writes DEVMODEW so somehow
772 we'll need to distinguish between these when we support NT
777 ret = RegSetValueExW( key, name, 0, REG_BINARY,
778 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
779 HeapFree( GetProcessHeap(), 0, dmA );
785 /******************************************************************
786 * get_servername_from_name (internal)
788 * for an external server, a copy of the serverpart from the full name is returned
791 static LPWSTR get_servername_from_name(LPCWSTR name)
795 WCHAR buffer[MAX_PATH];
798 if (name == NULL) return NULL;
799 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
801 server = strdupW(&name[2]); /* skip over both backslash */
802 if (server == NULL) return NULL;
804 /* strip '\' and the printername */
805 ptr = strchrW(server, '\\');
806 if (ptr) ptr[0] = '\0';
808 TRACE("found %s\n", debugstr_w(server));
810 len = sizeof(buffer)/sizeof(buffer[0]);
811 if (GetComputerNameW(buffer, &len)) {
812 if (lstrcmpW(buffer, server) == 0) {
813 /* The requested Servername is our computername */
814 HeapFree(GetProcessHeap(), 0, server);
821 /******************************************************************
822 * get_basename_from_name (internal)
824 * skip over the serverpart from the full name
827 static LPCWSTR get_basename_from_name(LPCWSTR name)
829 if (name == NULL) return NULL;
830 if ((name[0] == '\\') && (name[1] == '\\')) {
831 /* skip over the servername and search for the following '\' */
832 name = strchrW(&name[2], '\\');
833 if ((name) && (name[1])) {
834 /* found a separator ('\') followed by a name:
835 skip over the separator and return the rest */
840 /* no basename present (we found only a servername) */
847 static void free_printer_entry( opened_printer_t *printer )
849 /* the queue is shared, so don't free that here */
850 HeapFree( GetProcessHeap(), 0, printer->printername );
851 HeapFree( GetProcessHeap(), 0, printer->name );
852 HeapFree( GetProcessHeap(), 0, printer->devmode );
853 HeapFree( GetProcessHeap(), 0, printer );
856 /******************************************************************
857 * get_opened_printer_entry
858 * Get the first place empty in the opened printer table
861 * - pDefault is ignored
863 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
865 UINT_PTR handle = nb_printer_handles, i;
866 jobqueue_t *queue = NULL;
867 opened_printer_t *printer = NULL;
871 if ((backend == NULL) && !load_backend()) return NULL;
873 servername = get_servername_from_name(name);
875 FIXME("server %s not supported\n", debugstr_w(servername));
876 HeapFree(GetProcessHeap(), 0, servername);
877 SetLastError(ERROR_INVALID_PRINTER_NAME);
881 printername = get_basename_from_name(name);
882 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
884 /* an empty printername is invalid */
885 if (printername && (!printername[0])) {
886 SetLastError(ERROR_INVALID_PARAMETER);
890 EnterCriticalSection(&printer_handles_cs);
892 for (i = 0; i < nb_printer_handles; i++)
894 if (!printer_handles[i])
896 if(handle == nb_printer_handles)
901 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
902 queue = printer_handles[i]->queue;
906 if (handle >= nb_printer_handles)
908 opened_printer_t **new_array;
910 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
911 (nb_printer_handles + 16) * sizeof(*new_array) );
913 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
914 (nb_printer_handles + 16) * sizeof(*new_array) );
921 printer_handles = new_array;
922 nb_printer_handles += 16;
925 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
931 /* get a printer handle from the backend */
932 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
937 /* clone the base name. This is NULL for the printserver */
938 printer->printername = strdupW(printername);
940 /* clone the full name */
941 printer->name = strdupW(name);
942 if (name && (!printer->name)) {
947 if (pDefault && pDefault->pDevMode)
948 printer->devmode = dup_devmode( pDefault->pDevMode );
951 printer->queue = queue;
954 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
955 if (!printer->queue) {
959 list_init(&printer->queue->jobs);
960 printer->queue->ref = 0;
962 InterlockedIncrement(&printer->queue->ref);
964 printer_handles[handle] = printer;
967 LeaveCriticalSection(&printer_handles_cs);
968 if (!handle && printer) {
969 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
970 free_printer_entry( printer );
973 return (HANDLE)handle;
976 /******************************************************************
978 * Get the pointer to the opened printer referred by the handle
980 static opened_printer_t *get_opened_printer(HANDLE hprn)
982 UINT_PTR idx = (UINT_PTR)hprn;
983 opened_printer_t *ret = NULL;
985 EnterCriticalSection(&printer_handles_cs);
987 if ((idx > 0) && (idx <= nb_printer_handles)) {
988 ret = printer_handles[idx - 1];
990 LeaveCriticalSection(&printer_handles_cs);
994 /******************************************************************
995 * get_opened_printer_name
996 * Get the pointer to the opened printer name referred by the handle
998 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1000 opened_printer_t *printer = get_opened_printer(hprn);
1001 if(!printer) return NULL;
1002 return printer->name;
1005 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1011 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1012 if (err) return err;
1014 err = RegOpenKeyW( printers, name, key );
1015 if (err) err = ERROR_INVALID_PRINTER_NAME;
1016 RegCloseKey( printers );
1020 /******************************************************************
1021 * WINSPOOL_GetOpenedPrinterRegKey
1024 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1026 LPCWSTR name = get_opened_printer_name(hPrinter);
1028 if(!name) return ERROR_INVALID_HANDLE;
1029 return open_printer_reg_key( name, phkey );
1032 static void old_printer_check( BOOL delete_phase )
1034 PRINTER_INFO_5W* pi;
1035 DWORD needed, type, num, delete, i, size;
1036 const DWORD one = 1;
1040 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1041 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1043 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1044 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1045 for (i = 0; i < num; i++)
1047 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1048 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1051 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1055 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1061 size = sizeof( delete );
1062 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1066 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1067 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1069 DeletePrinter( hprn );
1070 ClosePrinter( hprn );
1072 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1076 HeapFree(GetProcessHeap(), 0, pi);
1079 void WINSPOOL_LoadSystemPrinters(void)
1081 HKEY hkey, hkeyPrinters;
1082 DWORD needed, num, i;
1083 WCHAR PrinterName[256];
1086 /* This ensures that all printer entries have a valid Name value. If causes
1087 problems later if they don't. If one is found to be missed we create one
1088 and set it equal to the name of the key */
1089 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1090 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1091 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1092 for(i = 0; i < num; i++) {
1093 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1094 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1095 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1096 set_reg_szW(hkey, NameW, PrinterName);
1103 RegCloseKey(hkeyPrinters);
1106 old_printer_check( FALSE );
1108 #ifdef SONAME_LIBCUPS
1109 done = CUPS_LoadPrinters();
1112 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1113 PRINTCAP_LoadPrinters();
1115 old_printer_check( TRUE );
1120 /******************************************************************
1123 * Get the pointer to the specified job.
1124 * Should hold the printer_handles_cs before calling.
1126 static job_t *get_job(HANDLE hprn, DWORD JobId)
1128 opened_printer_t *printer = get_opened_printer(hprn);
1131 if(!printer) return NULL;
1132 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1134 if(job->job_id == JobId)
1140 /***********************************************************
1143 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1146 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1149 Formname = (dmA->dmSize > off_formname);
1150 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1151 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1152 dmW->dmDeviceName, CCHDEVICENAME);
1154 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1155 dmA->dmSize - CCHDEVICENAME);
1157 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1158 off_formname - CCHDEVICENAME);
1159 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1160 dmW->dmFormName, CCHFORMNAME);
1161 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1162 (off_formname + CCHFORMNAME));
1165 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1166 dmA->dmDriverExtra);
1170 /******************************************************************
1171 * convert_printerinfo_W_to_A [internal]
1174 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1175 DWORD level, DWORD outlen, DWORD numentries)
1181 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1183 len = pi_sizeof[level] * numentries;
1184 ptr = (LPSTR) out + len;
1187 /* copy the numbers of all PRINTER_INFO_* first */
1188 memcpy(out, pPrintersW, len);
1190 while (id < numentries) {
1194 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1195 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1197 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1198 if (piW->pDescription) {
1199 piA->pDescription = ptr;
1200 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1201 ptr, outlen, NULL, NULL);
1207 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1208 ptr, outlen, NULL, NULL);
1212 if (piW->pComment) {
1213 piA->pComment = ptr;
1214 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1215 ptr, outlen, NULL, NULL);
1224 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1225 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1228 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1229 if (piW->pServerName) {
1230 piA->pServerName = ptr;
1231 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1232 ptr, outlen, NULL, NULL);
1236 if (piW->pPrinterName) {
1237 piA->pPrinterName = ptr;
1238 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1239 ptr, outlen, NULL, NULL);
1243 if (piW->pShareName) {
1244 piA->pShareName = ptr;
1245 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1246 ptr, outlen, NULL, NULL);
1250 if (piW->pPortName) {
1251 piA->pPortName = ptr;
1252 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1253 ptr, outlen, NULL, NULL);
1257 if (piW->pDriverName) {
1258 piA->pDriverName = ptr;
1259 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1260 ptr, outlen, NULL, NULL);
1264 if (piW->pComment) {
1265 piA->pComment = ptr;
1266 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1267 ptr, outlen, NULL, NULL);
1271 if (piW->pLocation) {
1272 piA->pLocation = ptr;
1273 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1274 ptr, outlen, NULL, NULL);
1279 dmA = DEVMODEdupWtoA(piW->pDevMode);
1281 /* align DEVMODEA to a DWORD boundary */
1282 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1286 piA->pDevMode = (LPDEVMODEA) ptr;
1287 len = dmA->dmSize + dmA->dmDriverExtra;
1288 memcpy(ptr, dmA, len);
1289 HeapFree(GetProcessHeap(), 0, dmA);
1295 if (piW->pSepFile) {
1296 piA->pSepFile = ptr;
1297 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1298 ptr, outlen, NULL, NULL);
1302 if (piW->pPrintProcessor) {
1303 piA->pPrintProcessor = ptr;
1304 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1305 ptr, outlen, NULL, NULL);
1309 if (piW->pDatatype) {
1310 piA->pDatatype = ptr;
1311 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1312 ptr, outlen, NULL, NULL);
1316 if (piW->pParameters) {
1317 piA->pParameters = ptr;
1318 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1319 ptr, outlen, NULL, NULL);
1323 if (piW->pSecurityDescriptor) {
1324 piA->pSecurityDescriptor = NULL;
1325 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1332 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1333 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1335 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1337 if (piW->pPrinterName) {
1338 piA->pPrinterName = ptr;
1339 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1340 ptr, outlen, NULL, NULL);
1344 if (piW->pServerName) {
1345 piA->pServerName = ptr;
1346 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1347 ptr, outlen, NULL, NULL);
1356 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1357 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1359 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1361 if (piW->pPrinterName) {
1362 piA->pPrinterName = ptr;
1363 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1364 ptr, outlen, NULL, NULL);
1368 if (piW->pPortName) {
1369 piA->pPortName = ptr;
1370 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1371 ptr, outlen, NULL, NULL);
1378 case 6: /* 6A and 6W are the same structure */
1383 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1384 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1386 TRACE("(%u) #%u\n", level, id);
1387 if (piW->pszObjectGUID) {
1388 piA->pszObjectGUID = ptr;
1389 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1390 ptr, outlen, NULL, NULL);
1400 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1401 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1404 TRACE("(%u) #%u\n", level, id);
1405 dmA = DEVMODEdupWtoA(piW->pDevMode);
1407 /* align DEVMODEA to a DWORD boundary */
1408 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1412 piA->pDevMode = (LPDEVMODEA) ptr;
1413 len = dmA->dmSize + dmA->dmDriverExtra;
1414 memcpy(ptr, dmA, len);
1415 HeapFree(GetProcessHeap(), 0, dmA);
1425 FIXME("for level %u\n", level);
1427 pPrintersW += pi_sizeof[level];
1428 out += pi_sizeof[level];
1433 /******************************************************************
1434 * convert_driverinfo_W_to_A [internal]
1437 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1438 DWORD level, DWORD outlen, DWORD numentries)
1444 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1446 len = di_sizeof[level] * numentries;
1447 ptr = (LPSTR) out + len;
1450 /* copy the numbers of all PRINTER_INFO_* first */
1451 memcpy(out, pDriversW, len);
1453 #define COPY_STRING(fld) \
1456 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1457 ptr += len; outlen -= len;\
1459 #define COPY_MULTIZ_STRING(fld) \
1460 { LPWSTR p = diW->fld; if (p){ \
1463 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1464 ptr += len; outlen -= len; p += len;\
1466 while(len > 1 && outlen > 0); \
1469 while (id < numentries)
1475 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1476 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1478 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1485 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1486 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1488 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1491 COPY_STRING(pEnvironment);
1492 COPY_STRING(pDriverPath);
1493 COPY_STRING(pDataFile);
1494 COPY_STRING(pConfigFile);
1499 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1500 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1502 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1505 COPY_STRING(pEnvironment);
1506 COPY_STRING(pDriverPath);
1507 COPY_STRING(pDataFile);
1508 COPY_STRING(pConfigFile);
1509 COPY_STRING(pHelpFile);
1510 COPY_MULTIZ_STRING(pDependentFiles);
1511 COPY_STRING(pMonitorName);
1512 COPY_STRING(pDefaultDataType);
1517 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1518 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1520 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1523 COPY_STRING(pEnvironment);
1524 COPY_STRING(pDriverPath);
1525 COPY_STRING(pDataFile);
1526 COPY_STRING(pConfigFile);
1527 COPY_STRING(pHelpFile);
1528 COPY_MULTIZ_STRING(pDependentFiles);
1529 COPY_STRING(pMonitorName);
1530 COPY_STRING(pDefaultDataType);
1531 COPY_MULTIZ_STRING(pszzPreviousNames);
1536 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1537 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1539 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1542 COPY_STRING(pEnvironment);
1543 COPY_STRING(pDriverPath);
1544 COPY_STRING(pDataFile);
1545 COPY_STRING(pConfigFile);
1550 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1551 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1553 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1556 COPY_STRING(pEnvironment);
1557 COPY_STRING(pDriverPath);
1558 COPY_STRING(pDataFile);
1559 COPY_STRING(pConfigFile);
1560 COPY_STRING(pHelpFile);
1561 COPY_MULTIZ_STRING(pDependentFiles);
1562 COPY_STRING(pMonitorName);
1563 COPY_STRING(pDefaultDataType);
1564 COPY_MULTIZ_STRING(pszzPreviousNames);
1565 COPY_STRING(pszMfgName);
1566 COPY_STRING(pszOEMUrl);
1567 COPY_STRING(pszHardwareID);
1568 COPY_STRING(pszProvider);
1573 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1574 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1576 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1579 COPY_STRING(pEnvironment);
1580 COPY_STRING(pDriverPath);
1581 COPY_STRING(pDataFile);
1582 COPY_STRING(pConfigFile);
1583 COPY_STRING(pHelpFile);
1584 COPY_MULTIZ_STRING(pDependentFiles);
1585 COPY_STRING(pMonitorName);
1586 COPY_STRING(pDefaultDataType);
1587 COPY_MULTIZ_STRING(pszzPreviousNames);
1588 COPY_STRING(pszMfgName);
1589 COPY_STRING(pszOEMUrl);
1590 COPY_STRING(pszHardwareID);
1591 COPY_STRING(pszProvider);
1592 COPY_STRING(pszPrintProcessor);
1593 COPY_STRING(pszVendorSetup);
1594 COPY_MULTIZ_STRING(pszzColorProfiles);
1595 COPY_STRING(pszInfPath);
1596 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1602 FIXME("for level %u\n", level);
1605 pDriversW += di_sizeof[level];
1606 out += di_sizeof[level];
1611 #undef COPY_MULTIZ_STRING
1615 /***********************************************************
1618 static void *printer_info_AtoW( const void *data, DWORD level )
1621 UNICODE_STRING usBuffer;
1623 if (!data) return NULL;
1625 if (level < 1 || level > 9) return NULL;
1627 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1628 if (!ret) return NULL;
1630 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1636 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1637 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1639 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1640 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1641 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1642 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1643 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1644 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1645 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1646 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1647 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1648 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1649 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1650 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1657 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1658 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1660 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1665 FIXME( "Unhandled level %d\n", level );
1666 HeapFree( GetProcessHeap(), 0, ret );
1673 /***********************************************************
1676 static void free_printer_info( void *data, DWORD level )
1684 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1686 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1687 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1688 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1689 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1690 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1691 HeapFree( GetProcessHeap(), 0, piW->pComment );
1692 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1693 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1694 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1695 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1696 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1697 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1704 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1706 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1711 FIXME( "Unhandled level %d\n", level );
1714 HeapFree( GetProcessHeap(), 0, data );
1718 /******************************************************************
1719 * DeviceCapabilities [WINSPOOL.@]
1720 * DeviceCapabilitiesA [WINSPOOL.@]
1723 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1724 LPSTR pOutput, LPDEVMODEA lpdm)
1728 if (!GDI_CallDeviceCapabilities16)
1730 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1732 if (!GDI_CallDeviceCapabilities16) return -1;
1734 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1736 /* If DC_PAPERSIZE map POINT16s to POINTs */
1737 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1738 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1739 POINT *pt = (POINT *)pOutput;
1741 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1742 for(i = 0; i < ret; i++, pt++)
1747 HeapFree( GetProcessHeap(), 0, tmp );
1753 /*****************************************************************************
1754 * DeviceCapabilitiesW [WINSPOOL.@]
1756 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1759 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1760 WORD fwCapability, LPWSTR pOutput,
1761 const DEVMODEW *pDevMode)
1763 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1764 LPSTR pDeviceA = strdupWtoA(pDevice);
1765 LPSTR pPortA = strdupWtoA(pPort);
1768 if(pOutput && (fwCapability == DC_BINNAMES ||
1769 fwCapability == DC_FILEDEPENDENCIES ||
1770 fwCapability == DC_PAPERNAMES)) {
1771 /* These need A -> W translation */
1774 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1778 switch(fwCapability) {
1783 case DC_FILEDEPENDENCIES:
1787 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1788 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1790 for(i = 0; i < ret; i++)
1791 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1792 pOutput + (i * size), size);
1793 HeapFree(GetProcessHeap(), 0, pOutputA);
1795 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1796 (LPSTR)pOutput, dmA);
1798 HeapFree(GetProcessHeap(),0,pPortA);
1799 HeapFree(GetProcessHeap(),0,pDeviceA);
1800 HeapFree(GetProcessHeap(),0,dmA);
1804 /******************************************************************
1805 * DocumentPropertiesA [WINSPOOL.@]
1807 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1809 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1810 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1811 LPDEVMODEA pDevModeInput,DWORD fMode )
1813 LPSTR lpName = pDeviceName;
1814 static CHAR port[] = "LPT1:";
1817 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1818 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1822 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1824 ERR("no name from hPrinter?\n");
1825 SetLastError(ERROR_INVALID_HANDLE);
1828 lpName = strdupWtoA(lpNameW);
1831 if (!GDI_CallExtDeviceMode16)
1833 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1835 if (!GDI_CallExtDeviceMode16) {
1836 ERR("No CallExtDeviceMode16?\n");
1840 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1841 pDevModeInput, NULL, fMode);
1844 HeapFree(GetProcessHeap(),0,lpName);
1849 /*****************************************************************************
1850 * DocumentPropertiesW (WINSPOOL.@)
1852 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1854 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1856 LPDEVMODEW pDevModeOutput,
1857 LPDEVMODEW pDevModeInput, DWORD fMode)
1860 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1861 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1862 LPDEVMODEA pDevModeOutputA = NULL;
1865 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1866 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1868 if(pDevModeOutput) {
1869 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1870 if(ret < 0) return ret;
1871 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1873 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1874 pDevModeInputA, fMode);
1875 if(pDevModeOutput) {
1876 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1877 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1879 if(fMode == 0 && ret > 0)
1880 ret += (CCHDEVICENAME + CCHFORMNAME);
1881 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1882 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1886 /*****************************************************************************
1887 * IsValidDevmodeA [WINSPOOL.@]
1889 * Validate a DEVMODE structure and fix errors if possible.
1892 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1894 FIXME("(%p,%ld): stub\n", pDevMode, size);
1902 /*****************************************************************************
1903 * IsValidDevmodeW [WINSPOOL.@]
1905 * Validate a DEVMODE structure and fix errors if possible.
1908 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1910 FIXME("(%p,%ld): stub\n", pDevMode, size);
1918 /******************************************************************
1919 * OpenPrinterA [WINSPOOL.@]
1924 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1925 LPPRINTER_DEFAULTSA pDefault)
1927 UNICODE_STRING lpPrinterNameW;
1928 UNICODE_STRING usBuffer;
1929 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1930 PWSTR pwstrPrinterNameW;
1933 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1936 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1937 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1938 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1939 pDefaultW = &DefaultW;
1941 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1943 RtlFreeUnicodeString(&usBuffer);
1944 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1946 RtlFreeUnicodeString(&lpPrinterNameW);
1950 /******************************************************************
1951 * OpenPrinterW [WINSPOOL.@]
1953 * Open a Printer / Printserver or a Printer-Object
1956 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1957 * phPrinter [O] The resulting Handle is stored here
1958 * pDefault [I] PTR to Default Printer Settings or NULL
1965 * lpPrinterName is one of:
1966 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1967 *| Printer: "PrinterName"
1968 *| Printer-Object: "PrinterName,Job xxx"
1969 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1970 *| XcvPort: "Servername,XcvPort PortName"
1973 *| Printer-Object not supported
1974 *| pDefaults is ignored
1977 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1980 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1983 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1984 SetLastError(ERROR_INVALID_PARAMETER);
1988 /* Get the unique handle of the printer or Printserver */
1989 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1990 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1991 return (*phPrinter != 0);
1994 /******************************************************************
1995 * AddMonitorA [WINSPOOL.@]
2000 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2002 LPWSTR nameW = NULL;
2005 LPMONITOR_INFO_2A mi2a;
2006 MONITOR_INFO_2W mi2w;
2008 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2009 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2010 debugstr_a(mi2a ? mi2a->pName : NULL),
2011 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2012 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2015 SetLastError(ERROR_INVALID_LEVEL);
2019 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2025 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2026 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2027 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2030 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2032 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2033 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2036 if (mi2a->pEnvironment) {
2037 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2038 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2039 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2041 if (mi2a->pDLLName) {
2042 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2043 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2044 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2047 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2049 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2050 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2051 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2053 HeapFree(GetProcessHeap(), 0, nameW);
2057 /******************************************************************************
2058 * AddMonitorW [WINSPOOL.@]
2060 * Install a Printmonitor
2063 * pName [I] Servername or NULL (local Computer)
2064 * Level [I] Structure-Level (Must be 2)
2065 * pMonitors [I] PTR to MONITOR_INFO_2
2072 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2075 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2077 LPMONITOR_INFO_2W mi2w;
2079 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2080 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2081 debugstr_w(mi2w ? mi2w->pName : NULL),
2082 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2083 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2085 if ((backend == NULL) && !load_backend()) return FALSE;
2088 SetLastError(ERROR_INVALID_LEVEL);
2092 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2097 return backend->fpAddMonitor(pName, Level, pMonitors);
2100 /******************************************************************
2101 * DeletePrinterDriverA [WINSPOOL.@]
2104 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2106 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2109 /******************************************************************
2110 * DeletePrinterDriverW [WINSPOOL.@]
2113 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2115 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2118 /******************************************************************
2119 * DeleteMonitorA [WINSPOOL.@]
2121 * See DeleteMonitorW.
2124 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2126 LPWSTR nameW = NULL;
2127 LPWSTR EnvironmentW = NULL;
2128 LPWSTR MonitorNameW = NULL;
2133 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2134 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2135 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2139 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2140 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2141 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2144 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2145 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2146 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2149 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2151 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2152 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2153 HeapFree(GetProcessHeap(), 0, nameW);
2157 /******************************************************************
2158 * DeleteMonitorW [WINSPOOL.@]
2160 * Delete a specific Printmonitor from a Printing-Environment
2163 * pName [I] Servername or NULL (local Computer)
2164 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2165 * pMonitorName [I] Name of the Monitor, that should be deleted
2172 * pEnvironment is ignored in Windows for the local Computer.
2175 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2178 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2179 debugstr_w(pMonitorName));
2181 if ((backend == NULL) && !load_backend()) return FALSE;
2183 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2187 /******************************************************************
2188 * DeletePortA [WINSPOOL.@]
2193 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2195 LPWSTR nameW = NULL;
2196 LPWSTR portW = NULL;
2200 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2202 /* convert servername to unicode */
2204 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2205 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2209 /* convert portname to unicode */
2211 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2212 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2213 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2216 res = DeletePortW(nameW, hWnd, portW);
2217 HeapFree(GetProcessHeap(), 0, nameW);
2218 HeapFree(GetProcessHeap(), 0, portW);
2222 /******************************************************************
2223 * DeletePortW [WINSPOOL.@]
2225 * Delete a specific Port
2228 * pName [I] Servername or NULL (local Computer)
2229 * hWnd [I] Handle to parent Window for the Dialog-Box
2230 * pPortName [I] Name of the Port, that should be deleted
2237 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2239 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2241 if ((backend == NULL) && !load_backend()) return FALSE;
2244 SetLastError(RPC_X_NULL_REF_POINTER);
2248 return backend->fpDeletePort(pName, hWnd, pPortName);
2251 /******************************************************************************
2252 * WritePrinter [WINSPOOL.@]
2254 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2256 opened_printer_t *printer;
2259 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2261 EnterCriticalSection(&printer_handles_cs);
2262 printer = get_opened_printer(hPrinter);
2265 SetLastError(ERROR_INVALID_HANDLE);
2271 SetLastError(ERROR_SPL_NO_STARTDOC);
2275 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2277 LeaveCriticalSection(&printer_handles_cs);
2281 /*****************************************************************************
2282 * AddFormA [WINSPOOL.@]
2284 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2286 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2290 /*****************************************************************************
2291 * AddFormW [WINSPOOL.@]
2293 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2295 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2299 /*****************************************************************************
2300 * AddJobA [WINSPOOL.@]
2302 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2305 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2309 SetLastError(ERROR_INVALID_LEVEL);
2313 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2316 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2317 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2318 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2319 if(*pcbNeeded > cbBuf) {
2320 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2323 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2324 addjobA->JobId = addjobW->JobId;
2325 addjobA->Path = (char *)(addjobA + 1);
2326 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2332 /*****************************************************************************
2333 * AddJobW [WINSPOOL.@]
2335 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2337 opened_printer_t *printer;
2340 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2341 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2342 WCHAR path[MAX_PATH], filename[MAX_PATH];
2344 ADDJOB_INFO_1W *addjob;
2346 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2348 EnterCriticalSection(&printer_handles_cs);
2350 printer = get_opened_printer(hPrinter);
2353 SetLastError(ERROR_INVALID_HANDLE);
2358 SetLastError(ERROR_INVALID_LEVEL);
2362 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2366 job->job_id = InterlockedIncrement(&next_job_id);
2368 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2369 if(path[len - 1] != '\\')
2371 memcpy(path + len, spool_path, sizeof(spool_path));
2372 sprintfW(filename, fmtW, path, job->job_id);
2374 len = strlenW(filename);
2375 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2376 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2377 job->portname = NULL;
2378 job->document_title = strdupW(default_doc_title);
2379 job->printer_name = strdupW(printer->name);
2380 job->devmode = dup_devmode( printer->devmode );
2381 list_add_tail(&printer->queue->jobs, &job->entry);
2383 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2384 if(*pcbNeeded <= cbBuf) {
2385 addjob = (ADDJOB_INFO_1W*)pData;
2386 addjob->JobId = job->job_id;
2387 addjob->Path = (WCHAR *)(addjob + 1);
2388 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2391 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2394 LeaveCriticalSection(&printer_handles_cs);
2398 /*****************************************************************************
2399 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2401 * Return the PATH for the Print-Processors
2403 * See GetPrintProcessorDirectoryW.
2407 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2408 DWORD level, LPBYTE Info,
2409 DWORD cbBuf, LPDWORD pcbNeeded)
2411 LPWSTR serverW = NULL;
2416 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2417 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2421 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2422 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2423 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2427 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2428 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2429 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2432 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2433 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2435 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2438 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2439 cbBuf, NULL, NULL) > 0;
2442 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2443 HeapFree(GetProcessHeap(), 0, envW);
2444 HeapFree(GetProcessHeap(), 0, serverW);
2448 /*****************************************************************************
2449 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2451 * Return the PATH for the Print-Processors
2454 * server [I] Servername (NT only) or NULL (local Computer)
2455 * env [I] Printing-Environment (see below) or NULL (Default)
2456 * level [I] Structure-Level (must be 1)
2457 * Info [O] PTR to Buffer that receives the Result
2458 * cbBuf [I] Size of Buffer at "Info"
2459 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2460 * required for the Buffer at "Info"
2463 * Success: TRUE and in pcbNeeded the Bytes used in Info
2464 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2465 * if cbBuf is too small
2467 * Native Values returned in Info on Success:
2468 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2469 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2470 *| win9x(Windows 4.0): "%winsysdir%"
2472 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2475 * Only NULL or "" is supported for server
2478 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2479 DWORD level, LPBYTE Info,
2480 DWORD cbBuf, LPDWORD pcbNeeded)
2483 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2484 Info, cbBuf, pcbNeeded);
2486 if ((backend == NULL) && !load_backend()) return FALSE;
2489 /* (Level != 1) is ignored in win9x */
2490 SetLastError(ERROR_INVALID_LEVEL);
2494 if (pcbNeeded == NULL) {
2495 /* (pcbNeeded == NULL) is ignored in win9x */
2496 SetLastError(RPC_X_NULL_REF_POINTER);
2500 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2503 /*****************************************************************************
2504 * WINSPOOL_OpenDriverReg [internal]
2506 * opens the registry for the printer drivers depending on the given input
2507 * variable pEnvironment
2510 * the opened hkey on success
2513 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2517 const printenv_t * env;
2519 TRACE("(%s)\n", debugstr_w(pEnvironment));
2521 env = validate_envW(pEnvironment);
2522 if (!env) return NULL;
2524 buffer = HeapAlloc( GetProcessHeap(), 0,
2525 (strlenW(DriversW) + strlenW(env->envname) +
2526 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2528 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2529 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2530 HeapFree(GetProcessHeap(), 0, buffer);
2535 /*****************************************************************************
2536 * set_devices_and_printerports [internal]
2538 * set the [Devices] and [PrinterPorts] entries for a printer.
2541 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2543 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2547 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2549 /* FIXME: the driver must change to "winspool" */
2550 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2552 lstrcpyW(devline, driver_nt);
2553 lstrcatW(devline, commaW);
2554 lstrcatW(devline, pi->pPortName);
2556 TRACE("using %s\n", debugstr_w(devline));
2557 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2558 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2559 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2560 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2564 lstrcatW(devline, timeout_15_45);
2565 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2566 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2567 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2568 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2571 HeapFree(GetProcessHeap(), 0, devline);
2575 /*****************************************************************************
2576 * AddPrinterW [WINSPOOL.@]
2578 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2580 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2583 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2585 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2586 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2587 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2588 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2589 statusW[] = {'S','t','a','t','u','s',0},
2590 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2592 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2595 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2596 SetLastError(ERROR_INVALID_PARAMETER);
2600 ERR("Level = %d, unsupported!\n", Level);
2601 SetLastError(ERROR_INVALID_LEVEL);
2605 SetLastError(ERROR_INVALID_PARAMETER);
2608 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2610 ERR("Can't create Printers key\n");
2613 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2614 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2615 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2616 RegCloseKey(hkeyPrinter);
2617 RegCloseKey(hkeyPrinters);
2620 RegCloseKey(hkeyPrinter);
2622 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2624 ERR("Can't create Drivers key\n");
2625 RegCloseKey(hkeyPrinters);
2628 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2630 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2631 RegCloseKey(hkeyPrinters);
2632 RegCloseKey(hkeyDrivers);
2633 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2636 RegCloseKey(hkeyDriver);
2637 RegCloseKey(hkeyDrivers);
2639 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2640 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2641 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2642 RegCloseKey(hkeyPrinters);
2646 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2648 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2649 SetLastError(ERROR_INVALID_PRINTER_NAME);
2650 RegCloseKey(hkeyPrinters);
2654 set_devices_and_printerports(pi);
2655 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2656 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2657 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2659 /* See if we can load the driver. We may need the devmode structure anyway
2662 * Note that DocumentPropertiesW will briefly try to open the printer we
2663 * just create to find a DEVMODE struct (it will use the WINEPS default
2664 * one in case it is not there, so we are ok).
2666 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2669 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2670 size = sizeof(DEVMODEW);
2676 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2678 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2680 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2681 HeapFree( GetProcessHeap(), 0, dm );
2686 /* set devmode to printer name */
2687 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2691 set_reg_devmode( hkeyPrinter, default_devmodeW, dm );
2692 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2694 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2695 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2696 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2697 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2699 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2700 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2701 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2702 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2703 (LPBYTE)&pi->Priority, sizeof(DWORD));
2704 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2705 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2706 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2707 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2708 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2709 (LPBYTE)&pi->Status, sizeof(DWORD));
2710 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2711 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2713 RegCloseKey(hkeyPrinter);
2714 RegCloseKey(hkeyPrinters);
2715 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2716 ERR("OpenPrinter failing\n");
2722 /*****************************************************************************
2723 * AddPrinterA [WINSPOOL.@]
2725 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2727 UNICODE_STRING pNameW;
2729 PRINTER_INFO_2W *piW;
2730 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2733 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2735 ERR("Level = %d, unsupported!\n", Level);
2736 SetLastError(ERROR_INVALID_LEVEL);
2739 pwstrNameW = asciitounicode(&pNameW,pName);
2740 piW = printer_info_AtoW( piA, Level );
2742 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2744 free_printer_info( piW, Level );
2745 RtlFreeUnicodeString(&pNameW);
2750 /*****************************************************************************
2751 * ClosePrinter [WINSPOOL.@]
2753 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2755 UINT_PTR i = (UINT_PTR)hPrinter;
2756 opened_printer_t *printer = NULL;
2759 TRACE("(%p)\n", hPrinter);
2761 EnterCriticalSection(&printer_handles_cs);
2763 if ((i > 0) && (i <= nb_printer_handles))
2764 printer = printer_handles[i - 1];
2769 struct list *cursor, *cursor2;
2771 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2773 if (printer->backend_printer) {
2774 backend->fpClosePrinter(printer->backend_printer);
2778 EndDocPrinter(hPrinter);
2780 if(InterlockedDecrement(&printer->queue->ref) == 0)
2782 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2784 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2785 ScheduleJob(hPrinter, job->job_id);
2787 HeapFree(GetProcessHeap(), 0, printer->queue);
2790 free_printer_entry( printer );
2791 printer_handles[i - 1] = NULL;
2794 LeaveCriticalSection(&printer_handles_cs);
2798 /*****************************************************************************
2799 * DeleteFormA [WINSPOOL.@]
2801 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2803 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2807 /*****************************************************************************
2808 * DeleteFormW [WINSPOOL.@]
2810 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2812 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2816 /*****************************************************************************
2817 * DeletePrinter [WINSPOOL.@]
2819 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2821 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2822 HKEY hkeyPrinters, hkey;
2823 WCHAR def[MAX_PATH];
2824 DWORD size = sizeof( def ) / sizeof( def[0] );
2827 SetLastError(ERROR_INVALID_HANDLE);
2830 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2831 RegDeleteTreeW(hkeyPrinters, lpNameW);
2832 RegCloseKey(hkeyPrinters);
2834 WriteProfileStringW(devicesW, lpNameW, NULL);
2835 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2837 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2838 RegDeleteValueW(hkey, lpNameW);
2842 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2843 RegDeleteValueW(hkey, lpNameW);
2847 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2849 WriteProfileStringW( windowsW, deviceW, NULL );
2850 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2852 RegDeleteValueW( hkey, deviceW );
2853 RegCloseKey( hkey );
2855 SetDefaultPrinterW( NULL );
2861 /*****************************************************************************
2862 * SetPrinterA [WINSPOOL.@]
2864 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2871 dataW = printer_info_AtoW( data, level );
2872 if (!dataW) return FALSE;
2875 ret = SetPrinterW( printer, level, dataW, command );
2877 if (dataW != data) free_printer_info( dataW, level );
2882 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2884 set_reg_szW( key, NameW, pi->pPrinterName );
2885 set_reg_szW( key, Share_NameW, pi->pShareName );
2886 set_reg_szW( key, PortW, pi->pPortName );
2887 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
2888 set_reg_szW( key, DescriptionW, pi->pComment );
2889 set_reg_szW( key, LocationW, pi->pLocation );
2892 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2894 set_reg_szW( key, Separator_FileW, pi->pSepFile );
2895 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
2896 set_reg_szW( key, DatatypeW, pi->pDatatype );
2897 set_reg_szW( key, ParametersW, pi->pParameters );
2899 set_reg_DWORD( key, "Attributes", pi->Attributes );
2900 set_reg_DWORD( key, "Priority", pi->Priority );
2901 set_reg_DWORD( key, "Default Priority", pi->DefaultPriority );
2902 set_reg_DWORD( key, "StartTime", pi->StartTime );
2903 set_reg_DWORD( key, "UntilTime", pi->UntilTime );
2906 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2908 if (!pi->pDevMode) return FALSE;
2910 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2914 /******************************************************************************
2915 * SetPrinterW [WINSPOOL.@]
2917 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2922 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2924 if (command != 0) FIXME( "Ignoring command %d\n", command );
2926 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2933 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2934 set_printer_2( key, pi2 );
2941 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2942 ret = set_printer_9( key, pi );
2947 FIXME( "Unimplemented level %d\n", level );
2948 SetLastError( ERROR_INVALID_LEVEL );
2955 /*****************************************************************************
2956 * SetJobA [WINSPOOL.@]
2958 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2959 LPBYTE pJob, DWORD Command)
2963 UNICODE_STRING usBuffer;
2965 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2967 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2968 are all ignored by SetJob, so we don't bother copying them */
2976 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2977 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2979 JobW = (LPBYTE)info1W;
2980 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2981 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2982 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2983 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2984 info1W->Status = info1A->Status;
2985 info1W->Priority = info1A->Priority;
2986 info1W->Position = info1A->Position;
2987 info1W->PagesPrinted = info1A->PagesPrinted;
2992 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2993 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2995 JobW = (LPBYTE)info2W;
2996 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2997 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2998 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2999 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3000 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3001 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3002 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3003 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3004 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3005 info2W->Status = info2A->Status;
3006 info2W->Priority = info2A->Priority;
3007 info2W->Position = info2A->Position;
3008 info2W->StartTime = info2A->StartTime;
3009 info2W->UntilTime = info2A->UntilTime;
3010 info2W->PagesPrinted = info2A->PagesPrinted;
3014 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3015 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3018 SetLastError(ERROR_INVALID_LEVEL);
3022 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3028 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3029 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3030 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3031 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3032 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3037 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3038 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3039 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3040 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3041 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3042 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3043 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3044 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3045 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3049 HeapFree(GetProcessHeap(), 0, JobW);
3054 /*****************************************************************************
3055 * SetJobW [WINSPOOL.@]
3057 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3058 LPBYTE pJob, DWORD Command)
3063 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3064 FIXME("Ignoring everything other than document title\n");
3066 EnterCriticalSection(&printer_handles_cs);
3067 job = get_job(hPrinter, JobId);
3077 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3078 HeapFree(GetProcessHeap(), 0, job->document_title);
3079 job->document_title = strdupW(info1->pDocument);
3084 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3085 HeapFree(GetProcessHeap(), 0, job->document_title);
3086 job->document_title = strdupW(info2->pDocument);
3087 HeapFree(GetProcessHeap(), 0, job->devmode);
3088 job->devmode = dup_devmode( info2->pDevMode );
3094 SetLastError(ERROR_INVALID_LEVEL);
3099 LeaveCriticalSection(&printer_handles_cs);
3103 /*****************************************************************************
3104 * EndDocPrinter [WINSPOOL.@]
3106 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3108 opened_printer_t *printer;
3110 TRACE("(%p)\n", hPrinter);
3112 EnterCriticalSection(&printer_handles_cs);
3114 printer = get_opened_printer(hPrinter);
3117 SetLastError(ERROR_INVALID_HANDLE);
3123 SetLastError(ERROR_SPL_NO_STARTDOC);
3127 CloseHandle(printer->doc->hf);
3128 ScheduleJob(hPrinter, printer->doc->job_id);
3129 HeapFree(GetProcessHeap(), 0, printer->doc);
3130 printer->doc = NULL;
3133 LeaveCriticalSection(&printer_handles_cs);
3137 /*****************************************************************************
3138 * EndPagePrinter [WINSPOOL.@]
3140 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3142 FIXME("(%p): stub\n", hPrinter);
3146 /*****************************************************************************
3147 * StartDocPrinterA [WINSPOOL.@]
3149 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3151 UNICODE_STRING usBuffer;
3153 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3156 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3157 or one (DOC_INFO_3) extra DWORDs */
3161 doc2W.JobId = doc2->JobId;
3164 doc2W.dwMode = doc2->dwMode;
3167 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3168 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3169 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3173 SetLastError(ERROR_INVALID_LEVEL);
3177 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3179 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3180 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3181 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3186 /*****************************************************************************
3187 * StartDocPrinterW [WINSPOOL.@]
3189 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3191 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3192 opened_printer_t *printer;
3193 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3194 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3195 JOB_INFO_1W job_info;
3196 DWORD needed, ret = 0;
3201 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3202 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3203 debugstr_w(doc->pDatatype));
3205 if(Level < 1 || Level > 3)
3207 SetLastError(ERROR_INVALID_LEVEL);
3211 EnterCriticalSection(&printer_handles_cs);
3212 printer = get_opened_printer(hPrinter);
3215 SetLastError(ERROR_INVALID_HANDLE);
3221 SetLastError(ERROR_INVALID_PRINTER_STATE);
3225 /* Even if we're printing to a file we still add a print job, we'll
3226 just ignore the spool file name */
3228 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3230 ERR("AddJob failed gle %u\n", GetLastError());
3234 /* use pOutputFile only, when it is a real filename */
3235 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3236 filename = doc->pOutputFile;
3238 filename = addjob->Path;
3240 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3241 if(hf == INVALID_HANDLE_VALUE)
3244 memset(&job_info, 0, sizeof(job_info));
3245 job_info.pDocument = doc->pDocName;
3246 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3248 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3249 printer->doc->hf = hf;
3250 ret = printer->doc->job_id = addjob->JobId;
3251 job = get_job(hPrinter, ret);
3252 job->portname = strdupW(doc->pOutputFile);
3255 LeaveCriticalSection(&printer_handles_cs);
3260 /*****************************************************************************
3261 * StartPagePrinter [WINSPOOL.@]
3263 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3265 FIXME("(%p): stub\n", hPrinter);
3269 /*****************************************************************************
3270 * GetFormA [WINSPOOL.@]
3272 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3273 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3275 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3276 Level,pForm,cbBuf,pcbNeeded);
3280 /*****************************************************************************
3281 * GetFormW [WINSPOOL.@]
3283 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3284 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3286 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3287 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3291 /*****************************************************************************
3292 * SetFormA [WINSPOOL.@]
3294 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3297 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3301 /*****************************************************************************
3302 * SetFormW [WINSPOOL.@]
3304 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3307 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3311 /*****************************************************************************
3312 * ReadPrinter [WINSPOOL.@]
3314 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3315 LPDWORD pNoBytesRead)
3317 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3321 /*****************************************************************************
3322 * ResetPrinterA [WINSPOOL.@]
3324 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3326 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3330 /*****************************************************************************
3331 * ResetPrinterW [WINSPOOL.@]
3333 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3335 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3339 /*****************************************************************************
3340 * WINSPOOL_GetDWORDFromReg
3342 * Return DWORD associated with ValueName from hkey.
3344 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3346 DWORD sz = sizeof(DWORD), type, value = 0;
3349 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3351 if(ret != ERROR_SUCCESS) {
3352 WARN("Got ret = %d on name %s\n", ret, ValueName);
3355 if(type != REG_DWORD) {
3356 ERR("Got type %d\n", type);
3363 /*****************************************************************************
3364 * get_filename_from_reg [internal]
3366 * Get ValueName from hkey storing result in out
3367 * when the Value in the registry has only a filename, use driverdir as prefix
3368 * outlen is space left in out
3369 * String is stored either as unicode or ascii
3373 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3374 LPBYTE out, DWORD outlen, LPDWORD needed)
3376 WCHAR filename[MAX_PATH];
3380 LPWSTR buffer = filename;
3384 size = sizeof(filename);
3386 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3387 if (ret == ERROR_MORE_DATA) {
3388 TRACE("need dynamic buffer: %u\n", size);
3389 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3391 /* No Memory is bad */
3395 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3398 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3399 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3405 /* do we have a full path ? */
3406 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3407 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3410 /* we must build the full Path */
3412 if ((out) && (outlen > dirlen)) {
3413 lstrcpyW((LPWSTR)out, driverdir);
3421 /* write the filename */
3422 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3423 if ((out) && (outlen >= size)) {
3424 lstrcpyW((LPWSTR)out, ptr);
3431 ptr += lstrlenW(ptr)+1;
3432 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3435 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3437 /* write the multisz-termination */
3438 if (type == REG_MULTI_SZ) {
3439 size = sizeof(WCHAR);
3442 if (out && (outlen >= size)) {
3443 memset (out, 0, size);
3449 /*****************************************************************************
3450 * WINSPOOL_GetStringFromReg
3452 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3453 * String is stored as unicode.
3455 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3456 DWORD buflen, DWORD *needed)
3458 DWORD sz = buflen, type;
3461 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3462 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3463 WARN("Got ret = %d\n", ret);
3467 /* add space for terminating '\0' */
3468 sz += sizeof(WCHAR);
3472 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3477 /*****************************************************************************
3478 * WINSPOOL_GetDefaultDevMode
3480 * Get a default DevMode values for wineps.
3484 static void WINSPOOL_GetDefaultDevMode(
3486 DWORD buflen, DWORD *needed)
3489 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3491 /* fill default DEVMODE - should be read from ppd... */
3492 ZeroMemory( &dm, sizeof(dm) );
3493 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3494 dm.dmSpecVersion = DM_SPECVERSION;
3495 dm.dmDriverVersion = 1;
3496 dm.dmSize = sizeof(DEVMODEW);
3497 dm.dmDriverExtra = 0;
3499 DM_ORIENTATION | DM_PAPERSIZE |
3500 DM_PAPERLENGTH | DM_PAPERWIDTH |
3503 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3504 DM_YRESOLUTION | DM_TTOPTION;
3506 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3507 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3508 dm.u1.s1.dmPaperLength = 2970;
3509 dm.u1.s1.dmPaperWidth = 2100;
3511 dm.u1.s1.dmScale = 100;
3512 dm.u1.s1.dmCopies = 1;
3513 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3514 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3517 dm.dmYResolution = 300; /* 300dpi */
3518 dm.dmTTOption = DMTT_BITMAP;
3521 /* dm.dmLogPixels */
3522 /* dm.dmBitsPerPel */
3523 /* dm.dmPelsWidth */
3524 /* dm.dmPelsHeight */
3525 /* dm.u2.dmDisplayFlags */
3526 /* dm.dmDisplayFrequency */
3527 /* dm.dmICMMethod */
3528 /* dm.dmICMIntent */
3529 /* dm.dmMediaType */
3530 /* dm.dmDitherType */
3531 /* dm.dmReserved1 */
3532 /* dm.dmReserved2 */
3533 /* dm.dmPanningWidth */
3534 /* dm.dmPanningHeight */
3536 if(buflen >= sizeof(DEVMODEW))
3537 memcpy(ptr, &dm, sizeof(DEVMODEW));
3538 *needed = sizeof(DEVMODEW);
3541 /*****************************************************************************
3542 * WINSPOOL_GetDevModeFromReg
3544 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3545 * DevMode is stored either as unicode or ascii.
3547 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3549 DWORD buflen, DWORD *needed)
3551 DWORD sz = buflen, type;
3554 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3555 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3556 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3557 if (sz < sizeof(DEVMODEA))
3559 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3562 /* ensures that dmSize is not erratically bogus if registry is invalid */
3563 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3564 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3565 sz += (CCHDEVICENAME + CCHFORMNAME);
3566 if (ptr && (buflen >= sz)) {
3567 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3568 memcpy(ptr, dmW, sz);
3569 HeapFree(GetProcessHeap(),0,dmW);
3575 /*********************************************************************
3576 * WINSPOOL_GetPrinter_1
3578 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3580 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3581 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3583 DWORD size, left = cbBuf;
3584 BOOL space = (cbBuf > 0);
3589 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3590 if(space && size <= left) {
3591 pi1->pName = (LPWSTR)ptr;
3599 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3600 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3601 if(space && size <= left) {
3602 pi1->pDescription = (LPWSTR)ptr;
3610 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3611 if(space && size <= left) {
3612 pi1->pComment = (LPWSTR)ptr;
3620 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3622 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3623 memset(pi1, 0, sizeof(*pi1));
3627 /*********************************************************************
3628 * WINSPOOL_GetPrinter_2
3630 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3632 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3633 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3635 DWORD size, left = cbBuf;
3636 BOOL space = (cbBuf > 0);
3641 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3642 if(space && size <= left) {
3643 pi2->pPrinterName = (LPWSTR)ptr;
3650 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3651 if(space && size <= left) {
3652 pi2->pShareName = (LPWSTR)ptr;
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3660 if(space && size <= left) {
3661 pi2->pPortName = (LPWSTR)ptr;
3668 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3669 if(space && size <= left) {
3670 pi2->pDriverName = (LPWSTR)ptr;
3677 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3678 if(space && size <= left) {
3679 pi2->pComment = (LPWSTR)ptr;
3686 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3687 if(space && size <= left) {
3688 pi2->pLocation = (LPWSTR)ptr;
3695 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3696 if(space && size <= left) {
3697 pi2->pDevMode = (LPDEVMODEW)ptr;
3706 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3707 if(space && size <= left) {
3708 pi2->pDevMode = (LPDEVMODEW)ptr;
3715 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3716 if(space && size <= left) {
3717 pi2->pSepFile = (LPWSTR)ptr;
3724 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3725 if(space && size <= left) {
3726 pi2->pPrintProcessor = (LPWSTR)ptr;
3733 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3734 if(space && size <= left) {
3735 pi2->pDatatype = (LPWSTR)ptr;
3742 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3743 if(space && size <= left) {
3744 pi2->pParameters = (LPWSTR)ptr;
3752 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3753 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3754 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3755 "Default Priority");
3756 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3757 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3760 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3761 memset(pi2, 0, sizeof(*pi2));
3766 /*********************************************************************
3767 * WINSPOOL_GetPrinter_4
3769 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3771 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3772 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3774 DWORD size, left = cbBuf;
3775 BOOL space = (cbBuf > 0);
3780 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3781 if(space && size <= left) {
3782 pi4->pPrinterName = (LPWSTR)ptr;
3790 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3793 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3794 memset(pi4, 0, sizeof(*pi4));
3799 /*********************************************************************
3800 * WINSPOOL_GetPrinter_5
3802 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3804 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3805 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3807 DWORD size, left = cbBuf;
3808 BOOL space = (cbBuf > 0);
3813 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3814 if(space && size <= left) {
3815 pi5->pPrinterName = (LPWSTR)ptr;
3822 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3823 if(space && size <= left) {
3824 pi5->pPortName = (LPWSTR)ptr;
3832 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3833 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3835 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3839 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3840 memset(pi5, 0, sizeof(*pi5));
3845 /*********************************************************************
3846 * WINSPOOL_GetPrinter_7
3848 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3850 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3851 DWORD cbBuf, LPDWORD pcbNeeded)
3853 DWORD size, left = cbBuf;
3854 BOOL space = (cbBuf > 0);
3859 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3862 size = sizeof(pi7->pszObjectGUID);
3864 if (space && size <= left) {
3865 pi7->pszObjectGUID = (LPWSTR)ptr;
3872 /* We do not have a Directory Service */
3873 pi7->dwAction = DSPRINT_UNPUBLISH;
3876 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3877 memset(pi7, 0, sizeof(*pi7));
3882 /*********************************************************************
3883 * WINSPOOL_GetPrinter_9
3885 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3887 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3888 DWORD cbBuf, LPDWORD pcbNeeded)
3891 BOOL space = (cbBuf > 0);
3895 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3896 if(space && size <= cbBuf) {
3897 pi9->pDevMode = (LPDEVMODEW)buf;
3904 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3905 if(space && size <= cbBuf) {
3906 pi9->pDevMode = (LPDEVMODEW)buf;
3912 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3913 memset(pi9, 0, sizeof(*pi9));
3918 /*****************************************************************************
3919 * GetPrinterW [WINSPOOL.@]
3921 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3922 DWORD cbBuf, LPDWORD pcbNeeded)
3924 DWORD size, needed = 0, err;
3929 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3931 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3934 SetLastError( err );
3941 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3943 size = sizeof(PRINTER_INFO_2W);
3945 ptr = pPrinter + size;
3947 memset(pPrinter, 0, size);
3952 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3959 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3961 size = sizeof(PRINTER_INFO_4W);
3963 ptr = pPrinter + size;
3965 memset(pPrinter, 0, size);
3970 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3978 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3980 size = sizeof(PRINTER_INFO_5W);
3982 ptr = pPrinter + size;
3984 memset(pPrinter, 0, size);
3990 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3998 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4000 size = sizeof(PRINTER_INFO_6);
4001 if (size <= cbBuf) {
4002 /* FIXME: We do not update the status yet */
4003 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4015 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4017 size = sizeof(PRINTER_INFO_7W);
4018 if (size <= cbBuf) {
4019 ptr = pPrinter + size;
4021 memset(pPrinter, 0, size);
4027 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4034 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4035 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4039 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4041 size = sizeof(PRINTER_INFO_9W);
4043 ptr = pPrinter + size;
4045 memset(pPrinter, 0, size);
4051 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4058 FIXME("Unimplemented level %d\n", Level);
4059 SetLastError(ERROR_INVALID_LEVEL);
4060 RegCloseKey(hkeyPrinter);
4064 RegCloseKey(hkeyPrinter);
4066 TRACE("returning %d needed = %d\n", ret, needed);
4067 if(pcbNeeded) *pcbNeeded = needed;
4069 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4073 /*****************************************************************************
4074 * GetPrinterA [WINSPOOL.@]
4076 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4077 DWORD cbBuf, LPDWORD pcbNeeded)
4083 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4085 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4087 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4088 HeapFree(GetProcessHeap(), 0, buf);
4093 /*****************************************************************************
4094 * WINSPOOL_EnumPrintersW
4096 * Implementation of EnumPrintersW
4098 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4099 DWORD dwLevel, LPBYTE lpbPrinters,
4100 DWORD cbBuf, LPDWORD lpdwNeeded,
4101 LPDWORD lpdwReturned)
4104 HKEY hkeyPrinters, hkeyPrinter;
4105 WCHAR PrinterName[255];
4106 DWORD needed = 0, number = 0;
4107 DWORD used, i, left;
4111 memset(lpbPrinters, 0, cbBuf);
4117 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4118 if(dwType == PRINTER_ENUM_DEFAULT)
4121 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4122 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4123 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4125 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4131 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4132 FIXME("dwType = %08x\n", dwType);
4133 SetLastError(ERROR_INVALID_FLAGS);
4137 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4139 ERR("Can't create Printers key\n");
4143 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4144 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4145 RegCloseKey(hkeyPrinters);
4146 ERR("Can't query Printers key\n");
4149 TRACE("Found %d printers\n", number);
4153 used = number * sizeof(PRINTER_INFO_1W);
4156 used = number * sizeof(PRINTER_INFO_2W);
4159 used = number * sizeof(PRINTER_INFO_4W);
4162 used = number * sizeof(PRINTER_INFO_5W);
4166 SetLastError(ERROR_INVALID_LEVEL);
4167 RegCloseKey(hkeyPrinters);
4170 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4172 for(i = 0; i < number; i++) {
4173 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4175 ERR("Can't enum key number %d\n", i);
4176 RegCloseKey(hkeyPrinters);
4179 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4180 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4182 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4183 RegCloseKey(hkeyPrinters);
4188 buf = lpbPrinters + used;
4189 left = cbBuf - used;
4197 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4200 if(pi) pi += sizeof(PRINTER_INFO_1W);
4203 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4206 if(pi) pi += sizeof(PRINTER_INFO_2W);
4209 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4212 if(pi) pi += sizeof(PRINTER_INFO_4W);
4215 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4218 if(pi) pi += sizeof(PRINTER_INFO_5W);
4221 ERR("Shouldn't be here!\n");
4222 RegCloseKey(hkeyPrinter);
4223 RegCloseKey(hkeyPrinters);
4226 RegCloseKey(hkeyPrinter);
4228 RegCloseKey(hkeyPrinters);
4235 memset(lpbPrinters, 0, cbBuf);
4236 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4240 *lpdwReturned = number;
4241 SetLastError(ERROR_SUCCESS);
4246 /******************************************************************
4247 * EnumPrintersW [WINSPOOL.@]
4249 * Enumerates the available printers, print servers and print
4250 * providers, depending on the specified flags, name and level.
4254 * If level is set to 1:
4255 * Returns an array of PRINTER_INFO_1 data structures in the
4256 * lpbPrinters buffer.
4258 * If level is set to 2:
4259 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4260 * Returns an array of PRINTER_INFO_2 data structures in the
4261 * lpbPrinters buffer. Note that according to MSDN also an
4262 * OpenPrinter should be performed on every remote printer.
4264 * If level is set to 4 (officially WinNT only):
4265 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4266 * Fast: Only the registry is queried to retrieve printer names,
4267 * no connection to the driver is made.
4268 * Returns an array of PRINTER_INFO_4 data structures in the
4269 * lpbPrinters buffer.
4271 * If level is set to 5 (officially WinNT4/Win9x only):
4272 * Fast: Only the registry is queried to retrieve printer names,
4273 * no connection to the driver is made.
4274 * Returns an array of PRINTER_INFO_5 data structures in the
4275 * lpbPrinters buffer.
4277 * If level set to 3 or 6+:
4278 * returns zero (failure!)
4280 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4284 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4285 * - Only levels 2, 4 and 5 are implemented at the moment.
4286 * - 16-bit printer drivers are not enumerated.
4287 * - Returned amount of bytes used/needed does not match the real Windoze
4288 * implementation (as in this implementation, all strings are part
4289 * of the buffer, whereas Win32 keeps them somewhere else)
4290 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4293 * - In a regular Wine installation, no registry settings for printers
4294 * exist, which makes this function return an empty list.
4296 BOOL WINAPI EnumPrintersW(
4297 DWORD dwType, /* [in] Types of print objects to enumerate */
4298 LPWSTR lpszName, /* [in] name of objects to enumerate */
4299 DWORD dwLevel, /* [in] type of printer info structure */
4300 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4301 DWORD cbBuf, /* [in] max size of buffer in bytes */
4302 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4303 LPDWORD lpdwReturned /* [out] number of entries returned */
4306 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4307 lpdwNeeded, lpdwReturned);
4310 /******************************************************************
4311 * EnumPrintersA [WINSPOOL.@]
4316 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4317 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4320 UNICODE_STRING pNameU;
4324 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4325 pPrinters, cbBuf, pcbNeeded, pcReturned);
4327 pNameW = asciitounicode(&pNameU, pName);
4329 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4330 MS Office need this */
4331 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4333 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4335 RtlFreeUnicodeString(&pNameU);
4337 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4339 HeapFree(GetProcessHeap(), 0, pPrintersW);
4343 /*****************************************************************************
4344 * WINSPOOL_GetDriverInfoFromReg [internal]
4346 * Enters the information from the registry into the DRIVER_INFO struct
4349 * zero if the printer driver does not exist in the registry
4350 * (only if Level > 1) otherwise nonzero
4352 static BOOL WINSPOOL_GetDriverInfoFromReg(
4355 const printenv_t * env,
4357 LPBYTE ptr, /* DRIVER_INFO */
4358 LPBYTE pDriverStrings, /* strings buffer */
4359 DWORD cbBuf, /* size of string buffer */
4360 LPDWORD pcbNeeded) /* space needed for str. */
4364 WCHAR driverdir[MAX_PATH];
4366 LPBYTE strPtr = pDriverStrings;
4367 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4369 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4370 debugstr_w(DriverName), env,
4371 Level, di, pDriverStrings, cbBuf);
4373 if (di) ZeroMemory(di, di_sizeof[Level]);
4375 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4376 if (*pcbNeeded <= cbBuf)
4377 strcpyW((LPWSTR)strPtr, DriverName);
4379 /* pName for level 1 has a different offset! */
4381 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4385 /* .cVersion and .pName for level > 1 */
4387 di->cVersion = env->driverversion;
4388 di->pName = (LPWSTR) strPtr;
4389 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4392 /* Reserve Space for the largest subdir and a Backslash*/
4393 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4394 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4395 /* Should never Fail */
4398 lstrcatW(driverdir, env->versionsubdir);
4399 lstrcatW(driverdir, backslashW);
4401 /* dirlen must not include the terminating zero */
4402 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4404 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4405 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4406 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4411 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4414 if (*pcbNeeded <= cbBuf) {
4415 lstrcpyW((LPWSTR)strPtr, env->envname);
4416 if (di) di->pEnvironment = (LPWSTR)strPtr;
4417 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4420 /* .pDriverPath is the Graphics rendering engine.
4421 The full Path is required to avoid a crash in some apps */
4422 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4424 if (*pcbNeeded <= cbBuf)
4425 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4427 if (di) di->pDriverPath = (LPWSTR)strPtr;
4428 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4431 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4432 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4434 if (*pcbNeeded <= cbBuf)
4435 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4437 if (di) di->pDataFile = (LPWSTR)strPtr;
4438 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4441 /* .pConfigFile is the Driver user Interface */
4442 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4444 if (*pcbNeeded <= cbBuf)
4445 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4447 if (di) di->pConfigFile = (LPWSTR)strPtr;
4448 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4452 RegCloseKey(hkeyDriver);
4453 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4458 RegCloseKey(hkeyDriver);
4459 FIXME("level 5: incomplete\n");
4464 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4466 if (*pcbNeeded <= cbBuf)
4467 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4469 if (di) di->pHelpFile = (LPWSTR)strPtr;
4470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4473 /* .pDependentFiles */
4474 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4476 if (*pcbNeeded <= cbBuf)
4477 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4479 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4480 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4482 else if (GetVersion() & 0x80000000) {
4483 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4484 size = 2 * sizeof(WCHAR);
4486 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4488 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4489 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4492 /* .pMonitorName is the optional Language Monitor */
4493 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4495 if (*pcbNeeded <= cbBuf)
4496 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4498 if (di) di->pMonitorName = (LPWSTR)strPtr;
4499 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4502 /* .pDefaultDataType */
4503 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4505 if(*pcbNeeded <= cbBuf)
4506 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4508 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4509 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4513 RegCloseKey(hkeyDriver);
4514 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4518 /* .pszzPreviousNames */
4519 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4521 if(*pcbNeeded <= cbBuf)
4522 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4524 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4525 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4529 RegCloseKey(hkeyDriver);
4530 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4534 /* support is missing, but not important enough for a FIXME */
4535 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4538 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4540 if(*pcbNeeded <= cbBuf)
4541 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4543 if (di) di->pszMfgName = (LPWSTR)strPtr;
4544 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4548 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4550 if(*pcbNeeded <= cbBuf)
4551 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4553 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4554 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4557 /* .pszHardwareID */
4558 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4560 if(*pcbNeeded <= cbBuf)
4561 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4563 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4564 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4568 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4570 if(*pcbNeeded <= cbBuf)
4571 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4573 if (di) di->pszProvider = (LPWSTR)strPtr;
4574 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4578 RegCloseKey(hkeyDriver);
4582 /* support is missing, but not important enough for a FIXME */
4583 TRACE("level 8: incomplete\n");
4585 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4586 RegCloseKey(hkeyDriver);
4590 /*****************************************************************************
4591 * GetPrinterDriverW [WINSPOOL.@]
4593 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4594 DWORD Level, LPBYTE pDriverInfo,
4595 DWORD cbBuf, LPDWORD pcbNeeded)
4598 WCHAR DriverName[100];
4599 DWORD ret, type, size, needed = 0;
4601 HKEY hkeyPrinter, hkeyDrivers;
4602 const printenv_t * env;
4604 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4605 Level,pDriverInfo,cbBuf, pcbNeeded);
4608 ZeroMemory(pDriverInfo, cbBuf);
4610 if (!(name = get_opened_printer_name(hPrinter))) {
4611 SetLastError(ERROR_INVALID_HANDLE);
4615 if (Level < 1 || Level == 7 || Level > 8) {
4616 SetLastError(ERROR_INVALID_LEVEL);
4620 env = validate_envW(pEnvironment);
4621 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4623 ret = open_printer_reg_key( name, &hkeyPrinter );
4626 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4627 SetLastError( ret );
4631 size = sizeof(DriverName);
4633 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4634 (LPBYTE)DriverName, &size);
4635 RegCloseKey(hkeyPrinter);
4636 if(ret != ERROR_SUCCESS) {
4637 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4641 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4643 ERR("Can't create Drivers key\n");
4647 size = di_sizeof[Level];
4648 if ((size <= cbBuf) && pDriverInfo)
4649 ptr = pDriverInfo + size;
4651 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4652 env, Level, pDriverInfo, ptr,
4653 (cbBuf < size) ? 0 : cbBuf - size,
4655 RegCloseKey(hkeyDrivers);
4659 RegCloseKey(hkeyDrivers);
4661 if(pcbNeeded) *pcbNeeded = size + needed;
4662 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4663 if(cbBuf >= size + needed) return TRUE;
4664 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4668 /*****************************************************************************
4669 * GetPrinterDriverA [WINSPOOL.@]
4671 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4672 DWORD Level, LPBYTE pDriverInfo,
4673 DWORD cbBuf, LPDWORD pcbNeeded)
4676 UNICODE_STRING pEnvW;
4682 ZeroMemory(pDriverInfo, cbBuf);
4683 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4686 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4687 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4690 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4692 HeapFree(GetProcessHeap(), 0, buf);
4694 RtlFreeUnicodeString(&pEnvW);
4698 /*****************************************************************************
4699 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4701 * Return the PATH for the Printer-Drivers (UNICODE)
4704 * pName [I] Servername (NT only) or NULL (local Computer)
4705 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4706 * Level [I] Structure-Level (must be 1)
4707 * pDriverDirectory [O] PTR to Buffer that receives the Result
4708 * cbBuf [I] Size of Buffer at pDriverDirectory
4709 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4710 * required for pDriverDirectory
4713 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4714 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4715 * if cbBuf is too small
4717 * Native Values returned in pDriverDirectory on Success:
4718 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4719 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4720 *| win9x(Windows 4.0): "%winsysdir%"
4722 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4725 *- Only NULL or "" is supported for pName
4728 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4729 DWORD Level, LPBYTE pDriverDirectory,
4730 DWORD cbBuf, LPDWORD pcbNeeded)
4732 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4733 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4735 if ((backend == NULL) && !load_backend()) return FALSE;
4738 /* (Level != 1) is ignored in win9x */
4739 SetLastError(ERROR_INVALID_LEVEL);
4742 if (pcbNeeded == NULL) {
4743 /* (pcbNeeded == NULL) is ignored in win9x */
4744 SetLastError(RPC_X_NULL_REF_POINTER);
4748 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4749 pDriverDirectory, cbBuf, pcbNeeded);
4754 /*****************************************************************************
4755 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4757 * Return the PATH for the Printer-Drivers (ANSI)
4759 * See GetPrinterDriverDirectoryW.
4762 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4765 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4766 DWORD Level, LPBYTE pDriverDirectory,
4767 DWORD cbBuf, LPDWORD pcbNeeded)
4769 UNICODE_STRING nameW, environmentW;
4772 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4773 WCHAR *driverDirectoryW = NULL;
4775 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4776 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4778 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4780 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4781 else nameW.Buffer = NULL;
4782 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4783 else environmentW.Buffer = NULL;
4785 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4786 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4789 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4790 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4792 *pcbNeeded = needed;
4793 ret = (needed <= cbBuf) ? TRUE : FALSE;
4795 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4797 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4799 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4800 RtlFreeUnicodeString(&environmentW);
4801 RtlFreeUnicodeString(&nameW);
4806 /*****************************************************************************
4807 * AddPrinterDriverA [WINSPOOL.@]
4809 * See AddPrinterDriverW.
4812 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4814 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4815 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4818 /******************************************************************************
4819 * AddPrinterDriverW (WINSPOOL.@)
4821 * Install a Printer Driver
4824 * pName [I] Servername or NULL (local Computer)
4825 * level [I] Level for the supplied DRIVER_INFO_*W struct
4826 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4833 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4835 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4836 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4839 /*****************************************************************************
4840 * AddPrintProcessorA [WINSPOOL.@]
4842 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4843 LPSTR pPrintProcessorName)
4845 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4846 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4850 /*****************************************************************************
4851 * AddPrintProcessorW [WINSPOOL.@]
4853 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4854 LPWSTR pPrintProcessorName)
4856 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4857 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4861 /*****************************************************************************
4862 * AddPrintProvidorA [WINSPOOL.@]
4864 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4866 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4870 /*****************************************************************************
4871 * AddPrintProvidorW [WINSPOOL.@]
4873 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4875 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4879 /*****************************************************************************
4880 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4882 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4883 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4885 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4886 pDevModeOutput, pDevModeInput);
4890 /*****************************************************************************
4891 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4893 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4894 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4896 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4897 pDevModeOutput, pDevModeInput);
4901 /*****************************************************************************
4902 * PrinterProperties [WINSPOOL.@]
4904 * Displays a dialog to set the properties of the printer.
4907 * nonzero on success or zero on failure
4910 * implemented as stub only
4912 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4913 HANDLE hPrinter /* [in] handle to printer object */
4915 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4920 /*****************************************************************************
4921 * EnumJobsA [WINSPOOL.@]
4924 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4925 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4928 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4929 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4931 if(pcbNeeded) *pcbNeeded = 0;
4932 if(pcReturned) *pcReturned = 0;
4937 /*****************************************************************************
4938 * EnumJobsW [WINSPOOL.@]
4941 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4942 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4945 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4946 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4948 if(pcbNeeded) *pcbNeeded = 0;
4949 if(pcReturned) *pcReturned = 0;
4953 /*****************************************************************************
4954 * WINSPOOL_EnumPrinterDrivers [internal]
4956 * Delivers information about all printer drivers installed on the
4957 * localhost or a given server
4960 * nonzero on success or zero on failure. If the buffer for the returned
4961 * information is too small the function will return an error
4964 * - only implemented for localhost, foreign hosts will return an error
4966 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4967 DWORD Level, LPBYTE pDriverInfo,
4969 DWORD cbBuf, LPDWORD pcbNeeded,
4970 LPDWORD pcFound, DWORD data_offset)
4974 const printenv_t * env;
4976 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4977 debugstr_w(pName), debugstr_w(pEnvironment),
4978 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4980 env = validate_envW(pEnvironment);
4981 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4985 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4987 ERR("Can't open Drivers key\n");
4991 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4992 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4993 RegCloseKey(hkeyDrivers);
4994 ERR("Can't query Drivers key\n");
4997 TRACE("Found %d Drivers\n", *pcFound);
4999 /* get size of single struct
5000 * unicode and ascii structure have the same size
5002 size = di_sizeof[Level];
5004 if (data_offset == 0)
5005 data_offset = size * (*pcFound);
5006 *pcbNeeded = data_offset;
5008 for( i = 0; i < *pcFound; i++) {
5009 WCHAR DriverNameW[255];
5010 PBYTE table_ptr = NULL;
5011 PBYTE data_ptr = NULL;
5014 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5016 ERR("Can't enum key number %d\n", i);
5017 RegCloseKey(hkeyDrivers);
5021 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5022 table_ptr = pDriverInfo + (driver_index + i) * size;
5023 if (pDriverInfo && *pcbNeeded <= cbBuf)
5024 data_ptr = pDriverInfo + *pcbNeeded;
5026 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5027 env, Level, table_ptr, data_ptr,
5028 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5030 RegCloseKey(hkeyDrivers);
5034 *pcbNeeded += needed;
5037 RegCloseKey(hkeyDrivers);
5039 if(cbBuf < *pcbNeeded){
5040 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5047 /*****************************************************************************
5048 * EnumPrinterDriversW [WINSPOOL.@]
5050 * see function EnumPrinterDrivers for RETURNS, BUGS
5052 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5053 LPBYTE pDriverInfo, DWORD cbBuf,
5054 LPDWORD pcbNeeded, LPDWORD pcReturned)
5056 static const WCHAR allW[] = {'a','l','l',0};
5060 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5062 SetLastError(RPC_X_NULL_REF_POINTER);
5066 /* check for local drivers */
5067 if((pName) && (pName[0])) {
5068 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5069 SetLastError(ERROR_ACCESS_DENIED);
5073 /* check input parameter */
5074 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5075 SetLastError(ERROR_INVALID_LEVEL);
5079 if(pDriverInfo && cbBuf > 0)
5080 memset( pDriverInfo, 0, cbBuf);
5082 /* Exception: pull all printers */
5083 if (pEnvironment && !strcmpW(pEnvironment, allW))
5085 DWORD i, needed, bufsize = cbBuf;
5086 DWORD total_needed = 0;
5087 DWORD total_found = 0;
5090 /* Precompute the overall total; we need this to know
5091 where pointers end and data begins (i.e. data_offset) */
5092 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5095 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5096 NULL, 0, 0, &needed, &found, 0);
5097 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5098 total_needed += needed;
5099 total_found += found;
5102 data_offset = di_sizeof[Level] * total_found;
5107 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5110 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5111 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5112 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5114 *pcReturned += found;
5115 *pcbNeeded = needed;
5116 data_offset = needed;
5117 total_found += found;
5122 /* Normal behavior */
5123 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5124 0, cbBuf, pcbNeeded, &found, 0);
5126 *pcReturned = found;
5131 /*****************************************************************************
5132 * EnumPrinterDriversA [WINSPOOL.@]
5134 * see function EnumPrinterDrivers for RETURNS, BUGS
5136 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5137 LPBYTE pDriverInfo, DWORD cbBuf,
5138 LPDWORD pcbNeeded, LPDWORD pcReturned)
5141 UNICODE_STRING pNameW, pEnvironmentW;
5142 PWSTR pwstrNameW, pwstrEnvironmentW;
5146 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5148 pwstrNameW = asciitounicode(&pNameW, pName);
5149 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5151 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5152 buf, cbBuf, pcbNeeded, pcReturned);
5154 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5156 HeapFree(GetProcessHeap(), 0, buf);
5158 RtlFreeUnicodeString(&pNameW);
5159 RtlFreeUnicodeString(&pEnvironmentW);
5164 /******************************************************************************
5165 * EnumPortsA (WINSPOOL.@)
5170 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5171 LPDWORD pcbNeeded, LPDWORD pcReturned)
5174 LPBYTE bufferW = NULL;
5175 LPWSTR nameW = NULL;
5177 DWORD numentries = 0;
5180 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5181 cbBuf, pcbNeeded, pcReturned);
5183 /* convert servername to unicode */
5185 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5186 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5187 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5189 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5190 needed = cbBuf * sizeof(WCHAR);
5191 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5192 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5194 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5195 if (pcbNeeded) needed = *pcbNeeded;
5196 /* HeapReAlloc return NULL, when bufferW was NULL */
5197 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5198 HeapAlloc(GetProcessHeap(), 0, needed);
5200 /* Try again with the large Buffer */
5201 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5203 needed = pcbNeeded ? *pcbNeeded : 0;
5204 numentries = pcReturned ? *pcReturned : 0;
5207 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5208 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5211 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5212 DWORD entrysize = 0;
5215 LPPORT_INFO_2W pi2w;
5216 LPPORT_INFO_2A pi2a;
5219 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5221 /* First pass: calculate the size for all Entries */
5222 pi2w = (LPPORT_INFO_2W) bufferW;
5223 pi2a = (LPPORT_INFO_2A) pPorts;
5225 while (index < numentries) {
5227 needed += entrysize; /* PORT_INFO_?A */
5228 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5230 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5231 NULL, 0, NULL, NULL);
5233 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5234 NULL, 0, NULL, NULL);
5235 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5236 NULL, 0, NULL, NULL);
5238 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5239 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5240 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5243 /* check for errors and quit on failure */
5244 if (cbBuf < needed) {
5245 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5249 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5250 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5251 cbBuf -= len ; /* free Bytes in the user-Buffer */
5252 pi2w = (LPPORT_INFO_2W) bufferW;
5253 pi2a = (LPPORT_INFO_2A) pPorts;
5255 /* Second Pass: Fill the User Buffer (if we have one) */
5256 while ((index < numentries) && pPorts) {
5258 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5259 pi2a->pPortName = ptr;
5260 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5261 ptr, cbBuf , NULL, NULL);
5265 pi2a->pMonitorName = ptr;
5266 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5267 ptr, cbBuf, NULL, NULL);
5271 pi2a->pDescription = ptr;
5272 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5273 ptr, cbBuf, NULL, NULL);
5277 pi2a->fPortType = pi2w->fPortType;
5278 pi2a->Reserved = 0; /* documented: "must be zero" */
5281 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5282 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5283 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5288 if (pcbNeeded) *pcbNeeded = needed;
5289 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5291 HeapFree(GetProcessHeap(), 0, nameW);
5292 HeapFree(GetProcessHeap(), 0, bufferW);
5294 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5295 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5301 /******************************************************************************
5302 * EnumPortsW (WINSPOOL.@)
5304 * Enumerate available Ports
5307 * pName [I] Servername or NULL (local Computer)
5308 * Level [I] Structure-Level (1 or 2)
5309 * pPorts [O] PTR to Buffer that receives the Result
5310 * cbBuf [I] Size of Buffer at pPorts
5311 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5312 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5316 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5319 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5322 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5323 cbBuf, pcbNeeded, pcReturned);
5325 if ((backend == NULL) && !load_backend()) return FALSE;
5327 /* Level is not checked in win9x */
5328 if (!Level || (Level > 2)) {
5329 WARN("level (%d) is ignored in win9x\n", Level);
5330 SetLastError(ERROR_INVALID_LEVEL);
5333 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5334 SetLastError(RPC_X_NULL_REF_POINTER);
5338 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5341 /******************************************************************************
5342 * GetDefaultPrinterW (WINSPOOL.@)
5345 * This function must read the value from data 'device' of key
5346 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5348 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5352 WCHAR *buffer, *ptr;
5356 SetLastError(ERROR_INVALID_PARAMETER);
5360 /* make the buffer big enough for the stuff from the profile/registry,
5361 * the content must fit into the local buffer to compute the correct
5362 * size even if the extern buffer is too small or not given.
5363 * (20 for ,driver,port) */
5365 len = max(100, (insize + 20));
5366 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5368 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5370 SetLastError (ERROR_FILE_NOT_FOUND);
5374 TRACE("%s\n", debugstr_w(buffer));
5376 if ((ptr = strchrW(buffer, ',')) == NULL)
5378 SetLastError(ERROR_INVALID_NAME);
5384 *namesize = strlenW(buffer) + 1;
5385 if(!name || (*namesize > insize))
5387 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5391 strcpyW(name, buffer);
5394 HeapFree( GetProcessHeap(), 0, buffer);
5399 /******************************************************************************
5400 * GetDefaultPrinterA (WINSPOOL.@)
5402 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5406 WCHAR *bufferW = NULL;
5410 SetLastError(ERROR_INVALID_PARAMETER);
5414 if(name && *namesize) {
5416 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5419 if(!GetDefaultPrinterW( bufferW, namesize)) {
5424 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5428 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5431 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5434 HeapFree( GetProcessHeap(), 0, bufferW);
5439 /******************************************************************************
5440 * SetDefaultPrinterW (WINSPOOL.204)
5442 * Set the Name of the Default Printer
5445 * pszPrinter [I] Name of the Printer or NULL
5452 * When the Parameter is NULL or points to an Empty String and
5453 * a Default Printer was already present, then this Function changes nothing.
5454 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5455 * the First enumerated local Printer is used.
5458 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5460 WCHAR default_printer[MAX_PATH];
5461 LPWSTR buffer = NULL;
5467 TRACE("(%s)\n", debugstr_w(pszPrinter));
5468 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5470 default_printer[0] = '\0';
5471 size = sizeof(default_printer)/sizeof(WCHAR);
5473 /* if we have a default Printer, do nothing. */
5474 if (GetDefaultPrinterW(default_printer, &size))
5478 /* we have no default Printer: search local Printers and use the first */
5479 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5481 default_printer[0] = '\0';
5482 size = sizeof(default_printer)/sizeof(WCHAR);
5483 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5485 pszPrinter = default_printer;
5486 TRACE("using %s\n", debugstr_w(pszPrinter));
5491 if (pszPrinter == NULL) {
5492 TRACE("no local printer found\n");
5493 SetLastError(ERROR_FILE_NOT_FOUND);
5498 /* "pszPrinter" is never empty or NULL here. */
5499 namelen = lstrlenW(pszPrinter);
5500 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5501 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5503 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5504 HeapFree(GetProcessHeap(), 0, buffer);
5505 SetLastError(ERROR_FILE_NOT_FOUND);
5509 /* read the devices entry for the printer (driver,port) to build the string for the
5510 default device entry (printer,driver,port) */
5511 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5512 buffer[namelen] = ',';
5513 namelen++; /* move index to the start of the driver */
5515 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5516 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5518 TRACE("set device to %s\n", debugstr_w(buffer));
5520 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5521 TRACE("failed to set the device entry: %d\n", GetLastError());
5522 lres = ERROR_INVALID_PRINTER_NAME;
5525 /* remove the next section, when INIFileMapping is implemented */
5528 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5529 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5536 if (lres != ERROR_FILE_NOT_FOUND)
5537 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5539 SetLastError(ERROR_INVALID_PRINTER_NAME);
5543 HeapFree(GetProcessHeap(), 0, buffer);
5544 return (lres == ERROR_SUCCESS);
5547 /******************************************************************************
5548 * SetDefaultPrinterA (WINSPOOL.202)
5550 * See SetDefaultPrinterW.
5553 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5555 LPWSTR bufferW = NULL;
5558 TRACE("(%s)\n", debugstr_a(pszPrinter));
5560 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5561 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5562 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5564 res = SetDefaultPrinterW(bufferW);
5565 HeapFree(GetProcessHeap(), 0, bufferW);
5569 /******************************************************************************
5570 * SetPrinterDataExA (WINSPOOL.@)
5572 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5573 LPCSTR pValueName, DWORD Type,
5574 LPBYTE pData, DWORD cbData)
5576 HKEY hkeyPrinter, hkeySubkey;
5579 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5580 debugstr_a(pValueName), Type, pData, cbData);
5582 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5586 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5588 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5589 RegCloseKey(hkeyPrinter);
5592 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5593 RegCloseKey(hkeySubkey);
5594 RegCloseKey(hkeyPrinter);
5598 /******************************************************************************
5599 * SetPrinterDataExW (WINSPOOL.@)
5601 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5602 LPCWSTR pValueName, DWORD Type,
5603 LPBYTE pData, DWORD cbData)
5605 HKEY hkeyPrinter, hkeySubkey;
5608 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5609 debugstr_w(pValueName), Type, pData, cbData);
5611 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5615 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5617 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5618 RegCloseKey(hkeyPrinter);
5621 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5622 RegCloseKey(hkeySubkey);
5623 RegCloseKey(hkeyPrinter);
5627 /******************************************************************************
5628 * SetPrinterDataA (WINSPOOL.@)
5630 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5631 LPBYTE pData, DWORD cbData)
5633 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5637 /******************************************************************************
5638 * SetPrinterDataW (WINSPOOL.@)
5640 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5641 LPBYTE pData, DWORD cbData)
5643 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5647 /******************************************************************************
5648 * GetPrinterDataExA (WINSPOOL.@)
5650 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5651 LPCSTR pValueName, LPDWORD pType,
5652 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5654 opened_printer_t *printer;
5655 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5658 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5659 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5661 printer = get_opened_printer(hPrinter);
5662 if(!printer) return ERROR_INVALID_HANDLE;
5664 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5665 if (ret) return ret;
5667 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5669 if (printer->name) {
5671 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5673 RegCloseKey(hkeyPrinters);
5676 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5677 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5678 RegCloseKey(hkeyPrinter);
5679 RegCloseKey(hkeyPrinters);
5684 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5685 0, pType, pData, pcbNeeded);
5687 if (!ret && !pData) ret = ERROR_MORE_DATA;
5689 RegCloseKey(hkeySubkey);
5690 RegCloseKey(hkeyPrinter);
5691 RegCloseKey(hkeyPrinters);
5693 TRACE("--> %d\n", ret);
5697 /******************************************************************************
5698 * GetPrinterDataExW (WINSPOOL.@)
5700 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5701 LPCWSTR pValueName, LPDWORD pType,
5702 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5704 opened_printer_t *printer;
5705 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5708 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5709 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5711 printer = get_opened_printer(hPrinter);
5712 if(!printer) return ERROR_INVALID_HANDLE;
5714 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5715 if (ret) return ret;
5717 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5719 if (printer->name) {
5721 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5723 RegCloseKey(hkeyPrinters);
5726 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5727 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5728 RegCloseKey(hkeyPrinter);
5729 RegCloseKey(hkeyPrinters);
5734 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5735 0, pType, pData, pcbNeeded);
5737 if (!ret && !pData) ret = ERROR_MORE_DATA;
5739 RegCloseKey(hkeySubkey);
5740 RegCloseKey(hkeyPrinter);
5741 RegCloseKey(hkeyPrinters);
5743 TRACE("--> %d\n", ret);
5747 /******************************************************************************
5748 * GetPrinterDataA (WINSPOOL.@)
5750 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5751 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5753 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5754 pData, nSize, pcbNeeded);
5757 /******************************************************************************
5758 * GetPrinterDataW (WINSPOOL.@)
5760 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5761 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5763 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5764 pData, nSize, pcbNeeded);
5767 /*******************************************************************************
5768 * EnumPrinterDataExW [WINSPOOL.@]
5770 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5771 LPBYTE pEnumValues, DWORD cbEnumValues,
5772 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5774 HKEY hkPrinter, hkSubKey;
5775 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5776 cbValueNameLen, cbMaxValueLen, cbValueLen,
5781 PPRINTER_ENUM_VALUESW ppev;
5783 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5785 if (pKeyName == NULL || *pKeyName == 0)
5786 return ERROR_INVALID_PARAMETER;
5788 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5789 if (ret != ERROR_SUCCESS)
5791 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5796 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5797 if (ret != ERROR_SUCCESS)
5799 r = RegCloseKey (hkPrinter);
5800 if (r != ERROR_SUCCESS)
5801 WARN ("RegCloseKey returned %i\n", r);
5802 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5803 debugstr_w (pKeyName), ret);
5807 ret = RegCloseKey (hkPrinter);
5808 if (ret != ERROR_SUCCESS)
5810 ERR ("RegCloseKey returned %i\n", ret);
5811 r = RegCloseKey (hkSubKey);
5812 if (r != ERROR_SUCCESS)
5813 WARN ("RegCloseKey returned %i\n", r);
5817 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5818 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5819 if (ret != ERROR_SUCCESS)
5821 r = RegCloseKey (hkSubKey);
5822 if (r != ERROR_SUCCESS)
5823 WARN ("RegCloseKey returned %i\n", r);
5824 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5828 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5829 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5831 if (cValues == 0) /* empty key */
5833 r = RegCloseKey (hkSubKey);
5834 if (r != ERROR_SUCCESS)
5835 WARN ("RegCloseKey returned %i\n", r);
5836 *pcbEnumValues = *pnEnumValues = 0;
5837 return ERROR_SUCCESS;
5840 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5842 hHeap = GetProcessHeap ();
5845 ERR ("GetProcessHeap failed\n");
5846 r = RegCloseKey (hkSubKey);
5847 if (r != ERROR_SUCCESS)
5848 WARN ("RegCloseKey returned %i\n", r);
5849 return ERROR_OUTOFMEMORY;
5852 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5853 if (lpValueName == NULL)
5855 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5856 r = RegCloseKey (hkSubKey);
5857 if (r != ERROR_SUCCESS)
5858 WARN ("RegCloseKey returned %i\n", r);
5859 return ERROR_OUTOFMEMORY;
5862 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5863 if (lpValue == NULL)
5865 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5866 if (HeapFree (hHeap, 0, lpValueName) == 0)
5867 WARN ("HeapFree failed with code %i\n", GetLastError ());
5868 r = RegCloseKey (hkSubKey);
5869 if (r != ERROR_SUCCESS)
5870 WARN ("RegCloseKey returned %i\n", r);
5871 return ERROR_OUTOFMEMORY;
5874 TRACE ("pass 1: calculating buffer required for all names and values\n");
5876 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5878 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5880 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5882 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5883 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5884 NULL, NULL, lpValue, &cbValueLen);
5885 if (ret != ERROR_SUCCESS)
5887 if (HeapFree (hHeap, 0, lpValue) == 0)
5888 WARN ("HeapFree failed with code %i\n", GetLastError ());
5889 if (HeapFree (hHeap, 0, lpValueName) == 0)
5890 WARN ("HeapFree failed with code %i\n", GetLastError ());
5891 r = RegCloseKey (hkSubKey);
5892 if (r != ERROR_SUCCESS)
5893 WARN ("RegCloseKey returned %i\n", r);
5894 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5898 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5899 debugstr_w (lpValueName), dwIndex,
5900 cbValueNameLen + 1, cbValueLen);
5902 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5903 cbBufSize += cbValueLen;
5906 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5908 *pcbEnumValues = cbBufSize;
5909 *pnEnumValues = cValues;
5911 if (cbEnumValues < cbBufSize) /* buffer too small */
5913 if (HeapFree (hHeap, 0, lpValue) == 0)
5914 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 if (HeapFree (hHeap, 0, lpValueName) == 0)
5916 WARN ("HeapFree failed with code %i\n", GetLastError ());
5917 r = RegCloseKey (hkSubKey);
5918 if (r != ERROR_SUCCESS)
5919 WARN ("RegCloseKey returned %i\n", r);
5920 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5921 return ERROR_MORE_DATA;
5924 TRACE ("pass 2: copying all names and values to buffer\n");
5926 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5927 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5929 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5931 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5932 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5933 NULL, &dwType, lpValue, &cbValueLen);
5934 if (ret != ERROR_SUCCESS)
5936 if (HeapFree (hHeap, 0, lpValue) == 0)
5937 WARN ("HeapFree failed with code %i\n", GetLastError ());
5938 if (HeapFree (hHeap, 0, lpValueName) == 0)
5939 WARN ("HeapFree failed with code %i\n", GetLastError ());
5940 r = RegCloseKey (hkSubKey);
5941 if (r != ERROR_SUCCESS)
5942 WARN ("RegCloseKey returned %i\n", r);
5943 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5947 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5948 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5949 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5950 pEnumValues += cbValueNameLen;
5952 /* return # of *bytes* (including trailing \0), not # of chars */
5953 ppev[dwIndex].cbValueName = cbValueNameLen;
5955 ppev[dwIndex].dwType = dwType;
5957 memcpy (pEnumValues, lpValue, cbValueLen);
5958 ppev[dwIndex].pData = pEnumValues;
5959 pEnumValues += cbValueLen;
5961 ppev[dwIndex].cbData = cbValueLen;
5963 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5964 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5967 if (HeapFree (hHeap, 0, lpValue) == 0)
5969 ret = GetLastError ();
5970 ERR ("HeapFree failed with code %i\n", ret);
5971 if (HeapFree (hHeap, 0, lpValueName) == 0)
5972 WARN ("HeapFree failed with code %i\n", GetLastError ());
5973 r = RegCloseKey (hkSubKey);
5974 if (r != ERROR_SUCCESS)
5975 WARN ("RegCloseKey returned %i\n", r);
5979 if (HeapFree (hHeap, 0, lpValueName) == 0)
5981 ret = GetLastError ();
5982 ERR ("HeapFree failed with code %i\n", ret);
5983 r = RegCloseKey (hkSubKey);
5984 if (r != ERROR_SUCCESS)
5985 WARN ("RegCloseKey returned %i\n", r);
5989 ret = RegCloseKey (hkSubKey);
5990 if (ret != ERROR_SUCCESS)
5992 ERR ("RegCloseKey returned %i\n", ret);
5996 return ERROR_SUCCESS;
5999 /*******************************************************************************
6000 * EnumPrinterDataExA [WINSPOOL.@]
6002 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6003 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6004 * what Windows 2000 SP1 does.
6007 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6008 LPBYTE pEnumValues, DWORD cbEnumValues,
6009 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6013 DWORD ret, dwIndex, dwBufSize;
6017 TRACE ("%p %s\n", hPrinter, pKeyName);
6019 if (pKeyName == NULL || *pKeyName == 0)
6020 return ERROR_INVALID_PARAMETER;
6022 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6025 ret = GetLastError ();
6026 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6030 hHeap = GetProcessHeap ();
6033 ERR ("GetProcessHeap failed\n");
6034 return ERROR_OUTOFMEMORY;
6037 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6038 if (pKeyNameW == NULL)
6040 ERR ("Failed to allocate %i bytes from process heap\n",
6041 (LONG)(len * sizeof (WCHAR)));
6042 return ERROR_OUTOFMEMORY;
6045 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6047 ret = GetLastError ();
6048 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6049 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6050 WARN ("HeapFree failed with code %i\n", GetLastError ());
6054 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6055 pcbEnumValues, pnEnumValues);
6056 if (ret != ERROR_SUCCESS)
6058 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6059 WARN ("HeapFree failed with code %i\n", GetLastError ());
6060 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6064 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6066 ret = GetLastError ();
6067 ERR ("HeapFree failed with code %i\n", ret);
6071 if (*pnEnumValues == 0) /* empty key */
6072 return ERROR_SUCCESS;
6075 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6077 PPRINTER_ENUM_VALUESW ppev =
6078 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6080 if (dwBufSize < ppev->cbValueName)
6081 dwBufSize = ppev->cbValueName;
6083 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6084 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6085 dwBufSize = ppev->cbData;
6088 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6090 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6091 if (pBuffer == NULL)
6093 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6094 return ERROR_OUTOFMEMORY;
6097 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6099 PPRINTER_ENUM_VALUESW ppev =
6100 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6102 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6103 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6107 ret = GetLastError ();
6108 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6109 if (HeapFree (hHeap, 0, pBuffer) == 0)
6110 WARN ("HeapFree failed with code %i\n", GetLastError ());
6114 memcpy (ppev->pValueName, pBuffer, len);
6116 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6118 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6119 ppev->dwType != REG_MULTI_SZ)
6122 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6123 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6126 ret = GetLastError ();
6127 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6128 if (HeapFree (hHeap, 0, pBuffer) == 0)
6129 WARN ("HeapFree failed with code %i\n", GetLastError ());
6133 memcpy (ppev->pData, pBuffer, len);
6135 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6136 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6139 if (HeapFree (hHeap, 0, pBuffer) == 0)
6141 ret = GetLastError ();
6142 ERR ("HeapFree failed with code %i\n", ret);
6146 return ERROR_SUCCESS;
6149 /******************************************************************************
6150 * AbortPrinter (WINSPOOL.@)
6152 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6154 FIXME("(%p), stub!\n", hPrinter);
6158 /******************************************************************************
6159 * AddPortA (WINSPOOL.@)
6164 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6166 LPWSTR nameW = NULL;
6167 LPWSTR monitorW = NULL;
6171 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6174 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6175 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6176 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6180 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6181 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6182 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6184 res = AddPortW(nameW, hWnd, monitorW);
6185 HeapFree(GetProcessHeap(), 0, nameW);
6186 HeapFree(GetProcessHeap(), 0, monitorW);
6190 /******************************************************************************
6191 * AddPortW (WINSPOOL.@)
6193 * Add a Port for a specific Monitor
6196 * pName [I] Servername or NULL (local Computer)
6197 * hWnd [I] Handle to parent Window for the Dialog-Box
6198 * pMonitorName [I] Name of the Monitor that manage the Port
6205 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6207 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6209 if ((backend == NULL) && !load_backend()) return FALSE;
6211 if (!pMonitorName) {
6212 SetLastError(RPC_X_NULL_REF_POINTER);
6216 return backend->fpAddPort(pName, hWnd, pMonitorName);
6219 /******************************************************************************
6220 * AddPortExA (WINSPOOL.@)
6225 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6228 PORT_INFO_2A * pi2A;
6229 LPWSTR nameW = NULL;
6230 LPWSTR monitorW = NULL;
6234 pi2A = (PORT_INFO_2A *) pBuffer;
6236 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6237 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6239 if ((level < 1) || (level > 2)) {
6240 SetLastError(ERROR_INVALID_LEVEL);
6245 SetLastError(ERROR_INVALID_PARAMETER);
6250 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6251 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6252 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6256 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6257 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6258 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6261 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6263 if (pi2A->pPortName) {
6264 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6265 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6266 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6270 if (pi2A->pMonitorName) {
6271 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6272 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6273 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6276 if (pi2A->pDescription) {
6277 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6278 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6279 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6281 pi2W.fPortType = pi2A->fPortType;
6282 pi2W.Reserved = pi2A->Reserved;
6285 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6287 HeapFree(GetProcessHeap(), 0, nameW);
6288 HeapFree(GetProcessHeap(), 0, monitorW);
6289 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6290 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6291 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6296 /******************************************************************************
6297 * AddPortExW (WINSPOOL.@)
6299 * Add a Port for a specific Monitor, without presenting a user interface
6302 * pName [I] Servername or NULL (local Computer)
6303 * level [I] Structure-Level (1 or 2) for pBuffer
6304 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6305 * pMonitorName [I] Name of the Monitor that manage the Port
6312 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6316 pi2 = (PORT_INFO_2W *) pBuffer;
6318 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6319 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6320 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6321 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6323 if ((backend == NULL) && !load_backend()) return FALSE;
6325 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6326 SetLastError(ERROR_INVALID_PARAMETER);
6330 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6333 /******************************************************************************
6334 * AddPrinterConnectionA (WINSPOOL.@)
6336 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6338 FIXME("%s\n", debugstr_a(pName));
6342 /******************************************************************************
6343 * AddPrinterConnectionW (WINSPOOL.@)
6345 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6347 FIXME("%s\n", debugstr_w(pName));
6351 /******************************************************************************
6352 * AddPrinterDriverExW (WINSPOOL.@)
6354 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6357 * pName [I] Servername or NULL (local Computer)
6358 * level [I] Level for the supplied DRIVER_INFO_*W struct
6359 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6360 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6367 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6369 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6371 if ((backend == NULL) && !load_backend()) return FALSE;
6373 if (level < 2 || level == 5 || level == 7 || level > 8) {
6374 SetLastError(ERROR_INVALID_LEVEL);
6379 SetLastError(ERROR_INVALID_PARAMETER);
6383 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6386 /******************************************************************************
6387 * AddPrinterDriverExA (WINSPOOL.@)
6389 * See AddPrinterDriverExW.
6392 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6394 DRIVER_INFO_8A *diA;
6396 LPWSTR nameW = NULL;
6401 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6403 diA = (DRIVER_INFO_8A *) pDriverInfo;
6404 ZeroMemory(&diW, sizeof(diW));
6406 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6407 SetLastError(ERROR_INVALID_LEVEL);
6412 SetLastError(ERROR_INVALID_PARAMETER);
6416 /* convert servername to unicode */
6418 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6419 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6420 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6424 diW.cVersion = diA->cVersion;
6427 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6428 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6429 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6432 if (diA->pEnvironment) {
6433 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6434 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6435 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6438 if (diA->pDriverPath) {
6439 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6440 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6441 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6444 if (diA->pDataFile) {
6445 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6446 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6447 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6450 if (diA->pConfigFile) {
6451 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6452 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6453 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6456 if ((Level > 2) && diA->pDependentFiles) {
6457 lenA = multi_sz_lenA(diA->pDependentFiles);
6458 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6459 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6460 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6463 if ((Level > 2) && diA->pMonitorName) {
6464 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6465 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6466 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6469 if ((Level > 3) && diA->pDefaultDataType) {
6470 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6471 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6472 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6475 if ((Level > 3) && diA->pszzPreviousNames) {
6476 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6477 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6478 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6479 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6482 if ((Level > 5) && diA->pszMfgName) {
6483 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6484 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6485 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6488 if ((Level > 5) && diA->pszOEMUrl) {
6489 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6490 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6491 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6494 if ((Level > 5) && diA->pszHardwareID) {
6495 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6496 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6497 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6500 if ((Level > 5) && diA->pszProvider) {
6501 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6502 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6503 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6507 FIXME("level %u is incomplete\n", Level);
6510 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6511 TRACE("got %u with %u\n", res, GetLastError());
6512 HeapFree(GetProcessHeap(), 0, nameW);
6513 HeapFree(GetProcessHeap(), 0, diW.pName);
6514 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6515 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6516 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6517 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6518 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6519 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6520 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6521 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6522 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6523 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6524 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6525 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6527 TRACE("=> %u with %u\n", res, GetLastError());
6531 /******************************************************************************
6532 * ConfigurePortA (WINSPOOL.@)
6534 * See ConfigurePortW.
6537 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6539 LPWSTR nameW = NULL;
6540 LPWSTR portW = NULL;
6544 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6546 /* convert servername to unicode */
6548 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6549 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6550 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6553 /* convert portname to unicode */
6555 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6556 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6557 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6560 res = ConfigurePortW(nameW, hWnd, portW);
6561 HeapFree(GetProcessHeap(), 0, nameW);
6562 HeapFree(GetProcessHeap(), 0, portW);
6566 /******************************************************************************
6567 * ConfigurePortW (WINSPOOL.@)
6569 * Display the Configuration-Dialog for a specific Port
6572 * pName [I] Servername or NULL (local Computer)
6573 * hWnd [I] Handle to parent Window for the Dialog-Box
6574 * pPortName [I] Name of the Port, that should be configured
6581 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6584 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6586 if ((backend == NULL) && !load_backend()) return FALSE;
6589 SetLastError(RPC_X_NULL_REF_POINTER);
6593 return backend->fpConfigurePort(pName, hWnd, pPortName);
6596 /******************************************************************************
6597 * ConnectToPrinterDlg (WINSPOOL.@)
6599 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6601 FIXME("%p %x\n", hWnd, Flags);
6605 /******************************************************************************
6606 * DeletePrinterConnectionA (WINSPOOL.@)
6608 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6610 FIXME("%s\n", debugstr_a(pName));
6614 /******************************************************************************
6615 * DeletePrinterConnectionW (WINSPOOL.@)
6617 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6619 FIXME("%s\n", debugstr_w(pName));
6623 /******************************************************************************
6624 * DeletePrinterDriverExW (WINSPOOL.@)
6626 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6627 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6632 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6633 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6635 if(pName && pName[0])
6637 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6638 SetLastError(ERROR_INVALID_PARAMETER);
6644 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6645 SetLastError(ERROR_INVALID_PARAMETER);
6649 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6653 ERR("Can't open drivers key\n");
6657 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6660 RegCloseKey(hkey_drivers);
6665 /******************************************************************************
6666 * DeletePrinterDriverExA (WINSPOOL.@)
6668 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6669 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6671 UNICODE_STRING NameW, EnvW, DriverW;
6674 asciitounicode(&NameW, pName);
6675 asciitounicode(&EnvW, pEnvironment);
6676 asciitounicode(&DriverW, pDriverName);
6678 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6680 RtlFreeUnicodeString(&DriverW);
6681 RtlFreeUnicodeString(&EnvW);
6682 RtlFreeUnicodeString(&NameW);
6687 /******************************************************************************
6688 * DeletePrinterDataExW (WINSPOOL.@)
6690 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6693 FIXME("%p %s %s\n", hPrinter,
6694 debugstr_w(pKeyName), debugstr_w(pValueName));
6695 return ERROR_INVALID_PARAMETER;
6698 /******************************************************************************
6699 * DeletePrinterDataExA (WINSPOOL.@)
6701 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6704 FIXME("%p %s %s\n", hPrinter,
6705 debugstr_a(pKeyName), debugstr_a(pValueName));
6706 return ERROR_INVALID_PARAMETER;
6709 /******************************************************************************
6710 * DeletePrintProcessorA (WINSPOOL.@)
6712 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6714 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6715 debugstr_a(pPrintProcessorName));
6719 /******************************************************************************
6720 * DeletePrintProcessorW (WINSPOOL.@)
6722 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6724 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6725 debugstr_w(pPrintProcessorName));
6729 /******************************************************************************
6730 * DeletePrintProvidorA (WINSPOOL.@)
6732 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6734 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6735 debugstr_a(pPrintProviderName));
6739 /******************************************************************************
6740 * DeletePrintProvidorW (WINSPOOL.@)
6742 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6744 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6745 debugstr_w(pPrintProviderName));
6749 /******************************************************************************
6750 * EnumFormsA (WINSPOOL.@)
6752 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6753 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6755 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6756 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6760 /******************************************************************************
6761 * EnumFormsW (WINSPOOL.@)
6763 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6764 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6766 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6767 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6771 /*****************************************************************************
6772 * EnumMonitorsA [WINSPOOL.@]
6774 * See EnumMonitorsW.
6777 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6778 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6781 LPBYTE bufferW = NULL;
6782 LPWSTR nameW = NULL;
6784 DWORD numentries = 0;
6787 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6788 cbBuf, pcbNeeded, pcReturned);
6790 /* convert servername to unicode */
6792 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6793 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6794 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6796 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6797 needed = cbBuf * sizeof(WCHAR);
6798 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6799 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6801 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6802 if (pcbNeeded) needed = *pcbNeeded;
6803 /* HeapReAlloc return NULL, when bufferW was NULL */
6804 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6805 HeapAlloc(GetProcessHeap(), 0, needed);
6807 /* Try again with the large Buffer */
6808 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6810 numentries = pcReturned ? *pcReturned : 0;
6813 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6814 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6817 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6818 DWORD entrysize = 0;
6821 LPMONITOR_INFO_2W mi2w;
6822 LPMONITOR_INFO_2A mi2a;
6824 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6825 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6827 /* First pass: calculate the size for all Entries */
6828 mi2w = (LPMONITOR_INFO_2W) bufferW;
6829 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6831 while (index < numentries) {
6833 needed += entrysize; /* MONITOR_INFO_?A */
6834 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6836 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6837 NULL, 0, NULL, NULL);
6839 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6840 NULL, 0, NULL, NULL);
6841 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6842 NULL, 0, NULL, NULL);
6844 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6845 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6846 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6849 /* check for errors and quit on failure */
6850 if (cbBuf < needed) {
6851 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6855 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6856 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6857 cbBuf -= len ; /* free Bytes in the user-Buffer */
6858 mi2w = (LPMONITOR_INFO_2W) bufferW;
6859 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6861 /* Second Pass: Fill the User Buffer (if we have one) */
6862 while ((index < numentries) && pMonitors) {
6864 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6866 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6867 ptr, cbBuf , NULL, NULL);
6871 mi2a->pEnvironment = ptr;
6872 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6873 ptr, cbBuf, NULL, NULL);
6877 mi2a->pDLLName = ptr;
6878 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6879 ptr, cbBuf, NULL, NULL);
6883 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6884 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6885 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6889 if (pcbNeeded) *pcbNeeded = needed;
6890 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6892 HeapFree(GetProcessHeap(), 0, nameW);
6893 HeapFree(GetProcessHeap(), 0, bufferW);
6895 TRACE("returning %d with %d (%d byte for %d entries)\n",
6896 (res), GetLastError(), needed, numentries);
6902 /*****************************************************************************
6903 * EnumMonitorsW [WINSPOOL.@]
6905 * Enumerate available Port-Monitors
6908 * pName [I] Servername or NULL (local Computer)
6909 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6910 * pMonitors [O] PTR to Buffer that receives the Result
6911 * cbBuf [I] Size of Buffer at pMonitors
6912 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6913 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6917 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6920 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6921 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6924 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6925 cbBuf, pcbNeeded, pcReturned);
6927 if ((backend == NULL) && !load_backend()) return FALSE;
6929 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6930 SetLastError(RPC_X_NULL_REF_POINTER);
6934 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6937 /******************************************************************************
6938 * SpoolerInit (WINSPOOL.@)
6940 * Initialize the Spooler
6947 * The function fails on windows, when the spooler service is not running
6950 BOOL WINAPI SpoolerInit(void)
6953 if ((backend == NULL) && !load_backend()) return FALSE;
6957 /******************************************************************************
6958 * XcvDataW (WINSPOOL.@)
6960 * Execute commands in the Printmonitor DLL
6963 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6964 * pszDataName [i] Name of the command to execute
6965 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6966 * cbInputData [i] Size in Bytes of Buffer at pInputData
6967 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6968 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6969 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6970 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6977 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6978 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6980 * Minimal List of commands, that a Printmonitor DLL should support:
6982 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6983 *| "AddPort" : Add a Port
6984 *| "DeletePort": Delete a Port
6986 * Many Printmonitors support additional commands. Examples for localspl.dll:
6987 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6988 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6991 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6992 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6993 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6995 opened_printer_t *printer;
6997 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6998 pInputData, cbInputData, pOutputData,
6999 cbOutputData, pcbOutputNeeded, pdwStatus);
7001 if ((backend == NULL) && !load_backend()) return FALSE;
7003 printer = get_opened_printer(hXcv);
7004 if (!printer || (!printer->backend_printer)) {
7005 SetLastError(ERROR_INVALID_HANDLE);
7009 if (!pcbOutputNeeded) {
7010 SetLastError(ERROR_INVALID_PARAMETER);
7014 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7015 SetLastError(RPC_X_NULL_REF_POINTER);
7019 *pcbOutputNeeded = 0;
7021 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7022 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7026 /*****************************************************************************
7027 * EnumPrinterDataA [WINSPOOL.@]
7030 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7031 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7032 DWORD cbData, LPDWORD pcbData )
7034 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7035 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7036 return ERROR_NO_MORE_ITEMS;
7039 /*****************************************************************************
7040 * EnumPrinterDataW [WINSPOOL.@]
7043 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7044 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7045 DWORD cbData, LPDWORD pcbData )
7047 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7048 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7049 return ERROR_NO_MORE_ITEMS;
7052 /*****************************************************************************
7053 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7056 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7057 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7058 LPDWORD pcbNeeded, LPDWORD pcReturned)
7060 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7061 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7062 pcbNeeded, pcReturned);
7066 /*****************************************************************************
7067 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7070 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7071 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7072 LPDWORD pcbNeeded, LPDWORD pcReturned)
7074 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7075 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7076 pcbNeeded, pcReturned);
7080 /*****************************************************************************
7081 * EnumPrintProcessorsA [WINSPOOL.@]
7083 * See EnumPrintProcessorsW.
7086 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7087 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7090 LPBYTE bufferW = NULL;
7091 LPWSTR nameW = NULL;
7094 DWORD numentries = 0;
7097 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7098 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7100 /* convert names to unicode */
7102 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7103 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7104 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7107 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7108 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7109 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7112 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7113 needed = cbBuf * sizeof(WCHAR);
7114 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7115 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7117 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7118 if (pcbNeeded) needed = *pcbNeeded;
7119 /* HeapReAlloc return NULL, when bufferW was NULL */
7120 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7121 HeapAlloc(GetProcessHeap(), 0, needed);
7123 /* Try again with the large Buffer */
7124 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7126 numentries = pcReturned ? *pcReturned : 0;
7130 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7133 PPRINTPROCESSOR_INFO_1W ppiw;
7134 PPRINTPROCESSOR_INFO_1A ppia;
7136 /* First pass: calculate the size for all Entries */
7137 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7138 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7140 while (index < numentries) {
7142 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7143 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7145 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7146 NULL, 0, NULL, NULL);
7148 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7149 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7152 /* check for errors and quit on failure */
7153 if (cbBuf < needed) {
7154 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7159 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7160 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7161 cbBuf -= len ; /* free Bytes in the user-Buffer */
7162 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7163 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7165 /* Second Pass: Fill the User Buffer (if we have one) */
7166 while ((index < numentries) && pPPInfo) {
7168 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7170 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7171 ptr, cbBuf , NULL, NULL);
7175 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7176 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7181 if (pcbNeeded) *pcbNeeded = needed;
7182 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7184 HeapFree(GetProcessHeap(), 0, nameW);
7185 HeapFree(GetProcessHeap(), 0, envW);
7186 HeapFree(GetProcessHeap(), 0, bufferW);
7188 TRACE("returning %d with %d (%d byte for %d entries)\n",
7189 (res), GetLastError(), needed, numentries);
7194 /*****************************************************************************
7195 * EnumPrintProcessorsW [WINSPOOL.@]
7197 * Enumerate available Print Processors
7200 * pName [I] Servername or NULL (local Computer)
7201 * pEnvironment [I] Printing-Environment or NULL (Default)
7202 * Level [I] Structure-Level (Only 1 is allowed)
7203 * pPPInfo [O] PTR to Buffer that receives the Result
7204 * cbBuf [I] Size of Buffer at pPPInfo
7205 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7206 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7210 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7213 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7214 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7217 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7218 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7220 if ((backend == NULL) && !load_backend()) return FALSE;
7222 if (!pcbNeeded || !pcReturned) {
7223 SetLastError(RPC_X_NULL_REF_POINTER);
7227 if (!pPPInfo && (cbBuf > 0)) {
7228 SetLastError(ERROR_INVALID_USER_BUFFER);
7232 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7233 cbBuf, pcbNeeded, pcReturned);
7236 /*****************************************************************************
7237 * ExtDeviceMode [WINSPOOL.@]
7240 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7241 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7244 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7245 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7246 debugstr_a(pProfile), fMode);
7250 /*****************************************************************************
7251 * FindClosePrinterChangeNotification [WINSPOOL.@]
7254 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7256 FIXME("Stub: %p\n", hChange);
7260 /*****************************************************************************
7261 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7264 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7265 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7267 FIXME("Stub: %p %x %x %p\n",
7268 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7269 return INVALID_HANDLE_VALUE;
7272 /*****************************************************************************
7273 * FindNextPrinterChangeNotification [WINSPOOL.@]
7276 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7277 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7279 FIXME("Stub: %p %p %p %p\n",
7280 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7284 /*****************************************************************************
7285 * FreePrinterNotifyInfo [WINSPOOL.@]
7288 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7290 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7294 /*****************************************************************************
7297 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7298 * ansi depending on the unicode parameter.
7300 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7310 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7313 memcpy(ptr, str, *size);
7320 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7323 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7330 /*****************************************************************************
7333 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7334 LPDWORD pcbNeeded, BOOL unicode)
7336 DWORD size, left = cbBuf;
7337 BOOL space = (cbBuf > 0);
7344 ji1->JobId = job->job_id;
7347 string_to_buf(job->document_title, ptr, left, &size, unicode);
7348 if(space && size <= left)
7350 ji1->pDocument = (LPWSTR)ptr;
7358 if (job->printer_name)
7360 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7361 if(space && size <= left)
7363 ji1->pPrinterName = (LPWSTR)ptr;
7375 /*****************************************************************************
7378 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7379 LPDWORD pcbNeeded, BOOL unicode)
7381 DWORD size, left = cbBuf;
7383 BOOL space = (cbBuf > 0);
7385 LPDEVMODEA dmA = NULL;
7392 ji2->JobId = job->job_id;
7395 string_to_buf(job->document_title, ptr, left, &size, unicode);
7396 if(space && size <= left)
7398 ji2->pDocument = (LPWSTR)ptr;
7406 if (job->printer_name)
7408 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7409 if(space && size <= left)
7411 ji2->pPrinterName = (LPWSTR)ptr;
7424 dmA = DEVMODEdupWtoA(job->devmode);
7425 devmode = (LPDEVMODEW) dmA;
7426 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7430 devmode = job->devmode;
7431 size = devmode->dmSize + devmode->dmDriverExtra;
7435 FIXME("Can't convert DEVMODE W to A\n");
7438 /* align DEVMODE to a DWORD boundary */
7439 shift = (4 - (*pcbNeeded & 3)) & 3;
7445 memcpy(ptr, devmode, size-shift);
7446 ji2->pDevMode = (LPDEVMODEW)ptr;
7447 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7460 /*****************************************************************************
7463 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7464 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7467 DWORD needed = 0, size;
7471 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7473 EnterCriticalSection(&printer_handles_cs);
7474 job = get_job(hPrinter, JobId);
7481 size = sizeof(JOB_INFO_1W);
7486 memset(pJob, 0, size);
7490 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7495 size = sizeof(JOB_INFO_2W);
7500 memset(pJob, 0, size);
7504 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7509 size = sizeof(JOB_INFO_3);
7513 memset(pJob, 0, size);
7522 SetLastError(ERROR_INVALID_LEVEL);
7526 *pcbNeeded = needed;
7528 LeaveCriticalSection(&printer_handles_cs);
7532 /*****************************************************************************
7533 * GetJobA [WINSPOOL.@]
7536 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7537 DWORD cbBuf, LPDWORD pcbNeeded)
7539 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7542 /*****************************************************************************
7543 * GetJobW [WINSPOOL.@]
7546 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7547 DWORD cbBuf, LPDWORD pcbNeeded)
7549 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7552 /*****************************************************************************
7555 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7558 char *unixname, *cmdA;
7560 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7566 if(!(unixname = wine_get_unix_file_name(filename)))
7569 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7570 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7571 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7573 TRACE("printing with: %s\n", cmdA);
7575 if((file_fd = open(unixname, O_RDONLY)) == -1)
7580 ERR("pipe() failed!\n");
7584 if ((pid = fork()) == 0)
7590 /* reset signals that we previously set to SIG_IGN */
7591 signal(SIGPIPE, SIG_DFL);
7593 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7598 ERR("fork() failed!\n");
7602 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7603 write(fds[1], buf, no_read);
7610 wret = waitpid(pid, &status, 0);
7611 } while (wret < 0 && errno == EINTR);
7614 ERR("waitpid() failed!\n");
7617 if (!WIFEXITED(status) || WEXITSTATUS(status))
7619 ERR("child process failed! %d\n", status);
7626 if(file_fd != -1) close(file_fd);
7627 if(fds[0] != -1) close(fds[0]);
7628 if(fds[1] != -1) close(fds[1]);
7630 HeapFree(GetProcessHeap(), 0, cmdA);
7631 HeapFree(GetProcessHeap(), 0, unixname);
7638 /*****************************************************************************
7641 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7644 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7647 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7648 sprintfW(cmd, fmtW, printer_name);
7650 r = schedule_pipe(cmd, filename);
7652 HeapFree(GetProcessHeap(), 0, cmd);
7656 #ifdef SONAME_LIBCUPS
7657 /*****************************************************************************
7658 * get_cups_jobs_ticket_options
7660 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7661 * The CUPS scheduler only looks for these in Print-File requests, and since
7662 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7665 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7667 FILE *fp = fopen( file, "r" );
7668 char buf[257]; /* DSC max of 256 + '\0' */
7669 const char *ps_adobe = "%!PS-Adobe-";
7670 const char *cups_job = "%cupsJobTicket:";
7672 if (!fp) return num_options;
7673 if (!fgets( buf, sizeof(buf), fp )) goto end;
7674 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7675 while (fgets( buf, sizeof(buf), fp ))
7677 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7678 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7687 /*****************************************************************************
7690 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7692 #ifdef SONAME_LIBCUPS
7695 char *unixname, *queue, *unix_doc_title;
7698 int num_options = 0, i;
7699 cups_option_t *options = NULL;
7701 if(!(unixname = wine_get_unix_file_name(filename)))
7704 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7705 queue = HeapAlloc(GetProcessHeap(), 0, len);
7706 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7708 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7709 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7710 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7712 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7714 TRACE( "printing via cups with options:\n" );
7715 for (i = 0; i < num_options; i++)
7716 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7718 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7720 pcupsFreeOptions( num_options, options );
7722 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7723 HeapFree(GetProcessHeap(), 0, queue);
7724 HeapFree(GetProcessHeap(), 0, unixname);
7730 return schedule_lpr(printer_name, filename);
7734 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7741 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7745 if(HIWORD(wparam) == BN_CLICKED)
7747 if(LOWORD(wparam) == IDOK)
7750 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7753 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7754 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7756 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7758 WCHAR caption[200], message[200];
7761 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7762 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7763 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7764 if(mb_ret == IDCANCEL)
7766 HeapFree(GetProcessHeap(), 0, filename);
7770 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7771 if(hf == INVALID_HANDLE_VALUE)
7773 WCHAR caption[200], message[200];
7775 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7776 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7777 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7778 HeapFree(GetProcessHeap(), 0, filename);
7782 DeleteFileW(filename);
7783 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7785 EndDialog(hwnd, IDOK);
7788 if(LOWORD(wparam) == IDCANCEL)
7790 EndDialog(hwnd, IDCANCEL);
7799 /*****************************************************************************
7802 static BOOL get_filename(LPWSTR *filename)
7804 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7805 file_dlg_proc, (LPARAM)filename) == IDOK;
7808 /*****************************************************************************
7811 static BOOL schedule_file(LPCWSTR filename)
7813 LPWSTR output = NULL;
7815 if(get_filename(&output))
7818 TRACE("copy to %s\n", debugstr_w(output));
7819 r = CopyFileW(filename, output, FALSE);
7820 HeapFree(GetProcessHeap(), 0, output);
7826 /*****************************************************************************
7829 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7831 int in_fd, out_fd, no_read;
7834 char *unixname, *outputA;
7837 if(!(unixname = wine_get_unix_file_name(filename)))
7840 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7841 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7842 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7844 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7845 in_fd = open(unixname, O_RDONLY);
7846 if(out_fd == -1 || in_fd == -1)
7849 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7850 write(out_fd, buf, no_read);
7854 if(in_fd != -1) close(in_fd);
7855 if(out_fd != -1) close(out_fd);
7856 HeapFree(GetProcessHeap(), 0, outputA);
7857 HeapFree(GetProcessHeap(), 0, unixname);
7861 /*****************************************************************************
7862 * ScheduleJob [WINSPOOL.@]
7865 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7867 opened_printer_t *printer;
7869 struct list *cursor, *cursor2;
7871 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7872 EnterCriticalSection(&printer_handles_cs);
7873 printer = get_opened_printer(hPrinter);
7877 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7879 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7882 if(job->job_id != dwJobID) continue;
7884 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7885 if(hf != INVALID_HANDLE_VALUE)
7887 PRINTER_INFO_5W *pi5 = NULL;
7888 LPWSTR portname = job->portname;
7892 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7893 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7897 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7898 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7899 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7900 portname = pi5->pPortName;
7902 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7903 debugstr_w(portname));
7907 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7908 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7910 DWORD type, count = sizeof(output);
7911 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7914 if(output[0] == '|')
7916 ret = schedule_pipe(output + 1, job->filename);
7920 ret = schedule_unixfile(output, job->filename);
7922 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7924 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7926 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7928 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7930 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7932 ret = schedule_file(job->filename);
7936 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7938 HeapFree(GetProcessHeap(), 0, pi5);
7940 DeleteFileW(job->filename);
7942 list_remove(cursor);
7943 HeapFree(GetProcessHeap(), 0, job->document_title);
7944 HeapFree(GetProcessHeap(), 0, job->printer_name);
7945 HeapFree(GetProcessHeap(), 0, job->portname);
7946 HeapFree(GetProcessHeap(), 0, job->filename);
7947 HeapFree(GetProcessHeap(), 0, job->devmode);
7948 HeapFree(GetProcessHeap(), 0, job);
7952 LeaveCriticalSection(&printer_handles_cs);
7956 /*****************************************************************************
7957 * StartDocDlgA [WINSPOOL.@]
7959 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7961 UNICODE_STRING usBuffer;
7964 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7967 docW.cbSize = sizeof(docW);
7968 if (doc->lpszDocName)
7970 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7971 if (!(docW.lpszDocName = docnameW)) return NULL;
7973 if (doc->lpszOutput)
7975 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7976 if (!(docW.lpszOutput = outputW)) return NULL;
7978 if (doc->lpszDatatype)
7980 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7981 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7983 docW.fwType = doc->fwType;
7985 retW = StartDocDlgW(hPrinter, &docW);
7989 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7990 ret = HeapAlloc(GetProcessHeap(), 0, len);
7991 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7992 HeapFree(GetProcessHeap(), 0, retW);
7995 HeapFree(GetProcessHeap(), 0, datatypeW);
7996 HeapFree(GetProcessHeap(), 0, outputW);
7997 HeapFree(GetProcessHeap(), 0, docnameW);
8002 /*****************************************************************************
8003 * StartDocDlgW [WINSPOOL.@]
8005 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8006 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8007 * port is "FILE:". Also returns the full path if passed a relative path.
8009 * The caller should free the returned string from the process heap.
8011 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8016 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8018 PRINTER_INFO_5W *pi5;
8019 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8020 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8022 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8023 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8024 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8026 HeapFree(GetProcessHeap(), 0, pi5);
8029 HeapFree(GetProcessHeap(), 0, pi5);
8032 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8036 if (get_filename(&name))
8038 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8040 HeapFree(GetProcessHeap(), 0, name);
8043 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8044 GetFullPathNameW(name, len, ret, NULL);
8045 HeapFree(GetProcessHeap(), 0, name);
8050 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8053 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8054 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8056 attr = GetFileAttributesW(ret);
8057 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8059 HeapFree(GetProcessHeap(), 0, ret);