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_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
754 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
755 (lstrlenW(value) + 1) * sizeof(WCHAR));
757 return ERROR_FILE_NOT_FOUND;
760 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
762 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
763 DWORD ret = ERROR_FILE_NOT_FOUND;
765 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
766 and we support these drivers. NT writes DEVMODEW so somehow
767 we'll need to distinguish between these when we support NT
772 ret = RegSetValueExW( key, name, 0, REG_BINARY,
773 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
774 HeapFree( GetProcessHeap(), 0, dmA );
780 /******************************************************************
781 * get_servername_from_name (internal)
783 * for an external server, a copy of the serverpart from the full name is returned
786 static LPWSTR get_servername_from_name(LPCWSTR name)
790 WCHAR buffer[MAX_PATH];
793 if (name == NULL) return NULL;
794 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
796 server = strdupW(&name[2]); /* skip over both backslash */
797 if (server == NULL) return NULL;
799 /* strip '\' and the printername */
800 ptr = strchrW(server, '\\');
801 if (ptr) ptr[0] = '\0';
803 TRACE("found %s\n", debugstr_w(server));
805 len = sizeof(buffer)/sizeof(buffer[0]);
806 if (GetComputerNameW(buffer, &len)) {
807 if (lstrcmpW(buffer, server) == 0) {
808 /* The requested Servername is our computername */
809 HeapFree(GetProcessHeap(), 0, server);
816 /******************************************************************
817 * get_basename_from_name (internal)
819 * skip over the serverpart from the full name
822 static LPCWSTR get_basename_from_name(LPCWSTR name)
824 if (name == NULL) return NULL;
825 if ((name[0] == '\\') && (name[1] == '\\')) {
826 /* skip over the servername and search for the following '\' */
827 name = strchrW(&name[2], '\\');
828 if ((name) && (name[1])) {
829 /* found a separator ('\') followed by a name:
830 skip over the separator and return the rest */
835 /* no basename present (we found only a servername) */
842 static void free_printer_entry( opened_printer_t *printer )
844 /* the queue is shared, so don't free that here */
845 HeapFree( GetProcessHeap(), 0, printer->printername );
846 HeapFree( GetProcessHeap(), 0, printer->name );
847 HeapFree( GetProcessHeap(), 0, printer->devmode );
848 HeapFree( GetProcessHeap(), 0, printer );
851 /******************************************************************
852 * get_opened_printer_entry
853 * Get the first place empty in the opened printer table
856 * - pDefault is ignored
858 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
860 UINT_PTR handle = nb_printer_handles, i;
861 jobqueue_t *queue = NULL;
862 opened_printer_t *printer = NULL;
866 if ((backend == NULL) && !load_backend()) return NULL;
868 servername = get_servername_from_name(name);
870 FIXME("server %s not supported\n", debugstr_w(servername));
871 HeapFree(GetProcessHeap(), 0, servername);
872 SetLastError(ERROR_INVALID_PRINTER_NAME);
876 printername = get_basename_from_name(name);
877 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
879 /* an empty printername is invalid */
880 if (printername && (!printername[0])) {
881 SetLastError(ERROR_INVALID_PARAMETER);
885 EnterCriticalSection(&printer_handles_cs);
887 for (i = 0; i < nb_printer_handles; i++)
889 if (!printer_handles[i])
891 if(handle == nb_printer_handles)
896 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
897 queue = printer_handles[i]->queue;
901 if (handle >= nb_printer_handles)
903 opened_printer_t **new_array;
905 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
906 (nb_printer_handles + 16) * sizeof(*new_array) );
908 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
909 (nb_printer_handles + 16) * sizeof(*new_array) );
916 printer_handles = new_array;
917 nb_printer_handles += 16;
920 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
926 /* get a printer handle from the backend */
927 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
932 /* clone the base name. This is NULL for the printserver */
933 printer->printername = strdupW(printername);
935 /* clone the full name */
936 printer->name = strdupW(name);
937 if (name && (!printer->name)) {
942 if (pDefault && pDefault->pDevMode)
943 printer->devmode = dup_devmode( pDefault->pDevMode );
946 printer->queue = queue;
949 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
950 if (!printer->queue) {
954 list_init(&printer->queue->jobs);
955 printer->queue->ref = 0;
957 InterlockedIncrement(&printer->queue->ref);
959 printer_handles[handle] = printer;
962 LeaveCriticalSection(&printer_handles_cs);
963 if (!handle && printer) {
964 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
965 free_printer_entry( printer );
968 return (HANDLE)handle;
971 /******************************************************************
973 * Get the pointer to the opened printer referred by the handle
975 static opened_printer_t *get_opened_printer(HANDLE hprn)
977 UINT_PTR idx = (UINT_PTR)hprn;
978 opened_printer_t *ret = NULL;
980 EnterCriticalSection(&printer_handles_cs);
982 if ((idx > 0) && (idx <= nb_printer_handles)) {
983 ret = printer_handles[idx - 1];
985 LeaveCriticalSection(&printer_handles_cs);
989 /******************************************************************
990 * get_opened_printer_name
991 * Get the pointer to the opened printer name referred by the handle
993 static LPCWSTR get_opened_printer_name(HANDLE hprn)
995 opened_printer_t *printer = get_opened_printer(hprn);
996 if(!printer) return NULL;
997 return printer->name;
1000 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1006 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1007 if (err) return err;
1009 err = RegOpenKeyW( printers, name, key );
1010 if (err) err = ERROR_INVALID_PRINTER_NAME;
1011 RegCloseKey( printers );
1015 /******************************************************************
1016 * WINSPOOL_GetOpenedPrinterRegKey
1019 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1021 LPCWSTR name = get_opened_printer_name(hPrinter);
1023 if(!name) return ERROR_INVALID_HANDLE;
1024 return open_printer_reg_key( name, phkey );
1027 static void old_printer_check( BOOL delete_phase )
1029 PRINTER_INFO_5W* pi;
1030 DWORD needed, type, num, delete, i, size;
1031 const DWORD one = 1;
1035 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1036 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1038 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1039 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1040 for (i = 0; i < num; i++)
1042 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1043 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1046 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1050 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1056 size = sizeof( delete );
1057 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1061 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1062 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1064 DeletePrinter( hprn );
1065 ClosePrinter( hprn );
1067 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1071 HeapFree(GetProcessHeap(), 0, pi);
1074 void WINSPOOL_LoadSystemPrinters(void)
1076 HKEY hkey, hkeyPrinters;
1077 DWORD needed, num, i;
1078 WCHAR PrinterName[256];
1081 /* This ensures that all printer entries have a valid Name value. If causes
1082 problems later if they don't. If one is found to be missed we create one
1083 and set it equal to the name of the key */
1084 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1085 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1086 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1087 for(i = 0; i < num; i++) {
1088 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1089 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1090 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1091 set_reg_szW(hkey, NameW, PrinterName);
1098 RegCloseKey(hkeyPrinters);
1101 old_printer_check( FALSE );
1103 #ifdef SONAME_LIBCUPS
1104 done = CUPS_LoadPrinters();
1107 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1108 PRINTCAP_LoadPrinters();
1110 old_printer_check( TRUE );
1115 /******************************************************************
1118 * Get the pointer to the specified job.
1119 * Should hold the printer_handles_cs before calling.
1121 static job_t *get_job(HANDLE hprn, DWORD JobId)
1123 opened_printer_t *printer = get_opened_printer(hprn);
1126 if(!printer) return NULL;
1127 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1129 if(job->job_id == JobId)
1135 /***********************************************************
1138 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1141 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1144 Formname = (dmA->dmSize > off_formname);
1145 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1146 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1147 dmW->dmDeviceName, CCHDEVICENAME);
1149 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1150 dmA->dmSize - CCHDEVICENAME);
1152 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1153 off_formname - CCHDEVICENAME);
1154 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1155 dmW->dmFormName, CCHFORMNAME);
1156 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1157 (off_formname + CCHFORMNAME));
1160 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1161 dmA->dmDriverExtra);
1165 /******************************************************************
1166 * convert_printerinfo_W_to_A [internal]
1169 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1170 DWORD level, DWORD outlen, DWORD numentries)
1176 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1178 len = pi_sizeof[level] * numentries;
1179 ptr = (LPSTR) out + len;
1182 /* copy the numbers of all PRINTER_INFO_* first */
1183 memcpy(out, pPrintersW, len);
1185 while (id < numentries) {
1189 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1190 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1192 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1193 if (piW->pDescription) {
1194 piA->pDescription = ptr;
1195 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1196 ptr, outlen, NULL, NULL);
1202 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1203 ptr, outlen, NULL, NULL);
1207 if (piW->pComment) {
1208 piA->pComment = ptr;
1209 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1210 ptr, outlen, NULL, NULL);
1219 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1220 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1223 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1224 if (piW->pServerName) {
1225 piA->pServerName = ptr;
1226 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1227 ptr, outlen, NULL, NULL);
1231 if (piW->pPrinterName) {
1232 piA->pPrinterName = ptr;
1233 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1234 ptr, outlen, NULL, NULL);
1238 if (piW->pShareName) {
1239 piA->pShareName = ptr;
1240 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1241 ptr, outlen, NULL, NULL);
1245 if (piW->pPortName) {
1246 piA->pPortName = ptr;
1247 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1248 ptr, outlen, NULL, NULL);
1252 if (piW->pDriverName) {
1253 piA->pDriverName = ptr;
1254 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1255 ptr, outlen, NULL, NULL);
1259 if (piW->pComment) {
1260 piA->pComment = ptr;
1261 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1262 ptr, outlen, NULL, NULL);
1266 if (piW->pLocation) {
1267 piA->pLocation = ptr;
1268 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1269 ptr, outlen, NULL, NULL);
1274 dmA = DEVMODEdupWtoA(piW->pDevMode);
1276 /* align DEVMODEA to a DWORD boundary */
1277 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1281 piA->pDevMode = (LPDEVMODEA) ptr;
1282 len = dmA->dmSize + dmA->dmDriverExtra;
1283 memcpy(ptr, dmA, len);
1284 HeapFree(GetProcessHeap(), 0, dmA);
1290 if (piW->pSepFile) {
1291 piA->pSepFile = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1293 ptr, outlen, NULL, NULL);
1297 if (piW->pPrintProcessor) {
1298 piA->pPrintProcessor = ptr;
1299 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1300 ptr, outlen, NULL, NULL);
1304 if (piW->pDatatype) {
1305 piA->pDatatype = ptr;
1306 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1307 ptr, outlen, NULL, NULL);
1311 if (piW->pParameters) {
1312 piA->pParameters = ptr;
1313 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1314 ptr, outlen, NULL, NULL);
1318 if (piW->pSecurityDescriptor) {
1319 piA->pSecurityDescriptor = NULL;
1320 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1327 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1328 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1330 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1332 if (piW->pPrinterName) {
1333 piA->pPrinterName = ptr;
1334 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1335 ptr, outlen, NULL, NULL);
1339 if (piW->pServerName) {
1340 piA->pServerName = ptr;
1341 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1342 ptr, outlen, NULL, NULL);
1351 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1352 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1354 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1356 if (piW->pPrinterName) {
1357 piA->pPrinterName = ptr;
1358 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1359 ptr, outlen, NULL, NULL);
1363 if (piW->pPortName) {
1364 piA->pPortName = ptr;
1365 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1366 ptr, outlen, NULL, NULL);
1373 case 6: /* 6A and 6W are the same structure */
1378 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1379 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1381 TRACE("(%u) #%u\n", level, id);
1382 if (piW->pszObjectGUID) {
1383 piA->pszObjectGUID = ptr;
1384 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1385 ptr, outlen, NULL, NULL);
1395 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1396 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1399 TRACE("(%u) #%u\n", level, id);
1400 dmA = DEVMODEdupWtoA(piW->pDevMode);
1402 /* align DEVMODEA to a DWORD boundary */
1403 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1407 piA->pDevMode = (LPDEVMODEA) ptr;
1408 len = dmA->dmSize + dmA->dmDriverExtra;
1409 memcpy(ptr, dmA, len);
1410 HeapFree(GetProcessHeap(), 0, dmA);
1420 FIXME("for level %u\n", level);
1422 pPrintersW += pi_sizeof[level];
1423 out += pi_sizeof[level];
1428 /******************************************************************
1429 * convert_driverinfo_W_to_A [internal]
1432 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1433 DWORD level, DWORD outlen, DWORD numentries)
1439 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1441 len = di_sizeof[level] * numentries;
1442 ptr = (LPSTR) out + len;
1445 /* copy the numbers of all PRINTER_INFO_* first */
1446 memcpy(out, pDriversW, len);
1448 #define COPY_STRING(fld) \
1451 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1452 ptr += len; outlen -= len;\
1454 #define COPY_MULTIZ_STRING(fld) \
1455 { LPWSTR p = diW->fld; if (p){ \
1458 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1459 ptr += len; outlen -= len; p += len;\
1461 while(len > 1 && outlen > 0); \
1464 while (id < numentries)
1470 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1471 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1473 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1480 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1481 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1483 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1486 COPY_STRING(pEnvironment);
1487 COPY_STRING(pDriverPath);
1488 COPY_STRING(pDataFile);
1489 COPY_STRING(pConfigFile);
1494 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1495 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1497 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1500 COPY_STRING(pEnvironment);
1501 COPY_STRING(pDriverPath);
1502 COPY_STRING(pDataFile);
1503 COPY_STRING(pConfigFile);
1504 COPY_STRING(pHelpFile);
1505 COPY_MULTIZ_STRING(pDependentFiles);
1506 COPY_STRING(pMonitorName);
1507 COPY_STRING(pDefaultDataType);
1512 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1513 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1515 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1518 COPY_STRING(pEnvironment);
1519 COPY_STRING(pDriverPath);
1520 COPY_STRING(pDataFile);
1521 COPY_STRING(pConfigFile);
1522 COPY_STRING(pHelpFile);
1523 COPY_MULTIZ_STRING(pDependentFiles);
1524 COPY_STRING(pMonitorName);
1525 COPY_STRING(pDefaultDataType);
1526 COPY_MULTIZ_STRING(pszzPreviousNames);
1531 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1532 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1534 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1537 COPY_STRING(pEnvironment);
1538 COPY_STRING(pDriverPath);
1539 COPY_STRING(pDataFile);
1540 COPY_STRING(pConfigFile);
1545 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1546 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1548 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1551 COPY_STRING(pEnvironment);
1552 COPY_STRING(pDriverPath);
1553 COPY_STRING(pDataFile);
1554 COPY_STRING(pConfigFile);
1555 COPY_STRING(pHelpFile);
1556 COPY_MULTIZ_STRING(pDependentFiles);
1557 COPY_STRING(pMonitorName);
1558 COPY_STRING(pDefaultDataType);
1559 COPY_MULTIZ_STRING(pszzPreviousNames);
1560 COPY_STRING(pszMfgName);
1561 COPY_STRING(pszOEMUrl);
1562 COPY_STRING(pszHardwareID);
1563 COPY_STRING(pszProvider);
1568 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1569 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1571 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1574 COPY_STRING(pEnvironment);
1575 COPY_STRING(pDriverPath);
1576 COPY_STRING(pDataFile);
1577 COPY_STRING(pConfigFile);
1578 COPY_STRING(pHelpFile);
1579 COPY_MULTIZ_STRING(pDependentFiles);
1580 COPY_STRING(pMonitorName);
1581 COPY_STRING(pDefaultDataType);
1582 COPY_MULTIZ_STRING(pszzPreviousNames);
1583 COPY_STRING(pszMfgName);
1584 COPY_STRING(pszOEMUrl);
1585 COPY_STRING(pszHardwareID);
1586 COPY_STRING(pszProvider);
1587 COPY_STRING(pszPrintProcessor);
1588 COPY_STRING(pszVendorSetup);
1589 COPY_MULTIZ_STRING(pszzColorProfiles);
1590 COPY_STRING(pszInfPath);
1591 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1597 FIXME("for level %u\n", level);
1600 pDriversW += di_sizeof[level];
1601 out += di_sizeof[level];
1606 #undef COPY_MULTIZ_STRING
1610 /***********************************************************
1613 static void *printer_info_AtoW( const void *data, DWORD level )
1616 UNICODE_STRING usBuffer;
1618 if (!data) return NULL;
1620 if (level < 1 || level > 9) return NULL;
1622 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1623 if (!ret) return NULL;
1625 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1631 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1632 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1634 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1635 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1636 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1637 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1638 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1639 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1640 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1641 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1642 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1643 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1644 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1645 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1652 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1653 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1655 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1660 FIXME( "Unhandled level %d\n", level );
1661 HeapFree( GetProcessHeap(), 0, ret );
1668 /***********************************************************
1671 static void free_printer_info( void *data, DWORD level )
1679 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1681 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1682 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1683 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1684 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1685 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1686 HeapFree( GetProcessHeap(), 0, piW->pComment );
1687 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1688 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1689 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1690 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1691 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1692 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1699 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1701 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1706 FIXME( "Unhandled level %d\n", level );
1709 HeapFree( GetProcessHeap(), 0, data );
1713 /******************************************************************
1714 * DeviceCapabilities [WINSPOOL.@]
1715 * DeviceCapabilitiesA [WINSPOOL.@]
1718 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1719 LPSTR pOutput, LPDEVMODEA lpdm)
1723 if (!GDI_CallDeviceCapabilities16)
1725 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1727 if (!GDI_CallDeviceCapabilities16) return -1;
1729 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1731 /* If DC_PAPERSIZE map POINT16s to POINTs */
1732 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1733 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1734 POINT *pt = (POINT *)pOutput;
1736 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1737 for(i = 0; i < ret; i++, pt++)
1742 HeapFree( GetProcessHeap(), 0, tmp );
1748 /*****************************************************************************
1749 * DeviceCapabilitiesW [WINSPOOL.@]
1751 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1754 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1755 WORD fwCapability, LPWSTR pOutput,
1756 const DEVMODEW *pDevMode)
1758 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1759 LPSTR pDeviceA = strdupWtoA(pDevice);
1760 LPSTR pPortA = strdupWtoA(pPort);
1763 if(pOutput && (fwCapability == DC_BINNAMES ||
1764 fwCapability == DC_FILEDEPENDENCIES ||
1765 fwCapability == DC_PAPERNAMES)) {
1766 /* These need A -> W translation */
1769 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1773 switch(fwCapability) {
1778 case DC_FILEDEPENDENCIES:
1782 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1783 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1785 for(i = 0; i < ret; i++)
1786 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1787 pOutput + (i * size), size);
1788 HeapFree(GetProcessHeap(), 0, pOutputA);
1790 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1791 (LPSTR)pOutput, dmA);
1793 HeapFree(GetProcessHeap(),0,pPortA);
1794 HeapFree(GetProcessHeap(),0,pDeviceA);
1795 HeapFree(GetProcessHeap(),0,dmA);
1799 /******************************************************************
1800 * DocumentPropertiesA [WINSPOOL.@]
1802 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1804 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1805 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1806 LPDEVMODEA pDevModeInput,DWORD fMode )
1808 LPSTR lpName = pDeviceName;
1809 static CHAR port[] = "LPT1:";
1812 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1813 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1817 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1819 ERR("no name from hPrinter?\n");
1820 SetLastError(ERROR_INVALID_HANDLE);
1823 lpName = strdupWtoA(lpNameW);
1826 if (!GDI_CallExtDeviceMode16)
1828 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1830 if (!GDI_CallExtDeviceMode16) {
1831 ERR("No CallExtDeviceMode16?\n");
1835 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1836 pDevModeInput, NULL, fMode);
1839 HeapFree(GetProcessHeap(),0,lpName);
1844 /*****************************************************************************
1845 * DocumentPropertiesW (WINSPOOL.@)
1847 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1849 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1851 LPDEVMODEW pDevModeOutput,
1852 LPDEVMODEW pDevModeInput, DWORD fMode)
1855 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1856 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1857 LPDEVMODEA pDevModeOutputA = NULL;
1860 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1861 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1863 if(pDevModeOutput) {
1864 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1865 if(ret < 0) return ret;
1866 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1868 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1869 pDevModeInputA, fMode);
1870 if(pDevModeOutput) {
1871 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1872 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1874 if(fMode == 0 && ret > 0)
1875 ret += (CCHDEVICENAME + CCHFORMNAME);
1876 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1877 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1881 /*****************************************************************************
1882 * IsValidDevmodeA [WINSPOOL.@]
1884 * Validate a DEVMODE structure and fix errors if possible.
1887 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1889 FIXME("(%p,%ld): stub\n", pDevMode, size);
1897 /*****************************************************************************
1898 * IsValidDevmodeW [WINSPOOL.@]
1900 * Validate a DEVMODE structure and fix errors if possible.
1903 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1905 FIXME("(%p,%ld): stub\n", pDevMode, size);
1913 /******************************************************************
1914 * OpenPrinterA [WINSPOOL.@]
1919 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1920 LPPRINTER_DEFAULTSA pDefault)
1922 UNICODE_STRING lpPrinterNameW;
1923 UNICODE_STRING usBuffer;
1924 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1925 PWSTR pwstrPrinterNameW;
1928 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1931 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1932 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1933 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1934 pDefaultW = &DefaultW;
1936 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1938 RtlFreeUnicodeString(&usBuffer);
1939 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1941 RtlFreeUnicodeString(&lpPrinterNameW);
1945 /******************************************************************
1946 * OpenPrinterW [WINSPOOL.@]
1948 * Open a Printer / Printserver or a Printer-Object
1951 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1952 * phPrinter [O] The resulting Handle is stored here
1953 * pDefault [I] PTR to Default Printer Settings or NULL
1960 * lpPrinterName is one of:
1961 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1962 *| Printer: "PrinterName"
1963 *| Printer-Object: "PrinterName,Job xxx"
1964 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1965 *| XcvPort: "Servername,XcvPort PortName"
1968 *| Printer-Object not supported
1969 *| pDefaults is ignored
1972 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1975 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1978 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1979 SetLastError(ERROR_INVALID_PARAMETER);
1983 /* Get the unique handle of the printer or Printserver */
1984 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1985 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1986 return (*phPrinter != 0);
1989 /******************************************************************
1990 * AddMonitorA [WINSPOOL.@]
1995 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1997 LPWSTR nameW = NULL;
2000 LPMONITOR_INFO_2A mi2a;
2001 MONITOR_INFO_2W mi2w;
2003 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2004 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2005 debugstr_a(mi2a ? mi2a->pName : NULL),
2006 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2007 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2010 SetLastError(ERROR_INVALID_LEVEL);
2014 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2020 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2021 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2022 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2025 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2027 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2028 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2029 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2031 if (mi2a->pEnvironment) {
2032 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2033 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2036 if (mi2a->pDLLName) {
2037 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2038 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2039 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2042 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2044 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2045 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2046 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2048 HeapFree(GetProcessHeap(), 0, nameW);
2052 /******************************************************************************
2053 * AddMonitorW [WINSPOOL.@]
2055 * Install a Printmonitor
2058 * pName [I] Servername or NULL (local Computer)
2059 * Level [I] Structure-Level (Must be 2)
2060 * pMonitors [I] PTR to MONITOR_INFO_2
2067 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2070 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2072 LPMONITOR_INFO_2W mi2w;
2074 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2075 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2076 debugstr_w(mi2w ? mi2w->pName : NULL),
2077 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2078 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2080 if ((backend == NULL) && !load_backend()) return FALSE;
2083 SetLastError(ERROR_INVALID_LEVEL);
2087 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2092 return backend->fpAddMonitor(pName, Level, pMonitors);
2095 /******************************************************************
2096 * DeletePrinterDriverA [WINSPOOL.@]
2099 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2101 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2104 /******************************************************************
2105 * DeletePrinterDriverW [WINSPOOL.@]
2108 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2110 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2113 /******************************************************************
2114 * DeleteMonitorA [WINSPOOL.@]
2116 * See DeleteMonitorW.
2119 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2121 LPWSTR nameW = NULL;
2122 LPWSTR EnvironmentW = NULL;
2123 LPWSTR MonitorNameW = NULL;
2128 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2129 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2130 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2134 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2135 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2136 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2139 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2140 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2141 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2144 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2146 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2147 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2148 HeapFree(GetProcessHeap(), 0, nameW);
2152 /******************************************************************
2153 * DeleteMonitorW [WINSPOOL.@]
2155 * Delete a specific Printmonitor from a Printing-Environment
2158 * pName [I] Servername or NULL (local Computer)
2159 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2160 * pMonitorName [I] Name of the Monitor, that should be deleted
2167 * pEnvironment is ignored in Windows for the local Computer.
2170 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2173 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2174 debugstr_w(pMonitorName));
2176 if ((backend == NULL) && !load_backend()) return FALSE;
2178 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2182 /******************************************************************
2183 * DeletePortA [WINSPOOL.@]
2188 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2190 LPWSTR nameW = NULL;
2191 LPWSTR portW = NULL;
2195 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2197 /* convert servername to unicode */
2199 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2200 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2201 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2204 /* convert portname to unicode */
2206 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2207 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2208 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2211 res = DeletePortW(nameW, hWnd, portW);
2212 HeapFree(GetProcessHeap(), 0, nameW);
2213 HeapFree(GetProcessHeap(), 0, portW);
2217 /******************************************************************
2218 * DeletePortW [WINSPOOL.@]
2220 * Delete a specific Port
2223 * pName [I] Servername or NULL (local Computer)
2224 * hWnd [I] Handle to parent Window for the Dialog-Box
2225 * pPortName [I] Name of the Port, that should be deleted
2232 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2234 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2236 if ((backend == NULL) && !load_backend()) return FALSE;
2239 SetLastError(RPC_X_NULL_REF_POINTER);
2243 return backend->fpDeletePort(pName, hWnd, pPortName);
2246 /******************************************************************************
2247 * WritePrinter [WINSPOOL.@]
2249 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2251 opened_printer_t *printer;
2254 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2256 EnterCriticalSection(&printer_handles_cs);
2257 printer = get_opened_printer(hPrinter);
2260 SetLastError(ERROR_INVALID_HANDLE);
2266 SetLastError(ERROR_SPL_NO_STARTDOC);
2270 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2272 LeaveCriticalSection(&printer_handles_cs);
2276 /*****************************************************************************
2277 * AddFormA [WINSPOOL.@]
2279 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2281 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2285 /*****************************************************************************
2286 * AddFormW [WINSPOOL.@]
2288 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2290 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2294 /*****************************************************************************
2295 * AddJobA [WINSPOOL.@]
2297 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2300 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2304 SetLastError(ERROR_INVALID_LEVEL);
2308 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2311 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2312 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2313 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2314 if(*pcbNeeded > cbBuf) {
2315 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2318 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2319 addjobA->JobId = addjobW->JobId;
2320 addjobA->Path = (char *)(addjobA + 1);
2321 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2327 /*****************************************************************************
2328 * AddJobW [WINSPOOL.@]
2330 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2332 opened_printer_t *printer;
2335 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2336 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2337 WCHAR path[MAX_PATH], filename[MAX_PATH];
2339 ADDJOB_INFO_1W *addjob;
2341 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2343 EnterCriticalSection(&printer_handles_cs);
2345 printer = get_opened_printer(hPrinter);
2348 SetLastError(ERROR_INVALID_HANDLE);
2353 SetLastError(ERROR_INVALID_LEVEL);
2357 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2361 job->job_id = InterlockedIncrement(&next_job_id);
2363 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2364 if(path[len - 1] != '\\')
2366 memcpy(path + len, spool_path, sizeof(spool_path));
2367 sprintfW(filename, fmtW, path, job->job_id);
2369 len = strlenW(filename);
2370 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2371 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2372 job->portname = NULL;
2373 job->document_title = strdupW(default_doc_title);
2374 job->printer_name = strdupW(printer->name);
2375 job->devmode = dup_devmode( printer->devmode );
2376 list_add_tail(&printer->queue->jobs, &job->entry);
2378 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2379 if(*pcbNeeded <= cbBuf) {
2380 addjob = (ADDJOB_INFO_1W*)pData;
2381 addjob->JobId = job->job_id;
2382 addjob->Path = (WCHAR *)(addjob + 1);
2383 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2386 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2389 LeaveCriticalSection(&printer_handles_cs);
2393 /*****************************************************************************
2394 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2396 * Return the PATH for the Print-Processors
2398 * See GetPrintProcessorDirectoryW.
2402 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2403 DWORD level, LPBYTE Info,
2404 DWORD cbBuf, LPDWORD pcbNeeded)
2406 LPWSTR serverW = NULL;
2411 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2412 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2416 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2417 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2418 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2422 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2423 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2424 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2427 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2428 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2430 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2433 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2434 cbBuf, NULL, NULL) > 0;
2437 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2438 HeapFree(GetProcessHeap(), 0, envW);
2439 HeapFree(GetProcessHeap(), 0, serverW);
2443 /*****************************************************************************
2444 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2446 * Return the PATH for the Print-Processors
2449 * server [I] Servername (NT only) or NULL (local Computer)
2450 * env [I] Printing-Environment (see below) or NULL (Default)
2451 * level [I] Structure-Level (must be 1)
2452 * Info [O] PTR to Buffer that receives the Result
2453 * cbBuf [I] Size of Buffer at "Info"
2454 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2455 * required for the Buffer at "Info"
2458 * Success: TRUE and in pcbNeeded the Bytes used in Info
2459 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2460 * if cbBuf is too small
2462 * Native Values returned in Info on Success:
2463 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2464 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2465 *| win9x(Windows 4.0): "%winsysdir%"
2467 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2470 * Only NULL or "" is supported for server
2473 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2474 DWORD level, LPBYTE Info,
2475 DWORD cbBuf, LPDWORD pcbNeeded)
2478 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2479 Info, cbBuf, pcbNeeded);
2481 if ((backend == NULL) && !load_backend()) return FALSE;
2484 /* (Level != 1) is ignored in win9x */
2485 SetLastError(ERROR_INVALID_LEVEL);
2489 if (pcbNeeded == NULL) {
2490 /* (pcbNeeded == NULL) is ignored in win9x */
2491 SetLastError(RPC_X_NULL_REF_POINTER);
2495 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2498 /*****************************************************************************
2499 * WINSPOOL_OpenDriverReg [internal]
2501 * opens the registry for the printer drivers depending on the given input
2502 * variable pEnvironment
2505 * the opened hkey on success
2508 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2512 const printenv_t * env;
2514 TRACE("(%s)\n", debugstr_w(pEnvironment));
2516 env = validate_envW(pEnvironment);
2517 if (!env) return NULL;
2519 buffer = HeapAlloc( GetProcessHeap(), 0,
2520 (strlenW(DriversW) + strlenW(env->envname) +
2521 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2523 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2524 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2525 HeapFree(GetProcessHeap(), 0, buffer);
2530 /*****************************************************************************
2531 * set_devices_and_printerports [internal]
2533 * set the [Devices] and [PrinterPorts] entries for a printer.
2536 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2538 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2542 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2544 /* FIXME: the driver must change to "winspool" */
2545 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2547 lstrcpyW(devline, driver_nt);
2548 lstrcatW(devline, commaW);
2549 lstrcatW(devline, pi->pPortName);
2551 TRACE("using %s\n", debugstr_w(devline));
2552 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2553 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2554 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2555 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2559 lstrcatW(devline, timeout_15_45);
2560 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2561 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2562 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2563 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2566 HeapFree(GetProcessHeap(), 0, devline);
2570 /*****************************************************************************
2571 * AddPrinterW [WINSPOOL.@]
2573 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2575 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2578 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2580 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2581 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2582 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2583 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2584 statusW[] = {'S','t','a','t','u','s',0},
2585 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2587 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2590 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2591 SetLastError(ERROR_INVALID_PARAMETER);
2595 ERR("Level = %d, unsupported!\n", Level);
2596 SetLastError(ERROR_INVALID_LEVEL);
2600 SetLastError(ERROR_INVALID_PARAMETER);
2603 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2605 ERR("Can't create Printers key\n");
2608 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2609 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2610 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2611 RegCloseKey(hkeyPrinter);
2612 RegCloseKey(hkeyPrinters);
2615 RegCloseKey(hkeyPrinter);
2617 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2619 ERR("Can't create Drivers key\n");
2620 RegCloseKey(hkeyPrinters);
2623 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2625 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2626 RegCloseKey(hkeyPrinters);
2627 RegCloseKey(hkeyDrivers);
2628 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2631 RegCloseKey(hkeyDriver);
2632 RegCloseKey(hkeyDrivers);
2634 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2635 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2636 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2637 RegCloseKey(hkeyPrinters);
2641 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2643 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2644 SetLastError(ERROR_INVALID_PRINTER_NAME);
2645 RegCloseKey(hkeyPrinters);
2649 set_devices_and_printerports(pi);
2650 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2651 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2652 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2654 /* See if we can load the driver. We may need the devmode structure anyway
2657 * Note that DocumentPropertiesW will briefly try to open the printer we
2658 * just create to find a DEVMODE struct (it will use the WINEPS default
2659 * one in case it is not there, so we are ok).
2661 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2664 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2665 size = sizeof(DEVMODEW);
2671 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2673 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2675 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2676 HeapFree( GetProcessHeap(), 0, dm );
2681 /* set devmode to printer name */
2682 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2686 set_reg_devmode( hkeyPrinter, default_devmodeW, dm );
2687 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2689 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2690 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2691 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2692 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2694 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2695 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2696 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2697 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2698 (LPBYTE)&pi->Priority, sizeof(DWORD));
2699 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2700 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2701 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2702 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2703 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2704 (LPBYTE)&pi->Status, sizeof(DWORD));
2705 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2706 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2708 RegCloseKey(hkeyPrinter);
2709 RegCloseKey(hkeyPrinters);
2710 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2711 ERR("OpenPrinter failing\n");
2717 /*****************************************************************************
2718 * AddPrinterA [WINSPOOL.@]
2720 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2722 UNICODE_STRING pNameW;
2724 PRINTER_INFO_2W *piW;
2725 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2728 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2730 ERR("Level = %d, unsupported!\n", Level);
2731 SetLastError(ERROR_INVALID_LEVEL);
2734 pwstrNameW = asciitounicode(&pNameW,pName);
2735 piW = printer_info_AtoW( piA, Level );
2737 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2739 free_printer_info( piW, Level );
2740 RtlFreeUnicodeString(&pNameW);
2745 /*****************************************************************************
2746 * ClosePrinter [WINSPOOL.@]
2748 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2750 UINT_PTR i = (UINT_PTR)hPrinter;
2751 opened_printer_t *printer = NULL;
2754 TRACE("(%p)\n", hPrinter);
2756 EnterCriticalSection(&printer_handles_cs);
2758 if ((i > 0) && (i <= nb_printer_handles))
2759 printer = printer_handles[i - 1];
2764 struct list *cursor, *cursor2;
2766 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2768 if (printer->backend_printer) {
2769 backend->fpClosePrinter(printer->backend_printer);
2773 EndDocPrinter(hPrinter);
2775 if(InterlockedDecrement(&printer->queue->ref) == 0)
2777 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2779 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2780 ScheduleJob(hPrinter, job->job_id);
2782 HeapFree(GetProcessHeap(), 0, printer->queue);
2785 free_printer_entry( printer );
2786 printer_handles[i - 1] = NULL;
2789 LeaveCriticalSection(&printer_handles_cs);
2793 /*****************************************************************************
2794 * DeleteFormA [WINSPOOL.@]
2796 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2798 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2802 /*****************************************************************************
2803 * DeleteFormW [WINSPOOL.@]
2805 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2807 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2811 /*****************************************************************************
2812 * DeletePrinter [WINSPOOL.@]
2814 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2816 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2817 HKEY hkeyPrinters, hkey;
2818 WCHAR def[MAX_PATH];
2819 DWORD size = sizeof( def ) / sizeof( def[0] );
2822 SetLastError(ERROR_INVALID_HANDLE);
2825 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2826 RegDeleteTreeW(hkeyPrinters, lpNameW);
2827 RegCloseKey(hkeyPrinters);
2829 WriteProfileStringW(devicesW, lpNameW, NULL);
2830 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2832 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2833 RegDeleteValueW(hkey, lpNameW);
2837 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2838 RegDeleteValueW(hkey, lpNameW);
2842 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2844 WriteProfileStringW( windowsW, deviceW, NULL );
2845 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2847 RegDeleteValueW( hkey, deviceW );
2848 RegCloseKey( hkey );
2850 SetDefaultPrinterW( NULL );
2856 /*****************************************************************************
2857 * SetPrinterA [WINSPOOL.@]
2859 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2866 dataW = printer_info_AtoW( data, level );
2867 if (!dataW) return FALSE;
2870 ret = SetPrinterW( printer, level, dataW, command );
2872 if (dataW != data) free_printer_info( dataW, level );
2877 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2879 if (!pi->pDevMode) return FALSE;
2881 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2885 /******************************************************************************
2886 * SetPrinterW [WINSPOOL.@]
2888 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2893 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2895 if (command != 0) FIXME( "Ignoring command %d\n", command );
2897 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2904 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2905 ret = set_printer_9( key, pi );
2910 FIXME( "Unimplemented level %d\n", level );
2911 SetLastError( ERROR_INVALID_LEVEL );
2918 /*****************************************************************************
2919 * SetJobA [WINSPOOL.@]
2921 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2922 LPBYTE pJob, DWORD Command)
2926 UNICODE_STRING usBuffer;
2928 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2930 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2931 are all ignored by SetJob, so we don't bother copying them */
2939 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2940 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2942 JobW = (LPBYTE)info1W;
2943 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2944 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2945 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2946 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2947 info1W->Status = info1A->Status;
2948 info1W->Priority = info1A->Priority;
2949 info1W->Position = info1A->Position;
2950 info1W->PagesPrinted = info1A->PagesPrinted;
2955 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2956 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2958 JobW = (LPBYTE)info2W;
2959 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2960 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2961 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2962 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2963 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2964 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2965 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2966 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2967 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2968 info2W->Status = info2A->Status;
2969 info2W->Priority = info2A->Priority;
2970 info2W->Position = info2A->Position;
2971 info2W->StartTime = info2A->StartTime;
2972 info2W->UntilTime = info2A->UntilTime;
2973 info2W->PagesPrinted = info2A->PagesPrinted;
2977 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2978 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2981 SetLastError(ERROR_INVALID_LEVEL);
2985 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2991 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2992 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2993 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2994 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2995 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3000 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3001 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3002 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3003 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3004 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3005 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3006 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3007 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3008 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3012 HeapFree(GetProcessHeap(), 0, JobW);
3017 /*****************************************************************************
3018 * SetJobW [WINSPOOL.@]
3020 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3021 LPBYTE pJob, DWORD Command)
3026 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3027 FIXME("Ignoring everything other than document title\n");
3029 EnterCriticalSection(&printer_handles_cs);
3030 job = get_job(hPrinter, JobId);
3040 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3041 HeapFree(GetProcessHeap(), 0, job->document_title);
3042 job->document_title = strdupW(info1->pDocument);
3047 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3048 HeapFree(GetProcessHeap(), 0, job->document_title);
3049 job->document_title = strdupW(info2->pDocument);
3050 HeapFree(GetProcessHeap(), 0, job->devmode);
3051 job->devmode = dup_devmode( info2->pDevMode );
3057 SetLastError(ERROR_INVALID_LEVEL);
3062 LeaveCriticalSection(&printer_handles_cs);
3066 /*****************************************************************************
3067 * EndDocPrinter [WINSPOOL.@]
3069 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3071 opened_printer_t *printer;
3073 TRACE("(%p)\n", hPrinter);
3075 EnterCriticalSection(&printer_handles_cs);
3077 printer = get_opened_printer(hPrinter);
3080 SetLastError(ERROR_INVALID_HANDLE);
3086 SetLastError(ERROR_SPL_NO_STARTDOC);
3090 CloseHandle(printer->doc->hf);
3091 ScheduleJob(hPrinter, printer->doc->job_id);
3092 HeapFree(GetProcessHeap(), 0, printer->doc);
3093 printer->doc = NULL;
3096 LeaveCriticalSection(&printer_handles_cs);
3100 /*****************************************************************************
3101 * EndPagePrinter [WINSPOOL.@]
3103 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3105 FIXME("(%p): stub\n", hPrinter);
3109 /*****************************************************************************
3110 * StartDocPrinterA [WINSPOOL.@]
3112 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3114 UNICODE_STRING usBuffer;
3116 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3119 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3120 or one (DOC_INFO_3) extra DWORDs */
3124 doc2W.JobId = doc2->JobId;
3127 doc2W.dwMode = doc2->dwMode;
3130 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3131 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3132 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3136 SetLastError(ERROR_INVALID_LEVEL);
3140 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3142 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3143 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3144 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3149 /*****************************************************************************
3150 * StartDocPrinterW [WINSPOOL.@]
3152 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3154 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3155 opened_printer_t *printer;
3156 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3157 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3158 JOB_INFO_1W job_info;
3159 DWORD needed, ret = 0;
3164 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3165 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3166 debugstr_w(doc->pDatatype));
3168 if(Level < 1 || Level > 3)
3170 SetLastError(ERROR_INVALID_LEVEL);
3174 EnterCriticalSection(&printer_handles_cs);
3175 printer = get_opened_printer(hPrinter);
3178 SetLastError(ERROR_INVALID_HANDLE);
3184 SetLastError(ERROR_INVALID_PRINTER_STATE);
3188 /* Even if we're printing to a file we still add a print job, we'll
3189 just ignore the spool file name */
3191 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3193 ERR("AddJob failed gle %u\n", GetLastError());
3197 /* use pOutputFile only, when it is a real filename */
3198 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3199 filename = doc->pOutputFile;
3201 filename = addjob->Path;
3203 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3204 if(hf == INVALID_HANDLE_VALUE)
3207 memset(&job_info, 0, sizeof(job_info));
3208 job_info.pDocument = doc->pDocName;
3209 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3211 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3212 printer->doc->hf = hf;
3213 ret = printer->doc->job_id = addjob->JobId;
3214 job = get_job(hPrinter, ret);
3215 job->portname = strdupW(doc->pOutputFile);
3218 LeaveCriticalSection(&printer_handles_cs);
3223 /*****************************************************************************
3224 * StartPagePrinter [WINSPOOL.@]
3226 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3228 FIXME("(%p): stub\n", hPrinter);
3232 /*****************************************************************************
3233 * GetFormA [WINSPOOL.@]
3235 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3236 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3238 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3239 Level,pForm,cbBuf,pcbNeeded);
3243 /*****************************************************************************
3244 * GetFormW [WINSPOOL.@]
3246 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3247 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3249 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3250 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3254 /*****************************************************************************
3255 * SetFormA [WINSPOOL.@]
3257 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3260 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3264 /*****************************************************************************
3265 * SetFormW [WINSPOOL.@]
3267 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3270 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3274 /*****************************************************************************
3275 * ReadPrinter [WINSPOOL.@]
3277 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3278 LPDWORD pNoBytesRead)
3280 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3284 /*****************************************************************************
3285 * ResetPrinterA [WINSPOOL.@]
3287 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3289 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3293 /*****************************************************************************
3294 * ResetPrinterW [WINSPOOL.@]
3296 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3298 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3302 /*****************************************************************************
3303 * WINSPOOL_GetDWORDFromReg
3305 * Return DWORD associated with ValueName from hkey.
3307 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3309 DWORD sz = sizeof(DWORD), type, value = 0;
3312 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3314 if(ret != ERROR_SUCCESS) {
3315 WARN("Got ret = %d on name %s\n", ret, ValueName);
3318 if(type != REG_DWORD) {
3319 ERR("Got type %d\n", type);
3326 /*****************************************************************************
3327 * get_filename_from_reg [internal]
3329 * Get ValueName from hkey storing result in out
3330 * when the Value in the registry has only a filename, use driverdir as prefix
3331 * outlen is space left in out
3332 * String is stored either as unicode or ascii
3336 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3337 LPBYTE out, DWORD outlen, LPDWORD needed)
3339 WCHAR filename[MAX_PATH];
3343 LPWSTR buffer = filename;
3347 size = sizeof(filename);
3349 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3350 if (ret == ERROR_MORE_DATA) {
3351 TRACE("need dynamic buffer: %u\n", size);
3352 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3354 /* No Memory is bad */
3358 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3361 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3362 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3368 /* do we have a full path ? */
3369 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3370 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3373 /* we must build the full Path */
3375 if ((out) && (outlen > dirlen)) {
3376 lstrcpyW((LPWSTR)out, driverdir);
3384 /* write the filename */
3385 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3386 if ((out) && (outlen >= size)) {
3387 lstrcpyW((LPWSTR)out, ptr);
3394 ptr += lstrlenW(ptr)+1;
3395 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3398 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3400 /* write the multisz-termination */
3401 if (type == REG_MULTI_SZ) {
3402 size = sizeof(WCHAR);
3405 if (out && (outlen >= size)) {
3406 memset (out, 0, size);
3412 /*****************************************************************************
3413 * WINSPOOL_GetStringFromReg
3415 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3416 * String is stored as unicode.
3418 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3419 DWORD buflen, DWORD *needed)
3421 DWORD sz = buflen, type;
3424 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3425 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3426 WARN("Got ret = %d\n", ret);
3430 /* add space for terminating '\0' */
3431 sz += sizeof(WCHAR);
3435 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3440 /*****************************************************************************
3441 * WINSPOOL_GetDefaultDevMode
3443 * Get a default DevMode values for wineps.
3447 static void WINSPOOL_GetDefaultDevMode(
3449 DWORD buflen, DWORD *needed)
3452 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3454 /* fill default DEVMODE - should be read from ppd... */
3455 ZeroMemory( &dm, sizeof(dm) );
3456 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3457 dm.dmSpecVersion = DM_SPECVERSION;
3458 dm.dmDriverVersion = 1;
3459 dm.dmSize = sizeof(DEVMODEW);
3460 dm.dmDriverExtra = 0;
3462 DM_ORIENTATION | DM_PAPERSIZE |
3463 DM_PAPERLENGTH | DM_PAPERWIDTH |
3466 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3467 DM_YRESOLUTION | DM_TTOPTION;
3469 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3470 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3471 dm.u1.s1.dmPaperLength = 2970;
3472 dm.u1.s1.dmPaperWidth = 2100;
3474 dm.u1.s1.dmScale = 100;
3475 dm.u1.s1.dmCopies = 1;
3476 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3477 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3480 dm.dmYResolution = 300; /* 300dpi */
3481 dm.dmTTOption = DMTT_BITMAP;
3484 /* dm.dmLogPixels */
3485 /* dm.dmBitsPerPel */
3486 /* dm.dmPelsWidth */
3487 /* dm.dmPelsHeight */
3488 /* dm.u2.dmDisplayFlags */
3489 /* dm.dmDisplayFrequency */
3490 /* dm.dmICMMethod */
3491 /* dm.dmICMIntent */
3492 /* dm.dmMediaType */
3493 /* dm.dmDitherType */
3494 /* dm.dmReserved1 */
3495 /* dm.dmReserved2 */
3496 /* dm.dmPanningWidth */
3497 /* dm.dmPanningHeight */
3499 if(buflen >= sizeof(DEVMODEW))
3500 memcpy(ptr, &dm, sizeof(DEVMODEW));
3501 *needed = sizeof(DEVMODEW);
3504 /*****************************************************************************
3505 * WINSPOOL_GetDevModeFromReg
3507 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3508 * DevMode is stored either as unicode or ascii.
3510 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3512 DWORD buflen, DWORD *needed)
3514 DWORD sz = buflen, type;
3517 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3518 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3519 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3520 if (sz < sizeof(DEVMODEA))
3522 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3525 /* ensures that dmSize is not erratically bogus if registry is invalid */
3526 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3527 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3528 sz += (CCHDEVICENAME + CCHFORMNAME);
3529 if (ptr && (buflen >= sz)) {
3530 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3531 memcpy(ptr, dmW, sz);
3532 HeapFree(GetProcessHeap(),0,dmW);
3538 /*********************************************************************
3539 * WINSPOOL_GetPrinter_1
3541 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3543 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3544 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3546 DWORD size, left = cbBuf;
3547 BOOL space = (cbBuf > 0);
3552 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3553 if(space && size <= left) {
3554 pi1->pName = (LPWSTR)ptr;
3562 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3563 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3564 if(space && size <= left) {
3565 pi1->pDescription = (LPWSTR)ptr;
3573 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3574 if(space && size <= left) {
3575 pi1->pComment = (LPWSTR)ptr;
3583 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3585 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3586 memset(pi1, 0, sizeof(*pi1));
3590 /*********************************************************************
3591 * WINSPOOL_GetPrinter_2
3593 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3595 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3596 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3598 DWORD size, left = cbBuf;
3599 BOOL space = (cbBuf > 0);
3604 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3605 if(space && size <= left) {
3606 pi2->pPrinterName = (LPWSTR)ptr;
3613 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3614 if(space && size <= left) {
3615 pi2->pShareName = (LPWSTR)ptr;
3622 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3623 if(space && size <= left) {
3624 pi2->pPortName = (LPWSTR)ptr;
3631 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3632 if(space && size <= left) {
3633 pi2->pDriverName = (LPWSTR)ptr;
3640 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3641 if(space && size <= left) {
3642 pi2->pComment = (LPWSTR)ptr;
3649 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3650 if(space && size <= left) {
3651 pi2->pLocation = (LPWSTR)ptr;
3658 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3659 if(space && size <= left) {
3660 pi2->pDevMode = (LPDEVMODEW)ptr;
3669 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3670 if(space && size <= left) {
3671 pi2->pDevMode = (LPDEVMODEW)ptr;
3678 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3679 if(space && size <= left) {
3680 pi2->pSepFile = (LPWSTR)ptr;
3687 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3688 if(space && size <= left) {
3689 pi2->pPrintProcessor = (LPWSTR)ptr;
3696 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3697 if(space && size <= left) {
3698 pi2->pDatatype = (LPWSTR)ptr;
3705 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3706 if(space && size <= left) {
3707 pi2->pParameters = (LPWSTR)ptr;
3715 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3716 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3717 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3718 "Default Priority");
3719 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3720 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3723 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3724 memset(pi2, 0, sizeof(*pi2));
3729 /*********************************************************************
3730 * WINSPOOL_GetPrinter_4
3732 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3734 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3735 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3737 DWORD size, left = cbBuf;
3738 BOOL space = (cbBuf > 0);
3743 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3744 if(space && size <= left) {
3745 pi4->pPrinterName = (LPWSTR)ptr;
3753 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3756 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3757 memset(pi4, 0, sizeof(*pi4));
3762 /*********************************************************************
3763 * WINSPOOL_GetPrinter_5
3765 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3767 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3768 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3770 DWORD size, left = cbBuf;
3771 BOOL space = (cbBuf > 0);
3776 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3777 if(space && size <= left) {
3778 pi5->pPrinterName = (LPWSTR)ptr;
3785 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3786 if(space && size <= left) {
3787 pi5->pPortName = (LPWSTR)ptr;
3795 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3796 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3798 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3802 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3803 memset(pi5, 0, sizeof(*pi5));
3808 /*********************************************************************
3809 * WINSPOOL_GetPrinter_7
3811 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3813 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3814 DWORD cbBuf, LPDWORD pcbNeeded)
3816 DWORD size, left = cbBuf;
3817 BOOL space = (cbBuf > 0);
3822 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3825 size = sizeof(pi7->pszObjectGUID);
3827 if (space && size <= left) {
3828 pi7->pszObjectGUID = (LPWSTR)ptr;
3835 /* We do not have a Directory Service */
3836 pi7->dwAction = DSPRINT_UNPUBLISH;
3839 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3840 memset(pi7, 0, sizeof(*pi7));
3845 /*********************************************************************
3846 * WINSPOOL_GetPrinter_9
3848 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3850 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3851 DWORD cbBuf, LPDWORD pcbNeeded)
3854 BOOL space = (cbBuf > 0);
3858 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3859 if(space && size <= cbBuf) {
3860 pi9->pDevMode = (LPDEVMODEW)buf;
3867 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3868 if(space && size <= cbBuf) {
3869 pi9->pDevMode = (LPDEVMODEW)buf;
3875 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3876 memset(pi9, 0, sizeof(*pi9));
3881 /*****************************************************************************
3882 * GetPrinterW [WINSPOOL.@]
3884 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3885 DWORD cbBuf, LPDWORD pcbNeeded)
3887 DWORD size, needed = 0, err;
3892 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3894 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3897 SetLastError( err );
3904 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3906 size = sizeof(PRINTER_INFO_2W);
3908 ptr = pPrinter + size;
3910 memset(pPrinter, 0, size);
3915 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3922 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3924 size = sizeof(PRINTER_INFO_4W);
3926 ptr = pPrinter + size;
3928 memset(pPrinter, 0, size);
3933 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3941 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3943 size = sizeof(PRINTER_INFO_5W);
3945 ptr = pPrinter + size;
3947 memset(pPrinter, 0, size);
3953 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3961 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3963 size = sizeof(PRINTER_INFO_6);
3964 if (size <= cbBuf) {
3965 /* FIXME: We do not update the status yet */
3966 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3978 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3980 size = sizeof(PRINTER_INFO_7W);
3981 if (size <= cbBuf) {
3982 ptr = pPrinter + size;
3984 memset(pPrinter, 0, size);
3990 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3997 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
3998 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4002 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4004 size = sizeof(PRINTER_INFO_9W);
4006 ptr = pPrinter + size;
4008 memset(pPrinter, 0, size);
4014 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4021 FIXME("Unimplemented level %d\n", Level);
4022 SetLastError(ERROR_INVALID_LEVEL);
4023 RegCloseKey(hkeyPrinter);
4027 RegCloseKey(hkeyPrinter);
4029 TRACE("returning %d needed = %d\n", ret, needed);
4030 if(pcbNeeded) *pcbNeeded = needed;
4032 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4036 /*****************************************************************************
4037 * GetPrinterA [WINSPOOL.@]
4039 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4040 DWORD cbBuf, LPDWORD pcbNeeded)
4046 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4048 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4050 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4051 HeapFree(GetProcessHeap(), 0, buf);
4056 /*****************************************************************************
4057 * WINSPOOL_EnumPrintersW
4059 * Implementation of EnumPrintersW
4061 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4062 DWORD dwLevel, LPBYTE lpbPrinters,
4063 DWORD cbBuf, LPDWORD lpdwNeeded,
4064 LPDWORD lpdwReturned)
4067 HKEY hkeyPrinters, hkeyPrinter;
4068 WCHAR PrinterName[255];
4069 DWORD needed = 0, number = 0;
4070 DWORD used, i, left;
4074 memset(lpbPrinters, 0, cbBuf);
4080 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4081 if(dwType == PRINTER_ENUM_DEFAULT)
4084 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4085 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4086 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4088 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4094 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4095 FIXME("dwType = %08x\n", dwType);
4096 SetLastError(ERROR_INVALID_FLAGS);
4100 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4102 ERR("Can't create Printers key\n");
4106 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4107 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4108 RegCloseKey(hkeyPrinters);
4109 ERR("Can't query Printers key\n");
4112 TRACE("Found %d printers\n", number);
4116 used = number * sizeof(PRINTER_INFO_1W);
4119 used = number * sizeof(PRINTER_INFO_2W);
4122 used = number * sizeof(PRINTER_INFO_4W);
4125 used = number * sizeof(PRINTER_INFO_5W);
4129 SetLastError(ERROR_INVALID_LEVEL);
4130 RegCloseKey(hkeyPrinters);
4133 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4135 for(i = 0; i < number; i++) {
4136 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4138 ERR("Can't enum key number %d\n", i);
4139 RegCloseKey(hkeyPrinters);
4142 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4143 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4145 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4146 RegCloseKey(hkeyPrinters);
4151 buf = lpbPrinters + used;
4152 left = cbBuf - used;
4160 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4163 if(pi) pi += sizeof(PRINTER_INFO_1W);
4166 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4169 if(pi) pi += sizeof(PRINTER_INFO_2W);
4172 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4175 if(pi) pi += sizeof(PRINTER_INFO_4W);
4178 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4181 if(pi) pi += sizeof(PRINTER_INFO_5W);
4184 ERR("Shouldn't be here!\n");
4185 RegCloseKey(hkeyPrinter);
4186 RegCloseKey(hkeyPrinters);
4189 RegCloseKey(hkeyPrinter);
4191 RegCloseKey(hkeyPrinters);
4198 memset(lpbPrinters, 0, cbBuf);
4199 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4203 *lpdwReturned = number;
4204 SetLastError(ERROR_SUCCESS);
4209 /******************************************************************
4210 * EnumPrintersW [WINSPOOL.@]
4212 * Enumerates the available printers, print servers and print
4213 * providers, depending on the specified flags, name and level.
4217 * If level is set to 1:
4218 * Returns an array of PRINTER_INFO_1 data structures in the
4219 * lpbPrinters buffer.
4221 * If level is set to 2:
4222 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4223 * Returns an array of PRINTER_INFO_2 data structures in the
4224 * lpbPrinters buffer. Note that according to MSDN also an
4225 * OpenPrinter should be performed on every remote printer.
4227 * If level is set to 4 (officially WinNT only):
4228 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4229 * Fast: Only the registry is queried to retrieve printer names,
4230 * no connection to the driver is made.
4231 * Returns an array of PRINTER_INFO_4 data structures in the
4232 * lpbPrinters buffer.
4234 * If level is set to 5 (officially WinNT4/Win9x only):
4235 * Fast: Only the registry is queried to retrieve printer names,
4236 * no connection to the driver is made.
4237 * Returns an array of PRINTER_INFO_5 data structures in the
4238 * lpbPrinters buffer.
4240 * If level set to 3 or 6+:
4241 * returns zero (failure!)
4243 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4247 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4248 * - Only levels 2, 4 and 5 are implemented at the moment.
4249 * - 16-bit printer drivers are not enumerated.
4250 * - Returned amount of bytes used/needed does not match the real Windoze
4251 * implementation (as in this implementation, all strings are part
4252 * of the buffer, whereas Win32 keeps them somewhere else)
4253 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4256 * - In a regular Wine installation, no registry settings for printers
4257 * exist, which makes this function return an empty list.
4259 BOOL WINAPI EnumPrintersW(
4260 DWORD dwType, /* [in] Types of print objects to enumerate */
4261 LPWSTR lpszName, /* [in] name of objects to enumerate */
4262 DWORD dwLevel, /* [in] type of printer info structure */
4263 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4264 DWORD cbBuf, /* [in] max size of buffer in bytes */
4265 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4266 LPDWORD lpdwReturned /* [out] number of entries returned */
4269 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4270 lpdwNeeded, lpdwReturned);
4273 /******************************************************************
4274 * EnumPrintersA [WINSPOOL.@]
4279 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4280 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4283 UNICODE_STRING pNameU;
4287 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4288 pPrinters, cbBuf, pcbNeeded, pcReturned);
4290 pNameW = asciitounicode(&pNameU, pName);
4292 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4293 MS Office need this */
4294 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4296 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4298 RtlFreeUnicodeString(&pNameU);
4300 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4302 HeapFree(GetProcessHeap(), 0, pPrintersW);
4306 /*****************************************************************************
4307 * WINSPOOL_GetDriverInfoFromReg [internal]
4309 * Enters the information from the registry into the DRIVER_INFO struct
4312 * zero if the printer driver does not exist in the registry
4313 * (only if Level > 1) otherwise nonzero
4315 static BOOL WINSPOOL_GetDriverInfoFromReg(
4318 const printenv_t * env,
4320 LPBYTE ptr, /* DRIVER_INFO */
4321 LPBYTE pDriverStrings, /* strings buffer */
4322 DWORD cbBuf, /* size of string buffer */
4323 LPDWORD pcbNeeded) /* space needed for str. */
4327 WCHAR driverdir[MAX_PATH];
4329 LPBYTE strPtr = pDriverStrings;
4330 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4332 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4333 debugstr_w(DriverName), env,
4334 Level, di, pDriverStrings, cbBuf);
4336 if (di) ZeroMemory(di, di_sizeof[Level]);
4338 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4339 if (*pcbNeeded <= cbBuf)
4340 strcpyW((LPWSTR)strPtr, DriverName);
4342 /* pName for level 1 has a different offset! */
4344 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4348 /* .cVersion and .pName for level > 1 */
4350 di->cVersion = env->driverversion;
4351 di->pName = (LPWSTR) strPtr;
4352 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4355 /* Reserve Space for the largest subdir and a Backslash*/
4356 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4357 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4358 /* Should never Fail */
4361 lstrcatW(driverdir, env->versionsubdir);
4362 lstrcatW(driverdir, backslashW);
4364 /* dirlen must not include the terminating zero */
4365 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4367 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4368 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4369 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4374 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4377 if (*pcbNeeded <= cbBuf) {
4378 lstrcpyW((LPWSTR)strPtr, env->envname);
4379 if (di) di->pEnvironment = (LPWSTR)strPtr;
4380 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4383 /* .pDriverPath is the Graphics rendering engine.
4384 The full Path is required to avoid a crash in some apps */
4385 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4387 if (*pcbNeeded <= cbBuf)
4388 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4390 if (di) di->pDriverPath = (LPWSTR)strPtr;
4391 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4394 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4395 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4397 if (*pcbNeeded <= cbBuf)
4398 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4400 if (di) di->pDataFile = (LPWSTR)strPtr;
4401 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4404 /* .pConfigFile is the Driver user Interface */
4405 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4407 if (*pcbNeeded <= cbBuf)
4408 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4410 if (di) di->pConfigFile = (LPWSTR)strPtr;
4411 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4415 RegCloseKey(hkeyDriver);
4416 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4421 RegCloseKey(hkeyDriver);
4422 FIXME("level 5: incomplete\n");
4427 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4429 if (*pcbNeeded <= cbBuf)
4430 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4432 if (di) di->pHelpFile = (LPWSTR)strPtr;
4433 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4436 /* .pDependentFiles */
4437 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4439 if (*pcbNeeded <= cbBuf)
4440 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4442 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4443 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4445 else if (GetVersion() & 0x80000000) {
4446 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4447 size = 2 * sizeof(WCHAR);
4449 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4451 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4452 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4455 /* .pMonitorName is the optional Language Monitor */
4456 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4458 if (*pcbNeeded <= cbBuf)
4459 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4461 if (di) di->pMonitorName = (LPWSTR)strPtr;
4462 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4465 /* .pDefaultDataType */
4466 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4468 if(*pcbNeeded <= cbBuf)
4469 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4471 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4472 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4476 RegCloseKey(hkeyDriver);
4477 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4481 /* .pszzPreviousNames */
4482 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4484 if(*pcbNeeded <= cbBuf)
4485 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4487 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4488 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4492 RegCloseKey(hkeyDriver);
4493 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4497 /* support is missing, but not important enough for a FIXME */
4498 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4501 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4503 if(*pcbNeeded <= cbBuf)
4504 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4506 if (di) di->pszMfgName = (LPWSTR)strPtr;
4507 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4511 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4513 if(*pcbNeeded <= cbBuf)
4514 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4516 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4517 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4520 /* .pszHardwareID */
4521 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4523 if(*pcbNeeded <= cbBuf)
4524 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4526 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4527 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4531 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4533 if(*pcbNeeded <= cbBuf)
4534 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4536 if (di) di->pszProvider = (LPWSTR)strPtr;
4537 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4541 RegCloseKey(hkeyDriver);
4545 /* support is missing, but not important enough for a FIXME */
4546 TRACE("level 8: incomplete\n");
4548 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4549 RegCloseKey(hkeyDriver);
4553 /*****************************************************************************
4554 * GetPrinterDriverW [WINSPOOL.@]
4556 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4557 DWORD Level, LPBYTE pDriverInfo,
4558 DWORD cbBuf, LPDWORD pcbNeeded)
4561 WCHAR DriverName[100];
4562 DWORD ret, type, size, needed = 0;
4564 HKEY hkeyPrinter, hkeyDrivers;
4565 const printenv_t * env;
4567 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4568 Level,pDriverInfo,cbBuf, pcbNeeded);
4571 ZeroMemory(pDriverInfo, cbBuf);
4573 if (!(name = get_opened_printer_name(hPrinter))) {
4574 SetLastError(ERROR_INVALID_HANDLE);
4578 if (Level < 1 || Level == 7 || Level > 8) {
4579 SetLastError(ERROR_INVALID_LEVEL);
4583 env = validate_envW(pEnvironment);
4584 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4586 ret = open_printer_reg_key( name, &hkeyPrinter );
4589 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4590 SetLastError( ret );
4594 size = sizeof(DriverName);
4596 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4597 (LPBYTE)DriverName, &size);
4598 RegCloseKey(hkeyPrinter);
4599 if(ret != ERROR_SUCCESS) {
4600 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4604 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4606 ERR("Can't create Drivers key\n");
4610 size = di_sizeof[Level];
4611 if ((size <= cbBuf) && pDriverInfo)
4612 ptr = pDriverInfo + size;
4614 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4615 env, Level, pDriverInfo, ptr,
4616 (cbBuf < size) ? 0 : cbBuf - size,
4618 RegCloseKey(hkeyDrivers);
4622 RegCloseKey(hkeyDrivers);
4624 if(pcbNeeded) *pcbNeeded = size + needed;
4625 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4626 if(cbBuf >= size + needed) return TRUE;
4627 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4631 /*****************************************************************************
4632 * GetPrinterDriverA [WINSPOOL.@]
4634 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4635 DWORD Level, LPBYTE pDriverInfo,
4636 DWORD cbBuf, LPDWORD pcbNeeded)
4639 UNICODE_STRING pEnvW;
4645 ZeroMemory(pDriverInfo, cbBuf);
4646 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4649 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4650 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4653 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4655 HeapFree(GetProcessHeap(), 0, buf);
4657 RtlFreeUnicodeString(&pEnvW);
4661 /*****************************************************************************
4662 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4664 * Return the PATH for the Printer-Drivers (UNICODE)
4667 * pName [I] Servername (NT only) or NULL (local Computer)
4668 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4669 * Level [I] Structure-Level (must be 1)
4670 * pDriverDirectory [O] PTR to Buffer that receives the Result
4671 * cbBuf [I] Size of Buffer at pDriverDirectory
4672 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4673 * required for pDriverDirectory
4676 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4677 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4678 * if cbBuf is too small
4680 * Native Values returned in pDriverDirectory on Success:
4681 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4682 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4683 *| win9x(Windows 4.0): "%winsysdir%"
4685 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4688 *- Only NULL or "" is supported for pName
4691 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4692 DWORD Level, LPBYTE pDriverDirectory,
4693 DWORD cbBuf, LPDWORD pcbNeeded)
4695 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4696 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4698 if ((backend == NULL) && !load_backend()) return FALSE;
4701 /* (Level != 1) is ignored in win9x */
4702 SetLastError(ERROR_INVALID_LEVEL);
4705 if (pcbNeeded == NULL) {
4706 /* (pcbNeeded == NULL) is ignored in win9x */
4707 SetLastError(RPC_X_NULL_REF_POINTER);
4711 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4712 pDriverDirectory, cbBuf, pcbNeeded);
4717 /*****************************************************************************
4718 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4720 * Return the PATH for the Printer-Drivers (ANSI)
4722 * See GetPrinterDriverDirectoryW.
4725 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4728 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4729 DWORD Level, LPBYTE pDriverDirectory,
4730 DWORD cbBuf, LPDWORD pcbNeeded)
4732 UNICODE_STRING nameW, environmentW;
4735 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4736 WCHAR *driverDirectoryW = NULL;
4738 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4739 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4741 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4743 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4744 else nameW.Buffer = NULL;
4745 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4746 else environmentW.Buffer = NULL;
4748 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4749 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4752 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4753 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4755 *pcbNeeded = needed;
4756 ret = (needed <= cbBuf) ? TRUE : FALSE;
4758 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4760 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4762 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4763 RtlFreeUnicodeString(&environmentW);
4764 RtlFreeUnicodeString(&nameW);
4769 /*****************************************************************************
4770 * AddPrinterDriverA [WINSPOOL.@]
4772 * See AddPrinterDriverW.
4775 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4777 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4778 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4781 /******************************************************************************
4782 * AddPrinterDriverW (WINSPOOL.@)
4784 * Install a Printer Driver
4787 * pName [I] Servername or NULL (local Computer)
4788 * level [I] Level for the supplied DRIVER_INFO_*W struct
4789 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4796 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4798 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4799 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4802 /*****************************************************************************
4803 * AddPrintProcessorA [WINSPOOL.@]
4805 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4806 LPSTR pPrintProcessorName)
4808 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4809 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4813 /*****************************************************************************
4814 * AddPrintProcessorW [WINSPOOL.@]
4816 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4817 LPWSTR pPrintProcessorName)
4819 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4820 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4824 /*****************************************************************************
4825 * AddPrintProvidorA [WINSPOOL.@]
4827 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4829 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4833 /*****************************************************************************
4834 * AddPrintProvidorW [WINSPOOL.@]
4836 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4838 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4842 /*****************************************************************************
4843 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4845 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4846 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4848 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4849 pDevModeOutput, pDevModeInput);
4853 /*****************************************************************************
4854 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4856 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4857 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4859 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4860 pDevModeOutput, pDevModeInput);
4864 /*****************************************************************************
4865 * PrinterProperties [WINSPOOL.@]
4867 * Displays a dialog to set the properties of the printer.
4870 * nonzero on success or zero on failure
4873 * implemented as stub only
4875 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4876 HANDLE hPrinter /* [in] handle to printer object */
4878 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4879 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4883 /*****************************************************************************
4884 * EnumJobsA [WINSPOOL.@]
4887 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4888 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4891 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4892 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4894 if(pcbNeeded) *pcbNeeded = 0;
4895 if(pcReturned) *pcReturned = 0;
4900 /*****************************************************************************
4901 * EnumJobsW [WINSPOOL.@]
4904 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4905 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4908 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4909 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4911 if(pcbNeeded) *pcbNeeded = 0;
4912 if(pcReturned) *pcReturned = 0;
4916 /*****************************************************************************
4917 * WINSPOOL_EnumPrinterDrivers [internal]
4919 * Delivers information about all printer drivers installed on the
4920 * localhost or a given server
4923 * nonzero on success or zero on failure. If the buffer for the returned
4924 * information is too small the function will return an error
4927 * - only implemented for localhost, foreign hosts will return an error
4929 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4930 DWORD Level, LPBYTE pDriverInfo,
4932 DWORD cbBuf, LPDWORD pcbNeeded,
4933 LPDWORD pcFound, DWORD data_offset)
4937 const printenv_t * env;
4939 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4940 debugstr_w(pName), debugstr_w(pEnvironment),
4941 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4943 env = validate_envW(pEnvironment);
4944 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4948 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4950 ERR("Can't open Drivers key\n");
4954 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4955 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4956 RegCloseKey(hkeyDrivers);
4957 ERR("Can't query Drivers key\n");
4960 TRACE("Found %d Drivers\n", *pcFound);
4962 /* get size of single struct
4963 * unicode and ascii structure have the same size
4965 size = di_sizeof[Level];
4967 if (data_offset == 0)
4968 data_offset = size * (*pcFound);
4969 *pcbNeeded = data_offset;
4971 for( i = 0; i < *pcFound; i++) {
4972 WCHAR DriverNameW[255];
4973 PBYTE table_ptr = NULL;
4974 PBYTE data_ptr = NULL;
4977 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4979 ERR("Can't enum key number %d\n", i);
4980 RegCloseKey(hkeyDrivers);
4984 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4985 table_ptr = pDriverInfo + (driver_index + i) * size;
4986 if (pDriverInfo && *pcbNeeded <= cbBuf)
4987 data_ptr = pDriverInfo + *pcbNeeded;
4989 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4990 env, Level, table_ptr, data_ptr,
4991 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4993 RegCloseKey(hkeyDrivers);
4997 *pcbNeeded += needed;
5000 RegCloseKey(hkeyDrivers);
5002 if(cbBuf < *pcbNeeded){
5003 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5010 /*****************************************************************************
5011 * EnumPrinterDriversW [WINSPOOL.@]
5013 * see function EnumPrinterDrivers for RETURNS, BUGS
5015 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5016 LPBYTE pDriverInfo, DWORD cbBuf,
5017 LPDWORD pcbNeeded, LPDWORD pcReturned)
5019 static const WCHAR allW[] = {'a','l','l',0};
5023 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5025 SetLastError(RPC_X_NULL_REF_POINTER);
5029 /* check for local drivers */
5030 if((pName) && (pName[0])) {
5031 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5032 SetLastError(ERROR_ACCESS_DENIED);
5036 /* check input parameter */
5037 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5038 SetLastError(ERROR_INVALID_LEVEL);
5042 if(pDriverInfo && cbBuf > 0)
5043 memset( pDriverInfo, 0, cbBuf);
5045 /* Exception: pull all printers */
5046 if (pEnvironment && !strcmpW(pEnvironment, allW))
5048 DWORD i, needed, bufsize = cbBuf;
5049 DWORD total_needed = 0;
5050 DWORD total_found = 0;
5053 /* Precompute the overall total; we need this to know
5054 where pointers end and data begins (i.e. data_offset) */
5055 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5058 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5059 NULL, 0, 0, &needed, &found, 0);
5060 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5061 total_needed += needed;
5062 total_found += found;
5065 data_offset = di_sizeof[Level] * total_found;
5070 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5073 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5074 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5075 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5077 *pcReturned += found;
5078 *pcbNeeded = needed;
5079 data_offset = needed;
5080 total_found += found;
5085 /* Normal behavior */
5086 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5087 0, cbBuf, pcbNeeded, &found, 0);
5089 *pcReturned = found;
5094 /*****************************************************************************
5095 * EnumPrinterDriversA [WINSPOOL.@]
5097 * see function EnumPrinterDrivers for RETURNS, BUGS
5099 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5100 LPBYTE pDriverInfo, DWORD cbBuf,
5101 LPDWORD pcbNeeded, LPDWORD pcReturned)
5104 UNICODE_STRING pNameW, pEnvironmentW;
5105 PWSTR pwstrNameW, pwstrEnvironmentW;
5109 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5111 pwstrNameW = asciitounicode(&pNameW, pName);
5112 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5114 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5115 buf, cbBuf, pcbNeeded, pcReturned);
5117 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5119 HeapFree(GetProcessHeap(), 0, buf);
5121 RtlFreeUnicodeString(&pNameW);
5122 RtlFreeUnicodeString(&pEnvironmentW);
5127 /******************************************************************************
5128 * EnumPortsA (WINSPOOL.@)
5133 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5134 LPDWORD pcbNeeded, LPDWORD pcReturned)
5137 LPBYTE bufferW = NULL;
5138 LPWSTR nameW = NULL;
5140 DWORD numentries = 0;
5143 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5144 cbBuf, pcbNeeded, pcReturned);
5146 /* convert servername to unicode */
5148 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5149 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5150 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5152 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5153 needed = cbBuf * sizeof(WCHAR);
5154 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5155 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5157 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5158 if (pcbNeeded) needed = *pcbNeeded;
5159 /* HeapReAlloc return NULL, when bufferW was NULL */
5160 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5161 HeapAlloc(GetProcessHeap(), 0, needed);
5163 /* Try again with the large Buffer */
5164 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5166 needed = pcbNeeded ? *pcbNeeded : 0;
5167 numentries = pcReturned ? *pcReturned : 0;
5170 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5171 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5174 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5175 DWORD entrysize = 0;
5178 LPPORT_INFO_2W pi2w;
5179 LPPORT_INFO_2A pi2a;
5182 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5184 /* First pass: calculate the size for all Entries */
5185 pi2w = (LPPORT_INFO_2W) bufferW;
5186 pi2a = (LPPORT_INFO_2A) pPorts;
5188 while (index < numentries) {
5190 needed += entrysize; /* PORT_INFO_?A */
5191 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5193 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5194 NULL, 0, NULL, NULL);
5196 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5197 NULL, 0, NULL, NULL);
5198 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5199 NULL, 0, NULL, NULL);
5201 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5202 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5203 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5206 /* check for errors and quit on failure */
5207 if (cbBuf < needed) {
5208 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5212 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5213 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5214 cbBuf -= len ; /* free Bytes in the user-Buffer */
5215 pi2w = (LPPORT_INFO_2W) bufferW;
5216 pi2a = (LPPORT_INFO_2A) pPorts;
5218 /* Second Pass: Fill the User Buffer (if we have one) */
5219 while ((index < numentries) && pPorts) {
5221 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5222 pi2a->pPortName = ptr;
5223 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5224 ptr, cbBuf , NULL, NULL);
5228 pi2a->pMonitorName = ptr;
5229 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5230 ptr, cbBuf, NULL, NULL);
5234 pi2a->pDescription = ptr;
5235 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5236 ptr, cbBuf, NULL, NULL);
5240 pi2a->fPortType = pi2w->fPortType;
5241 pi2a->Reserved = 0; /* documented: "must be zero" */
5244 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5245 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5246 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5251 if (pcbNeeded) *pcbNeeded = needed;
5252 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5254 HeapFree(GetProcessHeap(), 0, nameW);
5255 HeapFree(GetProcessHeap(), 0, bufferW);
5257 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5258 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5264 /******************************************************************************
5265 * EnumPortsW (WINSPOOL.@)
5267 * Enumerate available Ports
5270 * pName [I] Servername or NULL (local Computer)
5271 * Level [I] Structure-Level (1 or 2)
5272 * pPorts [O] PTR to Buffer that receives the Result
5273 * cbBuf [I] Size of Buffer at pPorts
5274 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5275 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5279 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5282 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5285 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5286 cbBuf, pcbNeeded, pcReturned);
5288 if ((backend == NULL) && !load_backend()) return FALSE;
5290 /* Level is not checked in win9x */
5291 if (!Level || (Level > 2)) {
5292 WARN("level (%d) is ignored in win9x\n", Level);
5293 SetLastError(ERROR_INVALID_LEVEL);
5296 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5297 SetLastError(RPC_X_NULL_REF_POINTER);
5301 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5304 /******************************************************************************
5305 * GetDefaultPrinterW (WINSPOOL.@)
5308 * This function must read the value from data 'device' of key
5309 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5311 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5315 WCHAR *buffer, *ptr;
5319 SetLastError(ERROR_INVALID_PARAMETER);
5323 /* make the buffer big enough for the stuff from the profile/registry,
5324 * the content must fit into the local buffer to compute the correct
5325 * size even if the extern buffer is too small or not given.
5326 * (20 for ,driver,port) */
5328 len = max(100, (insize + 20));
5329 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5331 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5333 SetLastError (ERROR_FILE_NOT_FOUND);
5337 TRACE("%s\n", debugstr_w(buffer));
5339 if ((ptr = strchrW(buffer, ',')) == NULL)
5341 SetLastError(ERROR_INVALID_NAME);
5347 *namesize = strlenW(buffer) + 1;
5348 if(!name || (*namesize > insize))
5350 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5354 strcpyW(name, buffer);
5357 HeapFree( GetProcessHeap(), 0, buffer);
5362 /******************************************************************************
5363 * GetDefaultPrinterA (WINSPOOL.@)
5365 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5369 WCHAR *bufferW = NULL;
5373 SetLastError(ERROR_INVALID_PARAMETER);
5377 if(name && *namesize) {
5379 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5382 if(!GetDefaultPrinterW( bufferW, namesize)) {
5387 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5391 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5394 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5397 HeapFree( GetProcessHeap(), 0, bufferW);
5402 /******************************************************************************
5403 * SetDefaultPrinterW (WINSPOOL.204)
5405 * Set the Name of the Default Printer
5408 * pszPrinter [I] Name of the Printer or NULL
5415 * When the Parameter is NULL or points to an Empty String and
5416 * a Default Printer was already present, then this Function changes nothing.
5417 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5418 * the First enumerated local Printer is used.
5421 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5423 WCHAR default_printer[MAX_PATH];
5424 LPWSTR buffer = NULL;
5430 TRACE("(%s)\n", debugstr_w(pszPrinter));
5431 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5433 default_printer[0] = '\0';
5434 size = sizeof(default_printer)/sizeof(WCHAR);
5436 /* if we have a default Printer, do nothing. */
5437 if (GetDefaultPrinterW(default_printer, &size))
5441 /* we have no default Printer: search local Printers and use the first */
5442 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5444 default_printer[0] = '\0';
5445 size = sizeof(default_printer)/sizeof(WCHAR);
5446 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5448 pszPrinter = default_printer;
5449 TRACE("using %s\n", debugstr_w(pszPrinter));
5454 if (pszPrinter == NULL) {
5455 TRACE("no local printer found\n");
5456 SetLastError(ERROR_FILE_NOT_FOUND);
5461 /* "pszPrinter" is never empty or NULL here. */
5462 namelen = lstrlenW(pszPrinter);
5463 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5464 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5466 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5467 HeapFree(GetProcessHeap(), 0, buffer);
5468 SetLastError(ERROR_FILE_NOT_FOUND);
5472 /* read the devices entry for the printer (driver,port) to build the string for the
5473 default device entry (printer,driver,port) */
5474 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5475 buffer[namelen] = ',';
5476 namelen++; /* move index to the start of the driver */
5478 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5479 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5481 TRACE("set device to %s\n", debugstr_w(buffer));
5483 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5484 TRACE("failed to set the device entry: %d\n", GetLastError());
5485 lres = ERROR_INVALID_PRINTER_NAME;
5488 /* remove the next section, when INIFileMapping is implemented */
5491 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5492 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5499 if (lres != ERROR_FILE_NOT_FOUND)
5500 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5502 SetLastError(ERROR_INVALID_PRINTER_NAME);
5506 HeapFree(GetProcessHeap(), 0, buffer);
5507 return (lres == ERROR_SUCCESS);
5510 /******************************************************************************
5511 * SetDefaultPrinterA (WINSPOOL.202)
5513 * See SetDefaultPrinterW.
5516 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5518 LPWSTR bufferW = NULL;
5521 TRACE("(%s)\n", debugstr_a(pszPrinter));
5523 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5524 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5525 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5527 res = SetDefaultPrinterW(bufferW);
5528 HeapFree(GetProcessHeap(), 0, bufferW);
5532 /******************************************************************************
5533 * SetPrinterDataExA (WINSPOOL.@)
5535 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5536 LPCSTR pValueName, DWORD Type,
5537 LPBYTE pData, DWORD cbData)
5539 HKEY hkeyPrinter, hkeySubkey;
5542 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5543 debugstr_a(pValueName), Type, pData, cbData);
5545 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5549 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5551 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5552 RegCloseKey(hkeyPrinter);
5555 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5556 RegCloseKey(hkeySubkey);
5557 RegCloseKey(hkeyPrinter);
5561 /******************************************************************************
5562 * SetPrinterDataExW (WINSPOOL.@)
5564 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5565 LPCWSTR pValueName, DWORD Type,
5566 LPBYTE pData, DWORD cbData)
5568 HKEY hkeyPrinter, hkeySubkey;
5571 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5572 debugstr_w(pValueName), Type, pData, cbData);
5574 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5578 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5580 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5581 RegCloseKey(hkeyPrinter);
5584 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5585 RegCloseKey(hkeySubkey);
5586 RegCloseKey(hkeyPrinter);
5590 /******************************************************************************
5591 * SetPrinterDataA (WINSPOOL.@)
5593 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5594 LPBYTE pData, DWORD cbData)
5596 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5600 /******************************************************************************
5601 * SetPrinterDataW (WINSPOOL.@)
5603 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5604 LPBYTE pData, DWORD cbData)
5606 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5610 /******************************************************************************
5611 * GetPrinterDataExA (WINSPOOL.@)
5613 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5614 LPCSTR pValueName, LPDWORD pType,
5615 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5617 opened_printer_t *printer;
5618 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5621 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5622 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5624 printer = get_opened_printer(hPrinter);
5625 if(!printer) return ERROR_INVALID_HANDLE;
5627 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5628 if (ret) return ret;
5630 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5632 if (printer->name) {
5634 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5636 RegCloseKey(hkeyPrinters);
5639 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5640 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5641 RegCloseKey(hkeyPrinter);
5642 RegCloseKey(hkeyPrinters);
5647 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5648 0, pType, pData, pcbNeeded);
5650 if (!ret && !pData) ret = ERROR_MORE_DATA;
5652 RegCloseKey(hkeySubkey);
5653 RegCloseKey(hkeyPrinter);
5654 RegCloseKey(hkeyPrinters);
5656 TRACE("--> %d\n", ret);
5660 /******************************************************************************
5661 * GetPrinterDataExW (WINSPOOL.@)
5663 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5664 LPCWSTR pValueName, LPDWORD pType,
5665 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5667 opened_printer_t *printer;
5668 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5671 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5672 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5674 printer = get_opened_printer(hPrinter);
5675 if(!printer) return ERROR_INVALID_HANDLE;
5677 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5678 if (ret) return ret;
5680 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5682 if (printer->name) {
5684 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5686 RegCloseKey(hkeyPrinters);
5689 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5690 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5691 RegCloseKey(hkeyPrinter);
5692 RegCloseKey(hkeyPrinters);
5697 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5698 0, pType, pData, pcbNeeded);
5700 if (!ret && !pData) ret = ERROR_MORE_DATA;
5702 RegCloseKey(hkeySubkey);
5703 RegCloseKey(hkeyPrinter);
5704 RegCloseKey(hkeyPrinters);
5706 TRACE("--> %d\n", ret);
5710 /******************************************************************************
5711 * GetPrinterDataA (WINSPOOL.@)
5713 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5714 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5716 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5717 pData, nSize, pcbNeeded);
5720 /******************************************************************************
5721 * GetPrinterDataW (WINSPOOL.@)
5723 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5724 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5726 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5727 pData, nSize, pcbNeeded);
5730 /*******************************************************************************
5731 * EnumPrinterDataExW [WINSPOOL.@]
5733 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5734 LPBYTE pEnumValues, DWORD cbEnumValues,
5735 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5737 HKEY hkPrinter, hkSubKey;
5738 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5739 cbValueNameLen, cbMaxValueLen, cbValueLen,
5744 PPRINTER_ENUM_VALUESW ppev;
5746 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5748 if (pKeyName == NULL || *pKeyName == 0)
5749 return ERROR_INVALID_PARAMETER;
5751 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5752 if (ret != ERROR_SUCCESS)
5754 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5759 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5760 if (ret != ERROR_SUCCESS)
5762 r = RegCloseKey (hkPrinter);
5763 if (r != ERROR_SUCCESS)
5764 WARN ("RegCloseKey returned %i\n", r);
5765 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5766 debugstr_w (pKeyName), ret);
5770 ret = RegCloseKey (hkPrinter);
5771 if (ret != ERROR_SUCCESS)
5773 ERR ("RegCloseKey returned %i\n", ret);
5774 r = RegCloseKey (hkSubKey);
5775 if (r != ERROR_SUCCESS)
5776 WARN ("RegCloseKey returned %i\n", r);
5780 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5781 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5782 if (ret != ERROR_SUCCESS)
5784 r = RegCloseKey (hkSubKey);
5785 if (r != ERROR_SUCCESS)
5786 WARN ("RegCloseKey returned %i\n", r);
5787 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5791 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5792 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5794 if (cValues == 0) /* empty key */
5796 r = RegCloseKey (hkSubKey);
5797 if (r != ERROR_SUCCESS)
5798 WARN ("RegCloseKey returned %i\n", r);
5799 *pcbEnumValues = *pnEnumValues = 0;
5800 return ERROR_SUCCESS;
5803 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5805 hHeap = GetProcessHeap ();
5808 ERR ("GetProcessHeap failed\n");
5809 r = RegCloseKey (hkSubKey);
5810 if (r != ERROR_SUCCESS)
5811 WARN ("RegCloseKey returned %i\n", r);
5812 return ERROR_OUTOFMEMORY;
5815 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5816 if (lpValueName == NULL)
5818 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5819 r = RegCloseKey (hkSubKey);
5820 if (r != ERROR_SUCCESS)
5821 WARN ("RegCloseKey returned %i\n", r);
5822 return ERROR_OUTOFMEMORY;
5825 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5826 if (lpValue == NULL)
5828 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5829 if (HeapFree (hHeap, 0, lpValueName) == 0)
5830 WARN ("HeapFree failed with code %i\n", GetLastError ());
5831 r = RegCloseKey (hkSubKey);
5832 if (r != ERROR_SUCCESS)
5833 WARN ("RegCloseKey returned %i\n", r);
5834 return ERROR_OUTOFMEMORY;
5837 TRACE ("pass 1: calculating buffer required for all names and values\n");
5839 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5841 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5843 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5845 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5846 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5847 NULL, NULL, lpValue, &cbValueLen);
5848 if (ret != ERROR_SUCCESS)
5850 if (HeapFree (hHeap, 0, lpValue) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5852 if (HeapFree (hHeap, 0, lpValueName) == 0)
5853 WARN ("HeapFree failed with code %i\n", GetLastError ());
5854 r = RegCloseKey (hkSubKey);
5855 if (r != ERROR_SUCCESS)
5856 WARN ("RegCloseKey returned %i\n", r);
5857 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5861 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5862 debugstr_w (lpValueName), dwIndex,
5863 cbValueNameLen + 1, cbValueLen);
5865 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5866 cbBufSize += cbValueLen;
5869 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5871 *pcbEnumValues = cbBufSize;
5872 *pnEnumValues = cValues;
5874 if (cbEnumValues < cbBufSize) /* buffer too small */
5876 if (HeapFree (hHeap, 0, lpValue) == 0)
5877 WARN ("HeapFree failed with code %i\n", GetLastError ());
5878 if (HeapFree (hHeap, 0, lpValueName) == 0)
5879 WARN ("HeapFree failed with code %i\n", GetLastError ());
5880 r = RegCloseKey (hkSubKey);
5881 if (r != ERROR_SUCCESS)
5882 WARN ("RegCloseKey returned %i\n", r);
5883 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5884 return ERROR_MORE_DATA;
5887 TRACE ("pass 2: copying all names and values to buffer\n");
5889 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5890 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5892 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5894 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5895 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5896 NULL, &dwType, lpValue, &cbValueLen);
5897 if (ret != ERROR_SUCCESS)
5899 if (HeapFree (hHeap, 0, lpValue) == 0)
5900 WARN ("HeapFree failed with code %i\n", GetLastError ());
5901 if (HeapFree (hHeap, 0, lpValueName) == 0)
5902 WARN ("HeapFree failed with code %i\n", GetLastError ());
5903 r = RegCloseKey (hkSubKey);
5904 if (r != ERROR_SUCCESS)
5905 WARN ("RegCloseKey returned %i\n", r);
5906 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5910 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5911 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5912 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5913 pEnumValues += cbValueNameLen;
5915 /* return # of *bytes* (including trailing \0), not # of chars */
5916 ppev[dwIndex].cbValueName = cbValueNameLen;
5918 ppev[dwIndex].dwType = dwType;
5920 memcpy (pEnumValues, lpValue, cbValueLen);
5921 ppev[dwIndex].pData = pEnumValues;
5922 pEnumValues += cbValueLen;
5924 ppev[dwIndex].cbData = cbValueLen;
5926 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5927 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5930 if (HeapFree (hHeap, 0, lpValue) == 0)
5932 ret = GetLastError ();
5933 ERR ("HeapFree failed with code %i\n", ret);
5934 if (HeapFree (hHeap, 0, lpValueName) == 0)
5935 WARN ("HeapFree failed with code %i\n", GetLastError ());
5936 r = RegCloseKey (hkSubKey);
5937 if (r != ERROR_SUCCESS)
5938 WARN ("RegCloseKey returned %i\n", r);
5942 if (HeapFree (hHeap, 0, lpValueName) == 0)
5944 ret = GetLastError ();
5945 ERR ("HeapFree failed with code %i\n", ret);
5946 r = RegCloseKey (hkSubKey);
5947 if (r != ERROR_SUCCESS)
5948 WARN ("RegCloseKey returned %i\n", r);
5952 ret = RegCloseKey (hkSubKey);
5953 if (ret != ERROR_SUCCESS)
5955 ERR ("RegCloseKey returned %i\n", ret);
5959 return ERROR_SUCCESS;
5962 /*******************************************************************************
5963 * EnumPrinterDataExA [WINSPOOL.@]
5965 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5966 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5967 * what Windows 2000 SP1 does.
5970 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5971 LPBYTE pEnumValues, DWORD cbEnumValues,
5972 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5976 DWORD ret, dwIndex, dwBufSize;
5980 TRACE ("%p %s\n", hPrinter, pKeyName);
5982 if (pKeyName == NULL || *pKeyName == 0)
5983 return ERROR_INVALID_PARAMETER;
5985 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5988 ret = GetLastError ();
5989 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5993 hHeap = GetProcessHeap ();
5996 ERR ("GetProcessHeap failed\n");
5997 return ERROR_OUTOFMEMORY;
6000 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6001 if (pKeyNameW == NULL)
6003 ERR ("Failed to allocate %i bytes from process heap\n",
6004 (LONG)(len * sizeof (WCHAR)));
6005 return ERROR_OUTOFMEMORY;
6008 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6010 ret = GetLastError ();
6011 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6012 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6013 WARN ("HeapFree failed with code %i\n", GetLastError ());
6017 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6018 pcbEnumValues, pnEnumValues);
6019 if (ret != ERROR_SUCCESS)
6021 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6022 WARN ("HeapFree failed with code %i\n", GetLastError ());
6023 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6027 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6029 ret = GetLastError ();
6030 ERR ("HeapFree failed with code %i\n", ret);
6034 if (*pnEnumValues == 0) /* empty key */
6035 return ERROR_SUCCESS;
6038 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6040 PPRINTER_ENUM_VALUESW ppev =
6041 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6043 if (dwBufSize < ppev->cbValueName)
6044 dwBufSize = ppev->cbValueName;
6046 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6047 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6048 dwBufSize = ppev->cbData;
6051 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6053 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6054 if (pBuffer == NULL)
6056 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6057 return ERROR_OUTOFMEMORY;
6060 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6062 PPRINTER_ENUM_VALUESW ppev =
6063 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6065 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6066 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6070 ret = GetLastError ();
6071 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6072 if (HeapFree (hHeap, 0, pBuffer) == 0)
6073 WARN ("HeapFree failed with code %i\n", GetLastError ());
6077 memcpy (ppev->pValueName, pBuffer, len);
6079 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6081 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6082 ppev->dwType != REG_MULTI_SZ)
6085 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6086 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6089 ret = GetLastError ();
6090 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6091 if (HeapFree (hHeap, 0, pBuffer) == 0)
6092 WARN ("HeapFree failed with code %i\n", GetLastError ());
6096 memcpy (ppev->pData, pBuffer, len);
6098 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6099 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6102 if (HeapFree (hHeap, 0, pBuffer) == 0)
6104 ret = GetLastError ();
6105 ERR ("HeapFree failed with code %i\n", ret);
6109 return ERROR_SUCCESS;
6112 /******************************************************************************
6113 * AbortPrinter (WINSPOOL.@)
6115 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6117 FIXME("(%p), stub!\n", hPrinter);
6121 /******************************************************************************
6122 * AddPortA (WINSPOOL.@)
6127 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6129 LPWSTR nameW = NULL;
6130 LPWSTR monitorW = NULL;
6134 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6137 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6138 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6139 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6143 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6144 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6145 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6147 res = AddPortW(nameW, hWnd, monitorW);
6148 HeapFree(GetProcessHeap(), 0, nameW);
6149 HeapFree(GetProcessHeap(), 0, monitorW);
6153 /******************************************************************************
6154 * AddPortW (WINSPOOL.@)
6156 * Add a Port for a specific Monitor
6159 * pName [I] Servername or NULL (local Computer)
6160 * hWnd [I] Handle to parent Window for the Dialog-Box
6161 * pMonitorName [I] Name of the Monitor that manage the Port
6168 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6170 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6172 if ((backend == NULL) && !load_backend()) return FALSE;
6174 if (!pMonitorName) {
6175 SetLastError(RPC_X_NULL_REF_POINTER);
6179 return backend->fpAddPort(pName, hWnd, pMonitorName);
6182 /******************************************************************************
6183 * AddPortExA (WINSPOOL.@)
6188 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6191 PORT_INFO_2A * pi2A;
6192 LPWSTR nameW = NULL;
6193 LPWSTR monitorW = NULL;
6197 pi2A = (PORT_INFO_2A *) pBuffer;
6199 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6200 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6202 if ((level < 1) || (level > 2)) {
6203 SetLastError(ERROR_INVALID_LEVEL);
6208 SetLastError(ERROR_INVALID_PARAMETER);
6213 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6214 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6215 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6219 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6220 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6221 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6224 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6226 if (pi2A->pPortName) {
6227 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6228 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6229 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6233 if (pi2A->pMonitorName) {
6234 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6235 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6236 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6239 if (pi2A->pDescription) {
6240 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6241 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6242 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6244 pi2W.fPortType = pi2A->fPortType;
6245 pi2W.Reserved = pi2A->Reserved;
6248 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6250 HeapFree(GetProcessHeap(), 0, nameW);
6251 HeapFree(GetProcessHeap(), 0, monitorW);
6252 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6253 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6254 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6259 /******************************************************************************
6260 * AddPortExW (WINSPOOL.@)
6262 * Add a Port for a specific Monitor, without presenting a user interface
6265 * pName [I] Servername or NULL (local Computer)
6266 * level [I] Structure-Level (1 or 2) for pBuffer
6267 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6268 * pMonitorName [I] Name of the Monitor that manage the Port
6275 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6279 pi2 = (PORT_INFO_2W *) pBuffer;
6281 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6282 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6283 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6284 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6286 if ((backend == NULL) && !load_backend()) return FALSE;
6288 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6289 SetLastError(ERROR_INVALID_PARAMETER);
6293 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6296 /******************************************************************************
6297 * AddPrinterConnectionA (WINSPOOL.@)
6299 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6301 FIXME("%s\n", debugstr_a(pName));
6305 /******************************************************************************
6306 * AddPrinterConnectionW (WINSPOOL.@)
6308 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6310 FIXME("%s\n", debugstr_w(pName));
6314 /******************************************************************************
6315 * AddPrinterDriverExW (WINSPOOL.@)
6317 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6320 * pName [I] Servername or NULL (local Computer)
6321 * level [I] Level for the supplied DRIVER_INFO_*W struct
6322 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6323 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6330 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6332 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6334 if ((backend == NULL) && !load_backend()) return FALSE;
6336 if (level < 2 || level == 5 || level == 7 || level > 8) {
6337 SetLastError(ERROR_INVALID_LEVEL);
6342 SetLastError(ERROR_INVALID_PARAMETER);
6346 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6349 /******************************************************************************
6350 * AddPrinterDriverExA (WINSPOOL.@)
6352 * See AddPrinterDriverExW.
6355 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6357 DRIVER_INFO_8A *diA;
6359 LPWSTR nameW = NULL;
6364 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6366 diA = (DRIVER_INFO_8A *) pDriverInfo;
6367 ZeroMemory(&diW, sizeof(diW));
6369 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6370 SetLastError(ERROR_INVALID_LEVEL);
6375 SetLastError(ERROR_INVALID_PARAMETER);
6379 /* convert servername to unicode */
6381 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6382 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6383 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6387 diW.cVersion = diA->cVersion;
6390 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6391 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6392 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6395 if (diA->pEnvironment) {
6396 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6397 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6398 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6401 if (diA->pDriverPath) {
6402 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6403 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6404 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6407 if (diA->pDataFile) {
6408 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6409 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6410 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6413 if (diA->pConfigFile) {
6414 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6415 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6416 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6419 if ((Level > 2) && diA->pDependentFiles) {
6420 lenA = multi_sz_lenA(diA->pDependentFiles);
6421 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6422 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6423 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6426 if ((Level > 2) && diA->pMonitorName) {
6427 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6428 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6429 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6432 if ((Level > 3) && diA->pDefaultDataType) {
6433 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6434 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6435 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6438 if ((Level > 3) && diA->pszzPreviousNames) {
6439 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6440 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6441 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6442 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6445 if ((Level > 5) && diA->pszMfgName) {
6446 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6447 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6448 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6451 if ((Level > 5) && diA->pszOEMUrl) {
6452 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6453 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6454 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6457 if ((Level > 5) && diA->pszHardwareID) {
6458 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6459 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6460 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6463 if ((Level > 5) && diA->pszProvider) {
6464 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6465 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6466 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6470 FIXME("level %u is incomplete\n", Level);
6473 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6474 TRACE("got %u with %u\n", res, GetLastError());
6475 HeapFree(GetProcessHeap(), 0, nameW);
6476 HeapFree(GetProcessHeap(), 0, diW.pName);
6477 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6478 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6479 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6480 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6481 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6482 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6483 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6484 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6485 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6486 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6487 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6488 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6490 TRACE("=> %u with %u\n", res, GetLastError());
6494 /******************************************************************************
6495 * ConfigurePortA (WINSPOOL.@)
6497 * See ConfigurePortW.
6500 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6502 LPWSTR nameW = NULL;
6503 LPWSTR portW = NULL;
6507 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6509 /* convert servername to unicode */
6511 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6512 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6513 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6516 /* convert portname to unicode */
6518 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6519 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6520 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6523 res = ConfigurePortW(nameW, hWnd, portW);
6524 HeapFree(GetProcessHeap(), 0, nameW);
6525 HeapFree(GetProcessHeap(), 0, portW);
6529 /******************************************************************************
6530 * ConfigurePortW (WINSPOOL.@)
6532 * Display the Configuration-Dialog for a specific Port
6535 * pName [I] Servername or NULL (local Computer)
6536 * hWnd [I] Handle to parent Window for the Dialog-Box
6537 * pPortName [I] Name of the Port, that should be configured
6544 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6547 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6549 if ((backend == NULL) && !load_backend()) return FALSE;
6552 SetLastError(RPC_X_NULL_REF_POINTER);
6556 return backend->fpConfigurePort(pName, hWnd, pPortName);
6559 /******************************************************************************
6560 * ConnectToPrinterDlg (WINSPOOL.@)
6562 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6564 FIXME("%p %x\n", hWnd, Flags);
6568 /******************************************************************************
6569 * DeletePrinterConnectionA (WINSPOOL.@)
6571 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6573 FIXME("%s\n", debugstr_a(pName));
6577 /******************************************************************************
6578 * DeletePrinterConnectionW (WINSPOOL.@)
6580 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6582 FIXME("%s\n", debugstr_w(pName));
6586 /******************************************************************************
6587 * DeletePrinterDriverExW (WINSPOOL.@)
6589 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6590 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6595 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6596 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6598 if(pName && pName[0])
6600 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6601 SetLastError(ERROR_INVALID_PARAMETER);
6607 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6608 SetLastError(ERROR_INVALID_PARAMETER);
6612 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6616 ERR("Can't open drivers key\n");
6620 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6623 RegCloseKey(hkey_drivers);
6628 /******************************************************************************
6629 * DeletePrinterDriverExA (WINSPOOL.@)
6631 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6632 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6634 UNICODE_STRING NameW, EnvW, DriverW;
6637 asciitounicode(&NameW, pName);
6638 asciitounicode(&EnvW, pEnvironment);
6639 asciitounicode(&DriverW, pDriverName);
6641 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6643 RtlFreeUnicodeString(&DriverW);
6644 RtlFreeUnicodeString(&EnvW);
6645 RtlFreeUnicodeString(&NameW);
6650 /******************************************************************************
6651 * DeletePrinterDataExW (WINSPOOL.@)
6653 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6656 FIXME("%p %s %s\n", hPrinter,
6657 debugstr_w(pKeyName), debugstr_w(pValueName));
6658 return ERROR_INVALID_PARAMETER;
6661 /******************************************************************************
6662 * DeletePrinterDataExA (WINSPOOL.@)
6664 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6667 FIXME("%p %s %s\n", hPrinter,
6668 debugstr_a(pKeyName), debugstr_a(pValueName));
6669 return ERROR_INVALID_PARAMETER;
6672 /******************************************************************************
6673 * DeletePrintProcessorA (WINSPOOL.@)
6675 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6677 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6678 debugstr_a(pPrintProcessorName));
6682 /******************************************************************************
6683 * DeletePrintProcessorW (WINSPOOL.@)
6685 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6687 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6688 debugstr_w(pPrintProcessorName));
6692 /******************************************************************************
6693 * DeletePrintProvidorA (WINSPOOL.@)
6695 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6697 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6698 debugstr_a(pPrintProviderName));
6702 /******************************************************************************
6703 * DeletePrintProvidorW (WINSPOOL.@)
6705 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6707 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6708 debugstr_w(pPrintProviderName));
6712 /******************************************************************************
6713 * EnumFormsA (WINSPOOL.@)
6715 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6716 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6718 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6719 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6723 /******************************************************************************
6724 * EnumFormsW (WINSPOOL.@)
6726 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6727 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6729 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6730 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6734 /*****************************************************************************
6735 * EnumMonitorsA [WINSPOOL.@]
6737 * See EnumMonitorsW.
6740 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6741 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6744 LPBYTE bufferW = NULL;
6745 LPWSTR nameW = NULL;
6747 DWORD numentries = 0;
6750 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6751 cbBuf, pcbNeeded, pcReturned);
6753 /* convert servername to unicode */
6755 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6756 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6759 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6760 needed = cbBuf * sizeof(WCHAR);
6761 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6762 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6764 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6765 if (pcbNeeded) needed = *pcbNeeded;
6766 /* HeapReAlloc return NULL, when bufferW was NULL */
6767 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6768 HeapAlloc(GetProcessHeap(), 0, needed);
6770 /* Try again with the large Buffer */
6771 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6773 numentries = pcReturned ? *pcReturned : 0;
6776 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6777 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6780 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6781 DWORD entrysize = 0;
6784 LPMONITOR_INFO_2W mi2w;
6785 LPMONITOR_INFO_2A mi2a;
6787 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6788 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6790 /* First pass: calculate the size for all Entries */
6791 mi2w = (LPMONITOR_INFO_2W) bufferW;
6792 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6794 while (index < numentries) {
6796 needed += entrysize; /* MONITOR_INFO_?A */
6797 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6799 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6800 NULL, 0, NULL, NULL);
6802 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6803 NULL, 0, NULL, NULL);
6804 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6805 NULL, 0, NULL, NULL);
6807 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6808 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6809 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6812 /* check for errors and quit on failure */
6813 if (cbBuf < needed) {
6814 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6818 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6819 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6820 cbBuf -= len ; /* free Bytes in the user-Buffer */
6821 mi2w = (LPMONITOR_INFO_2W) bufferW;
6822 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6824 /* Second Pass: Fill the User Buffer (if we have one) */
6825 while ((index < numentries) && pMonitors) {
6827 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6829 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6830 ptr, cbBuf , NULL, NULL);
6834 mi2a->pEnvironment = ptr;
6835 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6836 ptr, cbBuf, NULL, NULL);
6840 mi2a->pDLLName = ptr;
6841 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6842 ptr, cbBuf, NULL, NULL);
6846 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6847 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6848 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6852 if (pcbNeeded) *pcbNeeded = needed;
6853 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6855 HeapFree(GetProcessHeap(), 0, nameW);
6856 HeapFree(GetProcessHeap(), 0, bufferW);
6858 TRACE("returning %d with %d (%d byte for %d entries)\n",
6859 (res), GetLastError(), needed, numentries);
6865 /*****************************************************************************
6866 * EnumMonitorsW [WINSPOOL.@]
6868 * Enumerate available Port-Monitors
6871 * pName [I] Servername or NULL (local Computer)
6872 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6873 * pMonitors [O] PTR to Buffer that receives the Result
6874 * cbBuf [I] Size of Buffer at pMonitors
6875 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6876 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6880 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6883 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6884 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6887 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6888 cbBuf, pcbNeeded, pcReturned);
6890 if ((backend == NULL) && !load_backend()) return FALSE;
6892 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6893 SetLastError(RPC_X_NULL_REF_POINTER);
6897 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6900 /******************************************************************************
6901 * SpoolerInit (WINSPOOL.@)
6903 * Initialize the Spooler
6910 * The function fails on windows, when the spooler service is not running
6913 BOOL WINAPI SpoolerInit(void)
6916 if ((backend == NULL) && !load_backend()) return FALSE;
6920 /******************************************************************************
6921 * XcvDataW (WINSPOOL.@)
6923 * Execute commands in the Printmonitor DLL
6926 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6927 * pszDataName [i] Name of the command to execute
6928 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6929 * cbInputData [i] Size in Bytes of Buffer at pInputData
6930 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6931 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6932 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6933 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6940 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6941 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6943 * Minimal List of commands, that a Printmonitor DLL should support:
6945 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6946 *| "AddPort" : Add a Port
6947 *| "DeletePort": Delete a Port
6949 * Many Printmonitors support additional commands. Examples for localspl.dll:
6950 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6951 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6954 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6955 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6956 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6958 opened_printer_t *printer;
6960 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6961 pInputData, cbInputData, pOutputData,
6962 cbOutputData, pcbOutputNeeded, pdwStatus);
6964 if ((backend == NULL) && !load_backend()) return FALSE;
6966 printer = get_opened_printer(hXcv);
6967 if (!printer || (!printer->backend_printer)) {
6968 SetLastError(ERROR_INVALID_HANDLE);
6972 if (!pcbOutputNeeded) {
6973 SetLastError(ERROR_INVALID_PARAMETER);
6977 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6978 SetLastError(RPC_X_NULL_REF_POINTER);
6982 *pcbOutputNeeded = 0;
6984 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6985 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6989 /*****************************************************************************
6990 * EnumPrinterDataA [WINSPOOL.@]
6993 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6994 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6995 DWORD cbData, LPDWORD pcbData )
6997 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6998 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6999 return ERROR_NO_MORE_ITEMS;
7002 /*****************************************************************************
7003 * EnumPrinterDataW [WINSPOOL.@]
7006 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7007 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7008 DWORD cbData, LPDWORD pcbData )
7010 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7011 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7012 return ERROR_NO_MORE_ITEMS;
7015 /*****************************************************************************
7016 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7019 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7020 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7021 LPDWORD pcbNeeded, LPDWORD pcReturned)
7023 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7024 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7025 pcbNeeded, pcReturned);
7029 /*****************************************************************************
7030 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7033 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7034 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7035 LPDWORD pcbNeeded, LPDWORD pcReturned)
7037 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7038 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7039 pcbNeeded, pcReturned);
7043 /*****************************************************************************
7044 * EnumPrintProcessorsA [WINSPOOL.@]
7046 * See EnumPrintProcessorsW.
7049 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7050 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7053 LPBYTE bufferW = NULL;
7054 LPWSTR nameW = NULL;
7057 DWORD numentries = 0;
7060 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7061 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7063 /* convert names to unicode */
7065 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7066 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7067 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7070 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7071 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7072 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7075 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7076 needed = cbBuf * sizeof(WCHAR);
7077 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7078 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7080 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7081 if (pcbNeeded) needed = *pcbNeeded;
7082 /* HeapReAlloc return NULL, when bufferW was NULL */
7083 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7084 HeapAlloc(GetProcessHeap(), 0, needed);
7086 /* Try again with the large Buffer */
7087 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7089 numentries = pcReturned ? *pcReturned : 0;
7093 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7096 PPRINTPROCESSOR_INFO_1W ppiw;
7097 PPRINTPROCESSOR_INFO_1A ppia;
7099 /* First pass: calculate the size for all Entries */
7100 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7101 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7103 while (index < numentries) {
7105 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7106 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7108 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7109 NULL, 0, NULL, NULL);
7111 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7112 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7115 /* check for errors and quit on failure */
7116 if (cbBuf < needed) {
7117 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7122 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7123 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7124 cbBuf -= len ; /* free Bytes in the user-Buffer */
7125 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7126 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7128 /* Second Pass: Fill the User Buffer (if we have one) */
7129 while ((index < numentries) && pPPInfo) {
7131 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7133 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7134 ptr, cbBuf , NULL, NULL);
7138 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7139 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7144 if (pcbNeeded) *pcbNeeded = needed;
7145 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7147 HeapFree(GetProcessHeap(), 0, nameW);
7148 HeapFree(GetProcessHeap(), 0, envW);
7149 HeapFree(GetProcessHeap(), 0, bufferW);
7151 TRACE("returning %d with %d (%d byte for %d entries)\n",
7152 (res), GetLastError(), needed, numentries);
7157 /*****************************************************************************
7158 * EnumPrintProcessorsW [WINSPOOL.@]
7160 * Enumerate available Print Processors
7163 * pName [I] Servername or NULL (local Computer)
7164 * pEnvironment [I] Printing-Environment or NULL (Default)
7165 * Level [I] Structure-Level (Only 1 is allowed)
7166 * pPPInfo [O] PTR to Buffer that receives the Result
7167 * cbBuf [I] Size of Buffer at pPPInfo
7168 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7169 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7173 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7176 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7177 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7180 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7181 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7183 if ((backend == NULL) && !load_backend()) return FALSE;
7185 if (!pcbNeeded || !pcReturned) {
7186 SetLastError(RPC_X_NULL_REF_POINTER);
7190 if (!pPPInfo && (cbBuf > 0)) {
7191 SetLastError(ERROR_INVALID_USER_BUFFER);
7195 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7196 cbBuf, pcbNeeded, pcReturned);
7199 /*****************************************************************************
7200 * ExtDeviceMode [WINSPOOL.@]
7203 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7204 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7207 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7208 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7209 debugstr_a(pProfile), fMode);
7213 /*****************************************************************************
7214 * FindClosePrinterChangeNotification [WINSPOOL.@]
7217 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7219 FIXME("Stub: %p\n", hChange);
7223 /*****************************************************************************
7224 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7227 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7228 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7230 FIXME("Stub: %p %x %x %p\n",
7231 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7232 return INVALID_HANDLE_VALUE;
7235 /*****************************************************************************
7236 * FindNextPrinterChangeNotification [WINSPOOL.@]
7239 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7240 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7242 FIXME("Stub: %p %p %p %p\n",
7243 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7247 /*****************************************************************************
7248 * FreePrinterNotifyInfo [WINSPOOL.@]
7251 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7253 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7257 /*****************************************************************************
7260 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7261 * ansi depending on the unicode parameter.
7263 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7273 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7276 memcpy(ptr, str, *size);
7283 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7286 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7293 /*****************************************************************************
7296 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7297 LPDWORD pcbNeeded, BOOL unicode)
7299 DWORD size, left = cbBuf;
7300 BOOL space = (cbBuf > 0);
7307 ji1->JobId = job->job_id;
7310 string_to_buf(job->document_title, ptr, left, &size, unicode);
7311 if(space && size <= left)
7313 ji1->pDocument = (LPWSTR)ptr;
7321 if (job->printer_name)
7323 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7324 if(space && size <= left)
7326 ji1->pPrinterName = (LPWSTR)ptr;
7338 /*****************************************************************************
7341 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7342 LPDWORD pcbNeeded, BOOL unicode)
7344 DWORD size, left = cbBuf;
7346 BOOL space = (cbBuf > 0);
7348 LPDEVMODEA dmA = NULL;
7355 ji2->JobId = job->job_id;
7358 string_to_buf(job->document_title, ptr, left, &size, unicode);
7359 if(space && size <= left)
7361 ji2->pDocument = (LPWSTR)ptr;
7369 if (job->printer_name)
7371 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7372 if(space && size <= left)
7374 ji2->pPrinterName = (LPWSTR)ptr;
7387 dmA = DEVMODEdupWtoA(job->devmode);
7388 devmode = (LPDEVMODEW) dmA;
7389 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7393 devmode = job->devmode;
7394 size = devmode->dmSize + devmode->dmDriverExtra;
7398 FIXME("Can't convert DEVMODE W to A\n");
7401 /* align DEVMODE to a DWORD boundary */
7402 shift = (4 - (*pcbNeeded & 3)) & 3;
7408 memcpy(ptr, devmode, size-shift);
7409 ji2->pDevMode = (LPDEVMODEW)ptr;
7410 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7423 /*****************************************************************************
7426 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7427 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7430 DWORD needed = 0, size;
7434 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7436 EnterCriticalSection(&printer_handles_cs);
7437 job = get_job(hPrinter, JobId);
7444 size = sizeof(JOB_INFO_1W);
7449 memset(pJob, 0, size);
7453 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7458 size = sizeof(JOB_INFO_2W);
7463 memset(pJob, 0, size);
7467 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7472 size = sizeof(JOB_INFO_3);
7476 memset(pJob, 0, size);
7485 SetLastError(ERROR_INVALID_LEVEL);
7489 *pcbNeeded = needed;
7491 LeaveCriticalSection(&printer_handles_cs);
7495 /*****************************************************************************
7496 * GetJobA [WINSPOOL.@]
7499 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7500 DWORD cbBuf, LPDWORD pcbNeeded)
7502 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7505 /*****************************************************************************
7506 * GetJobW [WINSPOOL.@]
7509 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7510 DWORD cbBuf, LPDWORD pcbNeeded)
7512 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7515 /*****************************************************************************
7518 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7521 char *unixname, *cmdA;
7523 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7529 if(!(unixname = wine_get_unix_file_name(filename)))
7532 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7533 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7534 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7536 TRACE("printing with: %s\n", cmdA);
7538 if((file_fd = open(unixname, O_RDONLY)) == -1)
7543 ERR("pipe() failed!\n");
7547 if ((pid = fork()) == 0)
7553 /* reset signals that we previously set to SIG_IGN */
7554 signal(SIGPIPE, SIG_DFL);
7556 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7561 ERR("fork() failed!\n");
7565 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7566 write(fds[1], buf, no_read);
7573 wret = waitpid(pid, &status, 0);
7574 } while (wret < 0 && errno == EINTR);
7577 ERR("waitpid() failed!\n");
7580 if (!WIFEXITED(status) || WEXITSTATUS(status))
7582 ERR("child process failed! %d\n", status);
7589 if(file_fd != -1) close(file_fd);
7590 if(fds[0] != -1) close(fds[0]);
7591 if(fds[1] != -1) close(fds[1]);
7593 HeapFree(GetProcessHeap(), 0, cmdA);
7594 HeapFree(GetProcessHeap(), 0, unixname);
7601 /*****************************************************************************
7604 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7607 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7610 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7611 sprintfW(cmd, fmtW, printer_name);
7613 r = schedule_pipe(cmd, filename);
7615 HeapFree(GetProcessHeap(), 0, cmd);
7619 #ifdef SONAME_LIBCUPS
7620 /*****************************************************************************
7621 * get_cups_jobs_ticket_options
7623 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7624 * The CUPS scheduler only looks for these in Print-File requests, and since
7625 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7628 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7630 FILE *fp = fopen( file, "r" );
7631 char buf[257]; /* DSC max of 256 + '\0' */
7632 const char *ps_adobe = "%!PS-Adobe-";
7633 const char *cups_job = "%cupsJobTicket:";
7635 if (!fp) return num_options;
7636 if (!fgets( buf, sizeof(buf), fp )) goto end;
7637 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7638 while (fgets( buf, sizeof(buf), fp ))
7640 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7641 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7650 /*****************************************************************************
7653 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7655 #ifdef SONAME_LIBCUPS
7658 char *unixname, *queue, *unix_doc_title;
7661 int num_options = 0, i;
7662 cups_option_t *options = NULL;
7664 if(!(unixname = wine_get_unix_file_name(filename)))
7667 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7668 queue = HeapAlloc(GetProcessHeap(), 0, len);
7669 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7671 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7672 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7673 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7675 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7677 TRACE( "printing via cups with options:\n" );
7678 for (i = 0; i < num_options; i++)
7679 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7681 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7683 pcupsFreeOptions( num_options, options );
7685 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7686 HeapFree(GetProcessHeap(), 0, queue);
7687 HeapFree(GetProcessHeap(), 0, unixname);
7693 return schedule_lpr(printer_name, filename);
7697 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7704 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7708 if(HIWORD(wparam) == BN_CLICKED)
7710 if(LOWORD(wparam) == IDOK)
7713 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7716 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7717 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7719 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7721 WCHAR caption[200], message[200];
7724 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7725 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7726 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7727 if(mb_ret == IDCANCEL)
7729 HeapFree(GetProcessHeap(), 0, filename);
7733 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7734 if(hf == INVALID_HANDLE_VALUE)
7736 WCHAR caption[200], message[200];
7738 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7739 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7740 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7741 HeapFree(GetProcessHeap(), 0, filename);
7745 DeleteFileW(filename);
7746 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7748 EndDialog(hwnd, IDOK);
7751 if(LOWORD(wparam) == IDCANCEL)
7753 EndDialog(hwnd, IDCANCEL);
7762 /*****************************************************************************
7765 static BOOL get_filename(LPWSTR *filename)
7767 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7768 file_dlg_proc, (LPARAM)filename) == IDOK;
7771 /*****************************************************************************
7774 static BOOL schedule_file(LPCWSTR filename)
7776 LPWSTR output = NULL;
7778 if(get_filename(&output))
7781 TRACE("copy to %s\n", debugstr_w(output));
7782 r = CopyFileW(filename, output, FALSE);
7783 HeapFree(GetProcessHeap(), 0, output);
7789 /*****************************************************************************
7792 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7794 int in_fd, out_fd, no_read;
7797 char *unixname, *outputA;
7800 if(!(unixname = wine_get_unix_file_name(filename)))
7803 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7804 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7805 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7807 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7808 in_fd = open(unixname, O_RDONLY);
7809 if(out_fd == -1 || in_fd == -1)
7812 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7813 write(out_fd, buf, no_read);
7817 if(in_fd != -1) close(in_fd);
7818 if(out_fd != -1) close(out_fd);
7819 HeapFree(GetProcessHeap(), 0, outputA);
7820 HeapFree(GetProcessHeap(), 0, unixname);
7824 /*****************************************************************************
7825 * ScheduleJob [WINSPOOL.@]
7828 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7830 opened_printer_t *printer;
7832 struct list *cursor, *cursor2;
7834 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7835 EnterCriticalSection(&printer_handles_cs);
7836 printer = get_opened_printer(hPrinter);
7840 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7842 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7845 if(job->job_id != dwJobID) continue;
7847 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7848 if(hf != INVALID_HANDLE_VALUE)
7850 PRINTER_INFO_5W *pi5 = NULL;
7851 LPWSTR portname = job->portname;
7855 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7856 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7860 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7861 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7862 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7863 portname = pi5->pPortName;
7865 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7866 debugstr_w(portname));
7870 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7871 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7873 DWORD type, count = sizeof(output);
7874 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7877 if(output[0] == '|')
7879 ret = schedule_pipe(output + 1, job->filename);
7883 ret = schedule_unixfile(output, job->filename);
7885 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7887 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7889 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7891 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7893 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7895 ret = schedule_file(job->filename);
7899 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7901 HeapFree(GetProcessHeap(), 0, pi5);
7903 DeleteFileW(job->filename);
7905 list_remove(cursor);
7906 HeapFree(GetProcessHeap(), 0, job->document_title);
7907 HeapFree(GetProcessHeap(), 0, job->printer_name);
7908 HeapFree(GetProcessHeap(), 0, job->portname);
7909 HeapFree(GetProcessHeap(), 0, job->filename);
7910 HeapFree(GetProcessHeap(), 0, job->devmode);
7911 HeapFree(GetProcessHeap(), 0, job);
7915 LeaveCriticalSection(&printer_handles_cs);
7919 /*****************************************************************************
7920 * StartDocDlgA [WINSPOOL.@]
7922 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7924 UNICODE_STRING usBuffer;
7927 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7930 docW.cbSize = sizeof(docW);
7931 if (doc->lpszDocName)
7933 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7934 if (!(docW.lpszDocName = docnameW)) return NULL;
7936 if (doc->lpszOutput)
7938 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7939 if (!(docW.lpszOutput = outputW)) return NULL;
7941 if (doc->lpszDatatype)
7943 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7944 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7946 docW.fwType = doc->fwType;
7948 retW = StartDocDlgW(hPrinter, &docW);
7952 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7953 ret = HeapAlloc(GetProcessHeap(), 0, len);
7954 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7955 HeapFree(GetProcessHeap(), 0, retW);
7958 HeapFree(GetProcessHeap(), 0, datatypeW);
7959 HeapFree(GetProcessHeap(), 0, outputW);
7960 HeapFree(GetProcessHeap(), 0, docnameW);
7965 /*****************************************************************************
7966 * StartDocDlgW [WINSPOOL.@]
7968 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7969 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7970 * port is "FILE:". Also returns the full path if passed a relative path.
7972 * The caller should free the returned string from the process heap.
7974 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7979 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7981 PRINTER_INFO_5W *pi5;
7982 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7983 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7985 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7986 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7987 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7989 HeapFree(GetProcessHeap(), 0, pi5);
7992 HeapFree(GetProcessHeap(), 0, pi5);
7995 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7999 if (get_filename(&name))
8001 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8003 HeapFree(GetProcessHeap(), 0, name);
8006 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8007 GetFullPathNameW(name, len, ret, NULL);
8008 HeapFree(GetProcessHeap(), 0, name);
8013 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8016 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8017 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8019 attr = GetFileAttributesW(ret);
8020 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8022 HeapFree(GetProcessHeap(), 0, ret);