4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer;
107 WCHAR *document_title;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
121 /* ############################### */
123 static opened_printer_t **printer_handles;
124 static UINT nb_printer_handles;
125 static LONG next_job_id = 1;
127 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
128 WORD fwCapability, LPSTR lpszOutput,
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
135 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
186 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
187 static const WCHAR backslashW[] = {'\\',0};
188 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW[] = {'R','A','W',0};
222 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW[] = {',',0};
226 static WCHAR emptyStringW[] = {0};
228 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
230 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
234 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
237 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
238 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
239 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
240 0, sizeof(DRIVER_INFO_8W)};
243 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
244 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
245 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
246 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
247 sizeof(PRINTER_INFO_9W)};
249 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
251 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
253 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
259 * env [I] PTR to Environment-String or NULL
263 * Success: PTR to printenv_t
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
271 static const printenv_t * validate_envW(LPCWSTR env)
273 const printenv_t *result = NULL;
276 TRACE("testing %s\n", debugstr_w(env));
279 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
281 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
283 result = all_printenv[i];
288 if (result == NULL) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env));
290 SetLastError(ERROR_INVALID_ENVIRONMENT);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
296 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
298 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
312 return usBufferPtr->Buffer;
314 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
318 static LPWSTR strdupW(LPCWSTR p)
324 len = (strlenW(p) + 1) * sizeof(WCHAR);
325 ret = HeapAlloc(GetProcessHeap(), 0, len);
330 static LPSTR strdupWtoA( LPCWSTR str )
335 if (!str) return NULL;
336 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
337 ret = HeapAlloc( GetProcessHeap(), 0, len );
338 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
342 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
346 if (!dm) return NULL;
347 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
348 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
352 /***********************************************************
354 * Creates an ansi copy of supplied devmode
356 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
361 if (!dmW) return NULL;
362 size = dmW->dmSize - CCHDEVICENAME -
363 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
365 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
366 if (!dmA) return NULL;
368 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
369 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
371 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
373 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
374 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
378 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
379 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
380 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
381 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
383 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
387 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
392 /******************************************************************
393 * verify, that the filename is a local file
396 static inline BOOL is_local_file(LPWSTR name)
398 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
401 /* ################################ */
403 static int multi_sz_lenA(const char *str)
405 const char *ptr = str;
409 ptr += lstrlenA(ptr) + 1;
412 return ptr - str + 1;
416 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
419 /* If forcing, or no profile string entry for device yet, set the entry
421 * The always change entry if not WINEPS yet is discussable.
424 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
426 !strstr(qbuf,"WINEPS.DRV")
428 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
431 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
432 WriteProfileStringA("windows","device",buf);
433 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
434 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
437 HeapFree(GetProcessHeap(),0,buf);
441 static BOOL add_printer_driver(WCHAR *name)
445 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
448 di3.pEnvironment = envname_x86W;
449 di3.pDriverPath = driver_nt;
450 di3.pDataFile = generic_ppdW;
451 di3.pConfigFile = driver_nt;
452 di3.pDefaultDataType = rawW;
454 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
455 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
458 di3.pEnvironment = envname_win40W;
459 di3.pDriverPath = driver_9x;
460 di3.pConfigFile = driver_9x;
461 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
462 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
467 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
471 #ifdef SONAME_LIBCUPS
473 static void *cupshandle;
476 DO_FUNC(cupsFreeDests); \
477 DO_FUNC(cupsFreeOptions); \
478 DO_FUNC(cupsGetDests); \
479 DO_FUNC(cupsGetPPD); \
480 DO_FUNC(cupsParseOptions); \
481 DO_FUNC(cupsPrintFile);
483 #define DO_FUNC(f) static typeof(f) *p##f
487 static BOOL CUPS_LoadPrinters(void)
490 BOOL hadprinter = FALSE, haddefault = FALSE;
494 HKEY hkeyPrinter, hkeyPrinters;
496 WCHAR nameW[MAX_PATH];
497 HANDLE added_printer;
499 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
501 TRACE("%s\n", loaderror);
504 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
506 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
510 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
512 ERR("Can't create Printers key\n");
516 nrofdests = pcupsGetDests(&dests);
517 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
518 for (i=0;i<nrofdests;i++) {
519 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
521 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
522 lstrcpyW(port, CUPS_Port);
523 lstrcatW(port, nameW);
525 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
526 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
527 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
529 TRACE("Printer already exists\n");
530 /* overwrite old LPR:* port */
531 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
532 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
533 RegCloseKey(hkeyPrinter);
535 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
536 ' ','u','s','i','n','g',' ','C','U','P','S',0};
538 add_printer_driver(nameW);
540 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
541 pi2.pPrinterName = nameW;
542 pi2.pDatatype = rawW;
543 pi2.pPrintProcessor = WinPrintW;
544 pi2.pDriverName = nameW;
545 pi2.pComment = comment_cups;
546 pi2.pLocation = emptyStringW;
547 pi2.pPortName = port;
548 pi2.pParameters = emptyStringW;
549 pi2.pShareName = emptyStringW;
550 pi2.pSepFile = emptyStringW;
552 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
553 if (added_printer) ClosePrinter( added_printer );
554 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
555 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
557 HeapFree(GetProcessHeap(),0,port);
560 if (dests[i].is_default) {
561 SetDefaultPrinterW(nameW);
565 if (hadprinter && !haddefault) {
566 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
567 SetDefaultPrinterW(nameW);
569 pcupsFreeDests(nrofdests, dests);
570 RegCloseKey(hkeyPrinters);
575 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
577 PRINTER_INFO_2A pinfo2a;
580 char *e,*s,*name,*prettyname,*devname;
581 BOOL ret = FALSE, set_default = FALSE;
582 char *port = NULL, *env_default;
583 HKEY hkeyPrinter, hkeyPrinters;
584 WCHAR devnameW[MAX_PATH];
585 HANDLE added_printer;
587 while (isspace(*pent)) pent++;
588 r = strchr(pent,':');
592 name_len = strlen(pent);
593 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
594 memcpy(name, pent, name_len);
595 name[name_len] = '\0';
601 TRACE("name=%s entry=%s\n",name, pent);
603 if(ispunct(*name)) { /* a tc entry, not a real printer */
604 TRACE("skipping tc entry\n");
608 if(strstr(pent,":server")) { /* server only version so skip */
609 TRACE("skipping server entry\n");
613 /* Determine whether this is a postscript printer. */
616 env_default = getenv("PRINTER");
618 /* Get longest name, usually the one at the right for later display. */
619 while((s=strchr(prettyname,'|'))) {
622 while(isspace(*--e)) *e = '\0';
623 TRACE("\t%s\n", debugstr_a(prettyname));
624 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
625 for(prettyname = s+1; isspace(*prettyname); prettyname++)
628 e = prettyname + strlen(prettyname);
629 while(isspace(*--e)) *e = '\0';
630 TRACE("\t%s\n", debugstr_a(prettyname));
631 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
633 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
634 * if it is too long, we use it as comment below. */
635 devname = prettyname;
636 if (strlen(devname)>=CCHDEVICENAME-1)
638 if (strlen(devname)>=CCHDEVICENAME-1) {
643 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
644 sprintf(port,"LPR:%s",name);
646 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
648 ERR("Can't create Printers key\n");
653 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
655 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
656 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
658 TRACE("Printer already exists\n");
659 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
660 RegCloseKey(hkeyPrinter);
662 static CHAR data_type[] = "RAW",
663 print_proc[] = "WinPrint",
664 comment[] = "WINEPS Printer using LPR",
665 params[] = "<parameters?>",
666 share_name[] = "<share name?>",
667 sep_file[] = "<sep file?>";
669 add_printer_driver(devnameW);
671 memset(&pinfo2a,0,sizeof(pinfo2a));
672 pinfo2a.pPrinterName = devname;
673 pinfo2a.pDatatype = data_type;
674 pinfo2a.pPrintProcessor = print_proc;
675 pinfo2a.pDriverName = devname;
676 pinfo2a.pComment = comment;
677 pinfo2a.pLocation = prettyname;
678 pinfo2a.pPortName = port;
679 pinfo2a.pParameters = params;
680 pinfo2a.pShareName = share_name;
681 pinfo2a.pSepFile = sep_file;
683 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
684 if (added_printer) ClosePrinter( added_printer );
685 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
686 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
688 RegCloseKey(hkeyPrinters);
690 if (isfirst || set_default)
691 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
694 HeapFree(GetProcessHeap(), 0, port);
695 HeapFree(GetProcessHeap(), 0, name);
700 PRINTCAP_LoadPrinters(void) {
701 BOOL hadprinter = FALSE;
705 BOOL had_bash = FALSE;
707 f = fopen("/etc/printcap","r");
711 while(fgets(buf,sizeof(buf),f)) {
714 end=strchr(buf,'\n');
718 while(isspace(*start)) start++;
719 if(*start == '#' || *start == '\0')
722 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
723 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
724 HeapFree(GetProcessHeap(),0,pent);
728 if (end && *--end == '\\') {
735 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
738 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
744 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
745 HeapFree(GetProcessHeap(),0,pent);
751 static inline DWORD set_reg_DWORD(HKEY hkey, LPCSTR keyname, const DWORD value)
753 return RegSetValueExA(hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
756 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
759 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
760 (lstrlenW(value) + 1) * sizeof(WCHAR));
762 return ERROR_FILE_NOT_FOUND;
765 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
767 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
768 DWORD ret = ERROR_FILE_NOT_FOUND;
770 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
771 and we support these drivers. NT writes DEVMODEW so somehow
772 we'll need to distinguish between these when we support NT
777 ret = RegSetValueExW( key, name, 0, REG_BINARY,
778 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
779 HeapFree( GetProcessHeap(), 0, dmA );
785 /******************************************************************
786 * get_servername_from_name (internal)
788 * for an external server, a copy of the serverpart from the full name is returned
791 static LPWSTR get_servername_from_name(LPCWSTR name)
795 WCHAR buffer[MAX_PATH];
798 if (name == NULL) return NULL;
799 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
801 server = strdupW(&name[2]); /* skip over both backslash */
802 if (server == NULL) return NULL;
804 /* strip '\' and the printername */
805 ptr = strchrW(server, '\\');
806 if (ptr) ptr[0] = '\0';
808 TRACE("found %s\n", debugstr_w(server));
810 len = sizeof(buffer)/sizeof(buffer[0]);
811 if (GetComputerNameW(buffer, &len)) {
812 if (lstrcmpW(buffer, server) == 0) {
813 /* The requested Servername is our computername */
814 HeapFree(GetProcessHeap(), 0, server);
821 /******************************************************************
822 * get_basename_from_name (internal)
824 * skip over the serverpart from the full name
827 static LPCWSTR get_basename_from_name(LPCWSTR name)
829 if (name == NULL) return NULL;
830 if ((name[0] == '\\') && (name[1] == '\\')) {
831 /* skip over the servername and search for the following '\' */
832 name = strchrW(&name[2], '\\');
833 if ((name) && (name[1])) {
834 /* found a separator ('\') followed by a name:
835 skip over the separator and return the rest */
840 /* no basename present (we found only a servername) */
847 static void free_printer_entry( opened_printer_t *printer )
849 /* the queue is shared, so don't free that here */
850 HeapFree( GetProcessHeap(), 0, printer->printername );
851 HeapFree( GetProcessHeap(), 0, printer->name );
852 HeapFree( GetProcessHeap(), 0, printer->devmode );
853 HeapFree( GetProcessHeap(), 0, printer );
856 /******************************************************************
857 * get_opened_printer_entry
858 * Get the first place empty in the opened printer table
861 * - pDefault is ignored
863 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
865 UINT_PTR handle = nb_printer_handles, i;
866 jobqueue_t *queue = NULL;
867 opened_printer_t *printer = NULL;
871 if ((backend == NULL) && !load_backend()) return NULL;
873 servername = get_servername_from_name(name);
875 FIXME("server %s not supported\n", debugstr_w(servername));
876 HeapFree(GetProcessHeap(), 0, servername);
877 SetLastError(ERROR_INVALID_PRINTER_NAME);
881 printername = get_basename_from_name(name);
882 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
884 /* an empty printername is invalid */
885 if (printername && (!printername[0])) {
886 SetLastError(ERROR_INVALID_PARAMETER);
890 EnterCriticalSection(&printer_handles_cs);
892 for (i = 0; i < nb_printer_handles; i++)
894 if (!printer_handles[i])
896 if(handle == nb_printer_handles)
901 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
902 queue = printer_handles[i]->queue;
906 if (handle >= nb_printer_handles)
908 opened_printer_t **new_array;
910 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
911 (nb_printer_handles + 16) * sizeof(*new_array) );
913 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
914 (nb_printer_handles + 16) * sizeof(*new_array) );
921 printer_handles = new_array;
922 nb_printer_handles += 16;
925 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
931 /* get a printer handle from the backend */
932 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
937 /* clone the base name. This is NULL for the printserver */
938 printer->printername = strdupW(printername);
940 /* clone the full name */
941 printer->name = strdupW(name);
942 if (name && (!printer->name)) {
947 if (pDefault && pDefault->pDevMode)
948 printer->devmode = dup_devmode( pDefault->pDevMode );
951 printer->queue = queue;
954 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
955 if (!printer->queue) {
959 list_init(&printer->queue->jobs);
960 printer->queue->ref = 0;
962 InterlockedIncrement(&printer->queue->ref);
964 printer_handles[handle] = printer;
967 LeaveCriticalSection(&printer_handles_cs);
968 if (!handle && printer) {
969 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
970 free_printer_entry( printer );
973 return (HANDLE)handle;
976 /******************************************************************
978 * Get the pointer to the opened printer referred by the handle
980 static opened_printer_t *get_opened_printer(HANDLE hprn)
982 UINT_PTR idx = (UINT_PTR)hprn;
983 opened_printer_t *ret = NULL;
985 EnterCriticalSection(&printer_handles_cs);
987 if ((idx > 0) && (idx <= nb_printer_handles)) {
988 ret = printer_handles[idx - 1];
990 LeaveCriticalSection(&printer_handles_cs);
994 /******************************************************************
995 * get_opened_printer_name
996 * Get the pointer to the opened printer name referred by the handle
998 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1000 opened_printer_t *printer = get_opened_printer(hprn);
1001 if(!printer) return NULL;
1002 return printer->name;
1005 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1011 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1012 if (err) return err;
1014 err = RegOpenKeyW( printers, name, key );
1015 if (err) err = ERROR_INVALID_PRINTER_NAME;
1016 RegCloseKey( printers );
1020 /******************************************************************
1021 * WINSPOOL_GetOpenedPrinterRegKey
1024 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1026 LPCWSTR name = get_opened_printer_name(hPrinter);
1028 if(!name) return ERROR_INVALID_HANDLE;
1029 return open_printer_reg_key( name, phkey );
1032 static void old_printer_check( BOOL delete_phase )
1034 PRINTER_INFO_5W* pi;
1035 DWORD needed, type, num, delete, i, size;
1036 const DWORD one = 1;
1040 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1041 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1043 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1044 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1045 for (i = 0; i < num; i++)
1047 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1048 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1051 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1055 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1061 size = sizeof( delete );
1062 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1066 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1067 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1069 DeletePrinter( hprn );
1070 ClosePrinter( hprn );
1072 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1076 HeapFree(GetProcessHeap(), 0, pi);
1079 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1080 'M','U','T','E','X','_','_','\0'};
1082 void WINSPOOL_LoadSystemPrinters(void)
1084 HKEY hkey, hkeyPrinters;
1085 DWORD needed, num, i;
1086 WCHAR PrinterName[256];
1090 /* FIXME: The init code should be moved to spoolsv.exe */
1091 mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1094 ERR( "Failed to create mutex\n" );
1097 if (GetLastError() == ERROR_ALREADY_EXISTS)
1099 WaitForSingleObject( mutex, INFINITE );
1100 ReleaseMutex( mutex );
1101 TRACE( "Init already done\n" );
1105 /* This ensures that all printer entries have a valid Name value. If causes
1106 problems later if they don't. If one is found to be missed we create one
1107 and set it equal to the name of the key */
1108 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1109 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1110 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1111 for(i = 0; i < num; i++) {
1112 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1113 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1114 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1115 set_reg_szW(hkey, NameW, PrinterName);
1122 RegCloseKey(hkeyPrinters);
1125 old_printer_check( FALSE );
1127 #ifdef SONAME_LIBCUPS
1128 done = CUPS_LoadPrinters();
1131 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1132 PRINTCAP_LoadPrinters();
1134 old_printer_check( TRUE );
1136 ReleaseMutex( mutex );
1140 /******************************************************************
1143 * Get the pointer to the specified job.
1144 * Should hold the printer_handles_cs before calling.
1146 static job_t *get_job(HANDLE hprn, DWORD JobId)
1148 opened_printer_t *printer = get_opened_printer(hprn);
1151 if(!printer) return NULL;
1152 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1154 if(job->job_id == JobId)
1160 /***********************************************************
1163 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1166 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1169 Formname = (dmA->dmSize > off_formname);
1170 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1171 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1172 dmW->dmDeviceName, CCHDEVICENAME);
1174 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1175 dmA->dmSize - CCHDEVICENAME);
1177 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1178 off_formname - CCHDEVICENAME);
1179 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1180 dmW->dmFormName, CCHFORMNAME);
1181 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1182 (off_formname + CCHFORMNAME));
1185 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1186 dmA->dmDriverExtra);
1190 /******************************************************************
1191 * convert_printerinfo_W_to_A [internal]
1194 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1195 DWORD level, DWORD outlen, DWORD numentries)
1201 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1203 len = pi_sizeof[level] * numentries;
1204 ptr = (LPSTR) out + len;
1207 /* copy the numbers of all PRINTER_INFO_* first */
1208 memcpy(out, pPrintersW, len);
1210 while (id < numentries) {
1214 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1215 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1217 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1218 if (piW->pDescription) {
1219 piA->pDescription = ptr;
1220 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1221 ptr, outlen, NULL, NULL);
1227 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1228 ptr, outlen, NULL, NULL);
1232 if (piW->pComment) {
1233 piA->pComment = ptr;
1234 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1235 ptr, outlen, NULL, NULL);
1244 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1245 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1248 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1249 if (piW->pServerName) {
1250 piA->pServerName = ptr;
1251 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1252 ptr, outlen, NULL, NULL);
1256 if (piW->pPrinterName) {
1257 piA->pPrinterName = ptr;
1258 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1259 ptr, outlen, NULL, NULL);
1263 if (piW->pShareName) {
1264 piA->pShareName = ptr;
1265 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1266 ptr, outlen, NULL, NULL);
1270 if (piW->pPortName) {
1271 piA->pPortName = ptr;
1272 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1273 ptr, outlen, NULL, NULL);
1277 if (piW->pDriverName) {
1278 piA->pDriverName = ptr;
1279 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1280 ptr, outlen, NULL, NULL);
1284 if (piW->pComment) {
1285 piA->pComment = ptr;
1286 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1287 ptr, outlen, NULL, NULL);
1291 if (piW->pLocation) {
1292 piA->pLocation = ptr;
1293 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1294 ptr, outlen, NULL, NULL);
1299 dmA = DEVMODEdupWtoA(piW->pDevMode);
1301 /* align DEVMODEA to a DWORD boundary */
1302 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1306 piA->pDevMode = (LPDEVMODEA) ptr;
1307 len = dmA->dmSize + dmA->dmDriverExtra;
1308 memcpy(ptr, dmA, len);
1309 HeapFree(GetProcessHeap(), 0, dmA);
1315 if (piW->pSepFile) {
1316 piA->pSepFile = ptr;
1317 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1318 ptr, outlen, NULL, NULL);
1322 if (piW->pPrintProcessor) {
1323 piA->pPrintProcessor = ptr;
1324 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1325 ptr, outlen, NULL, NULL);
1329 if (piW->pDatatype) {
1330 piA->pDatatype = ptr;
1331 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1332 ptr, outlen, NULL, NULL);
1336 if (piW->pParameters) {
1337 piA->pParameters = ptr;
1338 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1339 ptr, outlen, NULL, NULL);
1343 if (piW->pSecurityDescriptor) {
1344 piA->pSecurityDescriptor = NULL;
1345 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1352 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1353 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1355 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1357 if (piW->pPrinterName) {
1358 piA->pPrinterName = ptr;
1359 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1360 ptr, outlen, NULL, NULL);
1364 if (piW->pServerName) {
1365 piA->pServerName = ptr;
1366 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1367 ptr, outlen, NULL, NULL);
1376 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1377 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1379 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1381 if (piW->pPrinterName) {
1382 piA->pPrinterName = ptr;
1383 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1384 ptr, outlen, NULL, NULL);
1388 if (piW->pPortName) {
1389 piA->pPortName = ptr;
1390 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1391 ptr, outlen, NULL, NULL);
1398 case 6: /* 6A and 6W are the same structure */
1403 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1404 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1406 TRACE("(%u) #%u\n", level, id);
1407 if (piW->pszObjectGUID) {
1408 piA->pszObjectGUID = ptr;
1409 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1410 ptr, outlen, NULL, NULL);
1420 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1421 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1424 TRACE("(%u) #%u\n", level, id);
1425 dmA = DEVMODEdupWtoA(piW->pDevMode);
1427 /* align DEVMODEA to a DWORD boundary */
1428 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1432 piA->pDevMode = (LPDEVMODEA) ptr;
1433 len = dmA->dmSize + dmA->dmDriverExtra;
1434 memcpy(ptr, dmA, len);
1435 HeapFree(GetProcessHeap(), 0, dmA);
1445 FIXME("for level %u\n", level);
1447 pPrintersW += pi_sizeof[level];
1448 out += pi_sizeof[level];
1453 /******************************************************************
1454 * convert_driverinfo_W_to_A [internal]
1457 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1458 DWORD level, DWORD outlen, DWORD numentries)
1464 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1466 len = di_sizeof[level] * numentries;
1467 ptr = (LPSTR) out + len;
1470 /* copy the numbers of all PRINTER_INFO_* first */
1471 memcpy(out, pDriversW, len);
1473 #define COPY_STRING(fld) \
1476 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1477 ptr += len; outlen -= len;\
1479 #define COPY_MULTIZ_STRING(fld) \
1480 { LPWSTR p = diW->fld; if (p){ \
1483 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1484 ptr += len; outlen -= len; p += len;\
1486 while(len > 1 && outlen > 0); \
1489 while (id < numentries)
1495 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1496 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1498 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1505 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1506 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1508 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1511 COPY_STRING(pEnvironment);
1512 COPY_STRING(pDriverPath);
1513 COPY_STRING(pDataFile);
1514 COPY_STRING(pConfigFile);
1519 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1520 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1522 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1525 COPY_STRING(pEnvironment);
1526 COPY_STRING(pDriverPath);
1527 COPY_STRING(pDataFile);
1528 COPY_STRING(pConfigFile);
1529 COPY_STRING(pHelpFile);
1530 COPY_MULTIZ_STRING(pDependentFiles);
1531 COPY_STRING(pMonitorName);
1532 COPY_STRING(pDefaultDataType);
1537 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1538 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1540 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1543 COPY_STRING(pEnvironment);
1544 COPY_STRING(pDriverPath);
1545 COPY_STRING(pDataFile);
1546 COPY_STRING(pConfigFile);
1547 COPY_STRING(pHelpFile);
1548 COPY_MULTIZ_STRING(pDependentFiles);
1549 COPY_STRING(pMonitorName);
1550 COPY_STRING(pDefaultDataType);
1551 COPY_MULTIZ_STRING(pszzPreviousNames);
1556 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1557 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1559 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1562 COPY_STRING(pEnvironment);
1563 COPY_STRING(pDriverPath);
1564 COPY_STRING(pDataFile);
1565 COPY_STRING(pConfigFile);
1570 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1571 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1573 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1576 COPY_STRING(pEnvironment);
1577 COPY_STRING(pDriverPath);
1578 COPY_STRING(pDataFile);
1579 COPY_STRING(pConfigFile);
1580 COPY_STRING(pHelpFile);
1581 COPY_MULTIZ_STRING(pDependentFiles);
1582 COPY_STRING(pMonitorName);
1583 COPY_STRING(pDefaultDataType);
1584 COPY_MULTIZ_STRING(pszzPreviousNames);
1585 COPY_STRING(pszMfgName);
1586 COPY_STRING(pszOEMUrl);
1587 COPY_STRING(pszHardwareID);
1588 COPY_STRING(pszProvider);
1593 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1594 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1596 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1599 COPY_STRING(pEnvironment);
1600 COPY_STRING(pDriverPath);
1601 COPY_STRING(pDataFile);
1602 COPY_STRING(pConfigFile);
1603 COPY_STRING(pHelpFile);
1604 COPY_MULTIZ_STRING(pDependentFiles);
1605 COPY_STRING(pMonitorName);
1606 COPY_STRING(pDefaultDataType);
1607 COPY_MULTIZ_STRING(pszzPreviousNames);
1608 COPY_STRING(pszMfgName);
1609 COPY_STRING(pszOEMUrl);
1610 COPY_STRING(pszHardwareID);
1611 COPY_STRING(pszProvider);
1612 COPY_STRING(pszPrintProcessor);
1613 COPY_STRING(pszVendorSetup);
1614 COPY_MULTIZ_STRING(pszzColorProfiles);
1615 COPY_STRING(pszInfPath);
1616 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1622 FIXME("for level %u\n", level);
1625 pDriversW += di_sizeof[level];
1626 out += di_sizeof[level];
1631 #undef COPY_MULTIZ_STRING
1635 /***********************************************************
1638 static void *printer_info_AtoW( const void *data, DWORD level )
1641 UNICODE_STRING usBuffer;
1643 if (!data) return NULL;
1645 if (level < 1 || level > 9) return NULL;
1647 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1648 if (!ret) return NULL;
1650 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1656 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1657 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1659 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1660 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1661 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1662 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1663 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1664 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1665 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1666 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1667 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1668 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1669 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1670 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1677 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1678 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1680 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1685 FIXME( "Unhandled level %d\n", level );
1686 HeapFree( GetProcessHeap(), 0, ret );
1693 /***********************************************************
1696 static void free_printer_info( void *data, DWORD level )
1704 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1706 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1707 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1708 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1709 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1710 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1711 HeapFree( GetProcessHeap(), 0, piW->pComment );
1712 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1713 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1714 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1715 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1716 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1717 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1724 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1726 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1731 FIXME( "Unhandled level %d\n", level );
1734 HeapFree( GetProcessHeap(), 0, data );
1738 /******************************************************************
1739 * DeviceCapabilities [WINSPOOL.@]
1740 * DeviceCapabilitiesA [WINSPOOL.@]
1743 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1744 LPSTR pOutput, LPDEVMODEA lpdm)
1748 if (!GDI_CallDeviceCapabilities16)
1750 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1752 if (!GDI_CallDeviceCapabilities16) return -1;
1754 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1756 /* If DC_PAPERSIZE map POINT16s to POINTs */
1757 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1758 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1759 POINT *pt = (POINT *)pOutput;
1761 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1762 for(i = 0; i < ret; i++, pt++)
1767 HeapFree( GetProcessHeap(), 0, tmp );
1773 /*****************************************************************************
1774 * DeviceCapabilitiesW [WINSPOOL.@]
1776 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1779 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1780 WORD fwCapability, LPWSTR pOutput,
1781 const DEVMODEW *pDevMode)
1783 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1784 LPSTR pDeviceA = strdupWtoA(pDevice);
1785 LPSTR pPortA = strdupWtoA(pPort);
1788 if(pOutput && (fwCapability == DC_BINNAMES ||
1789 fwCapability == DC_FILEDEPENDENCIES ||
1790 fwCapability == DC_PAPERNAMES)) {
1791 /* These need A -> W translation */
1794 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1798 switch(fwCapability) {
1803 case DC_FILEDEPENDENCIES:
1807 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1808 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1810 for(i = 0; i < ret; i++)
1811 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1812 pOutput + (i * size), size);
1813 HeapFree(GetProcessHeap(), 0, pOutputA);
1815 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1816 (LPSTR)pOutput, dmA);
1818 HeapFree(GetProcessHeap(),0,pPortA);
1819 HeapFree(GetProcessHeap(),0,pDeviceA);
1820 HeapFree(GetProcessHeap(),0,dmA);
1824 /******************************************************************
1825 * DocumentPropertiesA [WINSPOOL.@]
1827 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1829 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1830 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1831 LPDEVMODEA pDevModeInput,DWORD fMode )
1833 LPSTR lpName = pDeviceName;
1834 static CHAR port[] = "LPT1:";
1837 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1838 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1842 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1844 ERR("no name from hPrinter?\n");
1845 SetLastError(ERROR_INVALID_HANDLE);
1848 lpName = strdupWtoA(lpNameW);
1851 if (!GDI_CallExtDeviceMode16)
1853 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1855 if (!GDI_CallExtDeviceMode16) {
1856 ERR("No CallExtDeviceMode16?\n");
1860 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1861 pDevModeInput, NULL, fMode);
1864 HeapFree(GetProcessHeap(),0,lpName);
1869 /*****************************************************************************
1870 * DocumentPropertiesW (WINSPOOL.@)
1872 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1874 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1876 LPDEVMODEW pDevModeOutput,
1877 LPDEVMODEW pDevModeInput, DWORD fMode)
1880 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1881 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1882 LPDEVMODEA pDevModeOutputA = NULL;
1885 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1886 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1888 if(pDevModeOutput) {
1889 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1890 if(ret < 0) return ret;
1891 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1893 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1894 pDevModeInputA, fMode);
1895 if(pDevModeOutput) {
1896 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1897 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1899 if(fMode == 0 && ret > 0)
1900 ret += (CCHDEVICENAME + CCHFORMNAME);
1901 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1902 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1906 /*****************************************************************************
1907 * IsValidDevmodeA [WINSPOOL.@]
1909 * Validate a DEVMODE structure and fix errors if possible.
1912 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1914 FIXME("(%p,%ld): stub\n", pDevMode, size);
1922 /*****************************************************************************
1923 * IsValidDevmodeW [WINSPOOL.@]
1925 * Validate a DEVMODE structure and fix errors if possible.
1928 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1930 FIXME("(%p,%ld): stub\n", pDevMode, size);
1938 /******************************************************************
1939 * OpenPrinterA [WINSPOOL.@]
1944 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1945 LPPRINTER_DEFAULTSA pDefault)
1947 UNICODE_STRING lpPrinterNameW;
1948 UNICODE_STRING usBuffer;
1949 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1950 PWSTR pwstrPrinterNameW;
1953 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1956 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1957 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1958 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1959 pDefaultW = &DefaultW;
1961 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1963 RtlFreeUnicodeString(&usBuffer);
1964 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1966 RtlFreeUnicodeString(&lpPrinterNameW);
1970 /******************************************************************
1971 * OpenPrinterW [WINSPOOL.@]
1973 * Open a Printer / Printserver or a Printer-Object
1976 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1977 * phPrinter [O] The resulting Handle is stored here
1978 * pDefault [I] PTR to Default Printer Settings or NULL
1985 * lpPrinterName is one of:
1986 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1987 *| Printer: "PrinterName"
1988 *| Printer-Object: "PrinterName,Job xxx"
1989 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1990 *| XcvPort: "Servername,XcvPort PortName"
1993 *| Printer-Object not supported
1994 *| pDefaults is ignored
1997 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2000 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2003 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2004 SetLastError(ERROR_INVALID_PARAMETER);
2008 /* Get the unique handle of the printer or Printserver */
2009 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2010 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2011 return (*phPrinter != 0);
2014 /******************************************************************
2015 * AddMonitorA [WINSPOOL.@]
2020 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2022 LPWSTR nameW = NULL;
2025 LPMONITOR_INFO_2A mi2a;
2026 MONITOR_INFO_2W mi2w;
2028 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2029 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2030 debugstr_a(mi2a ? mi2a->pName : NULL),
2031 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2032 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2035 SetLastError(ERROR_INVALID_LEVEL);
2039 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2045 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2046 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2047 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2050 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2052 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2053 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2054 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2056 if (mi2a->pEnvironment) {
2057 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2058 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2059 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2061 if (mi2a->pDLLName) {
2062 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2063 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2064 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2067 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2069 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2070 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2071 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2073 HeapFree(GetProcessHeap(), 0, nameW);
2077 /******************************************************************************
2078 * AddMonitorW [WINSPOOL.@]
2080 * Install a Printmonitor
2083 * pName [I] Servername or NULL (local Computer)
2084 * Level [I] Structure-Level (Must be 2)
2085 * pMonitors [I] PTR to MONITOR_INFO_2
2092 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2095 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2097 LPMONITOR_INFO_2W mi2w;
2099 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2100 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2101 debugstr_w(mi2w ? mi2w->pName : NULL),
2102 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2103 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2105 if ((backend == NULL) && !load_backend()) return FALSE;
2108 SetLastError(ERROR_INVALID_LEVEL);
2112 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2117 return backend->fpAddMonitor(pName, Level, pMonitors);
2120 /******************************************************************
2121 * DeletePrinterDriverA [WINSPOOL.@]
2124 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2126 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2129 /******************************************************************
2130 * DeletePrinterDriverW [WINSPOOL.@]
2133 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2135 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2138 /******************************************************************
2139 * DeleteMonitorA [WINSPOOL.@]
2141 * See DeleteMonitorW.
2144 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2146 LPWSTR nameW = NULL;
2147 LPWSTR EnvironmentW = NULL;
2148 LPWSTR MonitorNameW = NULL;
2153 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2154 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2155 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2159 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2160 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2161 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2164 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2165 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2166 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2169 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2171 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2172 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2173 HeapFree(GetProcessHeap(), 0, nameW);
2177 /******************************************************************
2178 * DeleteMonitorW [WINSPOOL.@]
2180 * Delete a specific Printmonitor from a Printing-Environment
2183 * pName [I] Servername or NULL (local Computer)
2184 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2185 * pMonitorName [I] Name of the Monitor, that should be deleted
2192 * pEnvironment is ignored in Windows for the local Computer.
2195 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2198 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2199 debugstr_w(pMonitorName));
2201 if ((backend == NULL) && !load_backend()) return FALSE;
2203 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2207 /******************************************************************
2208 * DeletePortA [WINSPOOL.@]
2213 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2215 LPWSTR nameW = NULL;
2216 LPWSTR portW = NULL;
2220 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2222 /* convert servername to unicode */
2224 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2225 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2226 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2229 /* convert portname to unicode */
2231 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2232 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2233 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2236 res = DeletePortW(nameW, hWnd, portW);
2237 HeapFree(GetProcessHeap(), 0, nameW);
2238 HeapFree(GetProcessHeap(), 0, portW);
2242 /******************************************************************
2243 * DeletePortW [WINSPOOL.@]
2245 * Delete a specific Port
2248 * pName [I] Servername or NULL (local Computer)
2249 * hWnd [I] Handle to parent Window for the Dialog-Box
2250 * pPortName [I] Name of the Port, that should be deleted
2257 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2259 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2261 if ((backend == NULL) && !load_backend()) return FALSE;
2264 SetLastError(RPC_X_NULL_REF_POINTER);
2268 return backend->fpDeletePort(pName, hWnd, pPortName);
2271 /******************************************************************************
2272 * WritePrinter [WINSPOOL.@]
2274 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2276 opened_printer_t *printer;
2279 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2281 EnterCriticalSection(&printer_handles_cs);
2282 printer = get_opened_printer(hPrinter);
2285 SetLastError(ERROR_INVALID_HANDLE);
2291 SetLastError(ERROR_SPL_NO_STARTDOC);
2295 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2297 LeaveCriticalSection(&printer_handles_cs);
2301 /*****************************************************************************
2302 * AddFormA [WINSPOOL.@]
2304 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2306 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2310 /*****************************************************************************
2311 * AddFormW [WINSPOOL.@]
2313 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2315 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2319 /*****************************************************************************
2320 * AddJobA [WINSPOOL.@]
2322 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2325 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2329 SetLastError(ERROR_INVALID_LEVEL);
2333 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2336 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2337 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2338 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2339 if(*pcbNeeded > cbBuf) {
2340 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2343 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2344 addjobA->JobId = addjobW->JobId;
2345 addjobA->Path = (char *)(addjobA + 1);
2346 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2352 /*****************************************************************************
2353 * AddJobW [WINSPOOL.@]
2355 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2357 opened_printer_t *printer;
2360 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2361 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2362 WCHAR path[MAX_PATH], filename[MAX_PATH];
2364 ADDJOB_INFO_1W *addjob;
2366 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2368 EnterCriticalSection(&printer_handles_cs);
2370 printer = get_opened_printer(hPrinter);
2373 SetLastError(ERROR_INVALID_HANDLE);
2378 SetLastError(ERROR_INVALID_LEVEL);
2382 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2386 job->job_id = InterlockedIncrement(&next_job_id);
2388 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2389 if(path[len - 1] != '\\')
2391 memcpy(path + len, spool_path, sizeof(spool_path));
2392 sprintfW(filename, fmtW, path, job->job_id);
2394 len = strlenW(filename);
2395 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2396 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2397 job->portname = NULL;
2398 job->document_title = strdupW(default_doc_title);
2399 job->printer_name = strdupW(printer->name);
2400 job->devmode = dup_devmode( printer->devmode );
2401 list_add_tail(&printer->queue->jobs, &job->entry);
2403 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2404 if(*pcbNeeded <= cbBuf) {
2405 addjob = (ADDJOB_INFO_1W*)pData;
2406 addjob->JobId = job->job_id;
2407 addjob->Path = (WCHAR *)(addjob + 1);
2408 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2411 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2414 LeaveCriticalSection(&printer_handles_cs);
2418 /*****************************************************************************
2419 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2421 * Return the PATH for the Print-Processors
2423 * See GetPrintProcessorDirectoryW.
2427 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2428 DWORD level, LPBYTE Info,
2429 DWORD cbBuf, LPDWORD pcbNeeded)
2431 LPWSTR serverW = NULL;
2436 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2437 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2441 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2442 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2443 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2447 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2448 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2449 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2452 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2453 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2455 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2458 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2459 cbBuf, NULL, NULL) > 0;
2462 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2463 HeapFree(GetProcessHeap(), 0, envW);
2464 HeapFree(GetProcessHeap(), 0, serverW);
2468 /*****************************************************************************
2469 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2471 * Return the PATH for the Print-Processors
2474 * server [I] Servername (NT only) or NULL (local Computer)
2475 * env [I] Printing-Environment (see below) or NULL (Default)
2476 * level [I] Structure-Level (must be 1)
2477 * Info [O] PTR to Buffer that receives the Result
2478 * cbBuf [I] Size of Buffer at "Info"
2479 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2480 * required for the Buffer at "Info"
2483 * Success: TRUE and in pcbNeeded the Bytes used in Info
2484 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2485 * if cbBuf is too small
2487 * Native Values returned in Info on Success:
2488 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2489 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2490 *| win9x(Windows 4.0): "%winsysdir%"
2492 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2495 * Only NULL or "" is supported for server
2498 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2499 DWORD level, LPBYTE Info,
2500 DWORD cbBuf, LPDWORD pcbNeeded)
2503 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2504 Info, cbBuf, pcbNeeded);
2506 if ((backend == NULL) && !load_backend()) return FALSE;
2509 /* (Level != 1) is ignored in win9x */
2510 SetLastError(ERROR_INVALID_LEVEL);
2514 if (pcbNeeded == NULL) {
2515 /* (pcbNeeded == NULL) is ignored in win9x */
2516 SetLastError(RPC_X_NULL_REF_POINTER);
2520 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2523 /*****************************************************************************
2524 * WINSPOOL_OpenDriverReg [internal]
2526 * opens the registry for the printer drivers depending on the given input
2527 * variable pEnvironment
2530 * the opened hkey on success
2533 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2537 const printenv_t * env;
2539 TRACE("(%s)\n", debugstr_w(pEnvironment));
2541 env = validate_envW(pEnvironment);
2542 if (!env) return NULL;
2544 buffer = HeapAlloc( GetProcessHeap(), 0,
2545 (strlenW(DriversW) + strlenW(env->envname) +
2546 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2548 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2549 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2550 HeapFree(GetProcessHeap(), 0, buffer);
2555 /*****************************************************************************
2556 * set_devices_and_printerports [internal]
2558 * set the [Devices] and [PrinterPorts] entries for a printer.
2561 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2563 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2567 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2569 /* FIXME: the driver must change to "winspool" */
2570 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2572 lstrcpyW(devline, driver_nt);
2573 lstrcatW(devline, commaW);
2574 lstrcatW(devline, pi->pPortName);
2576 TRACE("using %s\n", debugstr_w(devline));
2577 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2578 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2579 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2580 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2584 lstrcatW(devline, timeout_15_45);
2585 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2586 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2587 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2588 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2591 HeapFree(GetProcessHeap(), 0, devline);
2595 /*****************************************************************************
2596 * AddPrinterW [WINSPOOL.@]
2598 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2600 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2603 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2605 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2606 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2607 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2608 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2609 statusW[] = {'S','t','a','t','u','s',0},
2610 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2612 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2615 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2616 SetLastError(ERROR_INVALID_PARAMETER);
2620 ERR("Level = %d, unsupported!\n", Level);
2621 SetLastError(ERROR_INVALID_LEVEL);
2625 SetLastError(ERROR_INVALID_PARAMETER);
2628 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2630 ERR("Can't create Printers key\n");
2633 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2634 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2635 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2636 RegCloseKey(hkeyPrinter);
2637 RegCloseKey(hkeyPrinters);
2640 RegCloseKey(hkeyPrinter);
2642 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2644 ERR("Can't create Drivers key\n");
2645 RegCloseKey(hkeyPrinters);
2648 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2650 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2651 RegCloseKey(hkeyPrinters);
2652 RegCloseKey(hkeyDrivers);
2653 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2656 RegCloseKey(hkeyDriver);
2657 RegCloseKey(hkeyDrivers);
2659 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2660 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2661 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2662 RegCloseKey(hkeyPrinters);
2666 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2668 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2669 SetLastError(ERROR_INVALID_PRINTER_NAME);
2670 RegCloseKey(hkeyPrinters);
2674 set_devices_and_printerports(pi);
2675 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2676 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2677 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2679 /* See if we can load the driver. We may need the devmode structure anyway
2682 * Note that DocumentPropertiesW will briefly try to open the printer we
2683 * just create to find a DEVMODE struct (it will use the WINEPS default
2684 * one in case it is not there, so we are ok).
2686 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2689 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2690 size = sizeof(DEVMODEW);
2696 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2698 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2700 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2701 HeapFree( GetProcessHeap(), 0, dm );
2706 /* set devmode to printer name */
2707 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2711 set_reg_devmode( hkeyPrinter, default_devmodeW, dm );
2712 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2714 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2715 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2716 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2717 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2719 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2720 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2721 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2722 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2723 (LPBYTE)&pi->Priority, sizeof(DWORD));
2724 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2725 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2726 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2727 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2728 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2729 (LPBYTE)&pi->Status, sizeof(DWORD));
2730 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2731 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2733 RegCloseKey(hkeyPrinter);
2734 RegCloseKey(hkeyPrinters);
2735 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2736 ERR("OpenPrinter failing\n");
2742 /*****************************************************************************
2743 * AddPrinterA [WINSPOOL.@]
2745 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2747 UNICODE_STRING pNameW;
2749 PRINTER_INFO_2W *piW;
2750 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2753 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2755 ERR("Level = %d, unsupported!\n", Level);
2756 SetLastError(ERROR_INVALID_LEVEL);
2759 pwstrNameW = asciitounicode(&pNameW,pName);
2760 piW = printer_info_AtoW( piA, Level );
2762 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2764 free_printer_info( piW, Level );
2765 RtlFreeUnicodeString(&pNameW);
2770 /*****************************************************************************
2771 * ClosePrinter [WINSPOOL.@]
2773 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2775 UINT_PTR i = (UINT_PTR)hPrinter;
2776 opened_printer_t *printer = NULL;
2779 TRACE("(%p)\n", hPrinter);
2781 EnterCriticalSection(&printer_handles_cs);
2783 if ((i > 0) && (i <= nb_printer_handles))
2784 printer = printer_handles[i - 1];
2789 struct list *cursor, *cursor2;
2791 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2793 if (printer->backend_printer) {
2794 backend->fpClosePrinter(printer->backend_printer);
2798 EndDocPrinter(hPrinter);
2800 if(InterlockedDecrement(&printer->queue->ref) == 0)
2802 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2804 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2805 ScheduleJob(hPrinter, job->job_id);
2807 HeapFree(GetProcessHeap(), 0, printer->queue);
2810 free_printer_entry( printer );
2811 printer_handles[i - 1] = NULL;
2814 LeaveCriticalSection(&printer_handles_cs);
2818 /*****************************************************************************
2819 * DeleteFormA [WINSPOOL.@]
2821 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2823 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2827 /*****************************************************************************
2828 * DeleteFormW [WINSPOOL.@]
2830 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2832 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2836 /*****************************************************************************
2837 * DeletePrinter [WINSPOOL.@]
2839 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2841 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2842 HKEY hkeyPrinters, hkey;
2843 WCHAR def[MAX_PATH];
2844 DWORD size = sizeof( def ) / sizeof( def[0] );
2847 SetLastError(ERROR_INVALID_HANDLE);
2850 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2851 RegDeleteTreeW(hkeyPrinters, lpNameW);
2852 RegCloseKey(hkeyPrinters);
2854 WriteProfileStringW(devicesW, lpNameW, NULL);
2855 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2857 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2858 RegDeleteValueW(hkey, lpNameW);
2862 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2863 RegDeleteValueW(hkey, lpNameW);
2867 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2869 WriteProfileStringW( windowsW, deviceW, NULL );
2870 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2872 RegDeleteValueW( hkey, deviceW );
2873 RegCloseKey( hkey );
2875 SetDefaultPrinterW( NULL );
2881 /*****************************************************************************
2882 * SetPrinterA [WINSPOOL.@]
2884 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2891 dataW = printer_info_AtoW( data, level );
2892 if (!dataW) return FALSE;
2895 ret = SetPrinterW( printer, level, dataW, command );
2897 if (dataW != data) free_printer_info( dataW, level );
2902 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2904 set_reg_szW( key, NameW, pi->pPrinterName );
2905 set_reg_szW( key, Share_NameW, pi->pShareName );
2906 set_reg_szW( key, PortW, pi->pPortName );
2907 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
2908 set_reg_szW( key, DescriptionW, pi->pComment );
2909 set_reg_szW( key, LocationW, pi->pLocation );
2912 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2914 set_reg_szW( key, Separator_FileW, pi->pSepFile );
2915 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
2916 set_reg_szW( key, DatatypeW, pi->pDatatype );
2917 set_reg_szW( key, ParametersW, pi->pParameters );
2919 set_reg_DWORD( key, "Attributes", pi->Attributes );
2920 set_reg_DWORD( key, "Priority", pi->Priority );
2921 set_reg_DWORD( key, "Default Priority", pi->DefaultPriority );
2922 set_reg_DWORD( key, "StartTime", pi->StartTime );
2923 set_reg_DWORD( key, "UntilTime", pi->UntilTime );
2926 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2928 if (!pi->pDevMode) return FALSE;
2930 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2934 /******************************************************************************
2935 * SetPrinterW [WINSPOOL.@]
2937 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2942 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2944 if (command != 0) FIXME( "Ignoring command %d\n", command );
2946 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2953 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2954 set_printer_2( key, pi2 );
2961 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2962 ret = set_printer_9( key, pi );
2967 FIXME( "Unimplemented level %d\n", level );
2968 SetLastError( ERROR_INVALID_LEVEL );
2975 /*****************************************************************************
2976 * SetJobA [WINSPOOL.@]
2978 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2979 LPBYTE pJob, DWORD Command)
2983 UNICODE_STRING usBuffer;
2985 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2987 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2988 are all ignored by SetJob, so we don't bother copying them */
2996 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2997 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2999 JobW = (LPBYTE)info1W;
3000 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3001 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3002 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3003 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3004 info1W->Status = info1A->Status;
3005 info1W->Priority = info1A->Priority;
3006 info1W->Position = info1A->Position;
3007 info1W->PagesPrinted = info1A->PagesPrinted;
3012 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3013 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3015 JobW = (LPBYTE)info2W;
3016 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3017 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3018 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3019 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3020 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3021 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3022 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3023 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3024 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3025 info2W->Status = info2A->Status;
3026 info2W->Priority = info2A->Priority;
3027 info2W->Position = info2A->Position;
3028 info2W->StartTime = info2A->StartTime;
3029 info2W->UntilTime = info2A->UntilTime;
3030 info2W->PagesPrinted = info2A->PagesPrinted;
3034 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3035 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3038 SetLastError(ERROR_INVALID_LEVEL);
3042 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3048 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3049 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3050 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3051 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3052 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3057 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3058 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3059 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3060 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3061 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3062 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3063 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3064 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3065 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3069 HeapFree(GetProcessHeap(), 0, JobW);
3074 /*****************************************************************************
3075 * SetJobW [WINSPOOL.@]
3077 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3078 LPBYTE pJob, DWORD Command)
3083 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3084 FIXME("Ignoring everything other than document title\n");
3086 EnterCriticalSection(&printer_handles_cs);
3087 job = get_job(hPrinter, JobId);
3097 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3098 HeapFree(GetProcessHeap(), 0, job->document_title);
3099 job->document_title = strdupW(info1->pDocument);
3104 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3105 HeapFree(GetProcessHeap(), 0, job->document_title);
3106 job->document_title = strdupW(info2->pDocument);
3107 HeapFree(GetProcessHeap(), 0, job->devmode);
3108 job->devmode = dup_devmode( info2->pDevMode );
3114 SetLastError(ERROR_INVALID_LEVEL);
3119 LeaveCriticalSection(&printer_handles_cs);
3123 /*****************************************************************************
3124 * EndDocPrinter [WINSPOOL.@]
3126 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3128 opened_printer_t *printer;
3130 TRACE("(%p)\n", hPrinter);
3132 EnterCriticalSection(&printer_handles_cs);
3134 printer = get_opened_printer(hPrinter);
3137 SetLastError(ERROR_INVALID_HANDLE);
3143 SetLastError(ERROR_SPL_NO_STARTDOC);
3147 CloseHandle(printer->doc->hf);
3148 ScheduleJob(hPrinter, printer->doc->job_id);
3149 HeapFree(GetProcessHeap(), 0, printer->doc);
3150 printer->doc = NULL;
3153 LeaveCriticalSection(&printer_handles_cs);
3157 /*****************************************************************************
3158 * EndPagePrinter [WINSPOOL.@]
3160 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3162 FIXME("(%p): stub\n", hPrinter);
3166 /*****************************************************************************
3167 * StartDocPrinterA [WINSPOOL.@]
3169 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3171 UNICODE_STRING usBuffer;
3173 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3176 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3177 or one (DOC_INFO_3) extra DWORDs */
3181 doc2W.JobId = doc2->JobId;
3184 doc2W.dwMode = doc2->dwMode;
3187 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3188 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3189 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3193 SetLastError(ERROR_INVALID_LEVEL);
3197 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3199 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3200 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3201 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3206 /*****************************************************************************
3207 * StartDocPrinterW [WINSPOOL.@]
3209 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3211 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3212 opened_printer_t *printer;
3213 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3214 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3215 JOB_INFO_1W job_info;
3216 DWORD needed, ret = 0;
3221 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3222 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3223 debugstr_w(doc->pDatatype));
3225 if(Level < 1 || Level > 3)
3227 SetLastError(ERROR_INVALID_LEVEL);
3231 EnterCriticalSection(&printer_handles_cs);
3232 printer = get_opened_printer(hPrinter);
3235 SetLastError(ERROR_INVALID_HANDLE);
3241 SetLastError(ERROR_INVALID_PRINTER_STATE);
3245 /* Even if we're printing to a file we still add a print job, we'll
3246 just ignore the spool file name */
3248 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3250 ERR("AddJob failed gle %u\n", GetLastError());
3254 /* use pOutputFile only, when it is a real filename */
3255 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3256 filename = doc->pOutputFile;
3258 filename = addjob->Path;
3260 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3261 if(hf == INVALID_HANDLE_VALUE)
3264 memset(&job_info, 0, sizeof(job_info));
3265 job_info.pDocument = doc->pDocName;
3266 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3268 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3269 printer->doc->hf = hf;
3270 ret = printer->doc->job_id = addjob->JobId;
3271 job = get_job(hPrinter, ret);
3272 job->portname = strdupW(doc->pOutputFile);
3275 LeaveCriticalSection(&printer_handles_cs);
3280 /*****************************************************************************
3281 * StartPagePrinter [WINSPOOL.@]
3283 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3285 FIXME("(%p): stub\n", hPrinter);
3289 /*****************************************************************************
3290 * GetFormA [WINSPOOL.@]
3292 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3293 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3295 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3296 Level,pForm,cbBuf,pcbNeeded);
3300 /*****************************************************************************
3301 * GetFormW [WINSPOOL.@]
3303 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3304 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3306 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3307 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3311 /*****************************************************************************
3312 * SetFormA [WINSPOOL.@]
3314 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3317 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3321 /*****************************************************************************
3322 * SetFormW [WINSPOOL.@]
3324 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3327 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3331 /*****************************************************************************
3332 * ReadPrinter [WINSPOOL.@]
3334 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3335 LPDWORD pNoBytesRead)
3337 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3341 /*****************************************************************************
3342 * ResetPrinterA [WINSPOOL.@]
3344 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3346 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3350 /*****************************************************************************
3351 * ResetPrinterW [WINSPOOL.@]
3353 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3355 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3359 /*****************************************************************************
3360 * WINSPOOL_GetDWORDFromReg
3362 * Return DWORD associated with ValueName from hkey.
3364 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3366 DWORD sz = sizeof(DWORD), type, value = 0;
3369 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3371 if(ret != ERROR_SUCCESS) {
3372 WARN("Got ret = %d on name %s\n", ret, ValueName);
3375 if(type != REG_DWORD) {
3376 ERR("Got type %d\n", type);
3383 /*****************************************************************************
3384 * get_filename_from_reg [internal]
3386 * Get ValueName from hkey storing result in out
3387 * when the Value in the registry has only a filename, use driverdir as prefix
3388 * outlen is space left in out
3389 * String is stored either as unicode or ascii
3393 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3394 LPBYTE out, DWORD outlen, LPDWORD needed)
3396 WCHAR filename[MAX_PATH];
3400 LPWSTR buffer = filename;
3404 size = sizeof(filename);
3406 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3407 if (ret == ERROR_MORE_DATA) {
3408 TRACE("need dynamic buffer: %u\n", size);
3409 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3411 /* No Memory is bad */
3415 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3418 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3419 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3425 /* do we have a full path ? */
3426 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3427 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3430 /* we must build the full Path */
3432 if ((out) && (outlen > dirlen)) {
3433 lstrcpyW((LPWSTR)out, driverdir);
3441 /* write the filename */
3442 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3443 if ((out) && (outlen >= size)) {
3444 lstrcpyW((LPWSTR)out, ptr);
3451 ptr += lstrlenW(ptr)+1;
3452 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3455 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3457 /* write the multisz-termination */
3458 if (type == REG_MULTI_SZ) {
3459 size = sizeof(WCHAR);
3462 if (out && (outlen >= size)) {
3463 memset (out, 0, size);
3469 /*****************************************************************************
3470 * WINSPOOL_GetStringFromReg
3472 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3473 * String is stored as unicode.
3475 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3476 DWORD buflen, DWORD *needed)
3478 DWORD sz = buflen, type;
3481 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3482 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3483 WARN("Got ret = %d\n", ret);
3487 /* add space for terminating '\0' */
3488 sz += sizeof(WCHAR);
3492 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3497 /*****************************************************************************
3498 * WINSPOOL_GetDefaultDevMode
3500 * Get a default DevMode values for wineps.
3504 static void WINSPOOL_GetDefaultDevMode(
3506 DWORD buflen, DWORD *needed)
3509 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3511 /* fill default DEVMODE - should be read from ppd... */
3512 ZeroMemory( &dm, sizeof(dm) );
3513 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3514 dm.dmSpecVersion = DM_SPECVERSION;
3515 dm.dmDriverVersion = 1;
3516 dm.dmSize = sizeof(DEVMODEW);
3517 dm.dmDriverExtra = 0;
3519 DM_ORIENTATION | DM_PAPERSIZE |
3520 DM_PAPERLENGTH | DM_PAPERWIDTH |
3523 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3524 DM_YRESOLUTION | DM_TTOPTION;
3526 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3527 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3528 dm.u1.s1.dmPaperLength = 2970;
3529 dm.u1.s1.dmPaperWidth = 2100;
3531 dm.u1.s1.dmScale = 100;
3532 dm.u1.s1.dmCopies = 1;
3533 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3534 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3537 dm.dmYResolution = 300; /* 300dpi */
3538 dm.dmTTOption = DMTT_BITMAP;
3541 /* dm.dmLogPixels */
3542 /* dm.dmBitsPerPel */
3543 /* dm.dmPelsWidth */
3544 /* dm.dmPelsHeight */
3545 /* dm.u2.dmDisplayFlags */
3546 /* dm.dmDisplayFrequency */
3547 /* dm.dmICMMethod */
3548 /* dm.dmICMIntent */
3549 /* dm.dmMediaType */
3550 /* dm.dmDitherType */
3551 /* dm.dmReserved1 */
3552 /* dm.dmReserved2 */
3553 /* dm.dmPanningWidth */
3554 /* dm.dmPanningHeight */
3556 if(buflen >= sizeof(DEVMODEW))
3557 memcpy(ptr, &dm, sizeof(DEVMODEW));
3558 *needed = sizeof(DEVMODEW);
3561 /*****************************************************************************
3562 * WINSPOOL_GetDevModeFromReg
3564 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3565 * DevMode is stored either as unicode or ascii.
3567 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3569 DWORD buflen, DWORD *needed)
3571 DWORD sz = buflen, type;
3574 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3575 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3576 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3577 if (sz < sizeof(DEVMODEA))
3579 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3582 /* ensures that dmSize is not erratically bogus if registry is invalid */
3583 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3584 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3585 sz += (CCHDEVICENAME + CCHFORMNAME);
3586 if (ptr && (buflen >= sz)) {
3587 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3588 memcpy(ptr, dmW, sz);
3589 HeapFree(GetProcessHeap(),0,dmW);
3595 /*********************************************************************
3596 * WINSPOOL_GetPrinter_1
3598 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3600 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3601 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3603 DWORD size, left = cbBuf;
3604 BOOL space = (cbBuf > 0);
3609 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3610 if(space && size <= left) {
3611 pi1->pName = (LPWSTR)ptr;
3619 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3620 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3621 if(space && size <= left) {
3622 pi1->pDescription = (LPWSTR)ptr;
3630 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3631 if(space && size <= left) {
3632 pi1->pComment = (LPWSTR)ptr;
3640 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3642 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3643 memset(pi1, 0, sizeof(*pi1));
3647 /*********************************************************************
3648 * WINSPOOL_GetPrinter_2
3650 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3652 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3653 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3655 DWORD size, left = cbBuf;
3656 BOOL space = (cbBuf > 0);
3661 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3662 if(space && size <= left) {
3663 pi2->pPrinterName = (LPWSTR)ptr;
3670 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3671 if(space && size <= left) {
3672 pi2->pShareName = (LPWSTR)ptr;
3679 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3680 if(space && size <= left) {
3681 pi2->pPortName = (LPWSTR)ptr;
3688 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3689 if(space && size <= left) {
3690 pi2->pDriverName = (LPWSTR)ptr;
3697 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3698 if(space && size <= left) {
3699 pi2->pComment = (LPWSTR)ptr;
3706 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3707 if(space && size <= left) {
3708 pi2->pLocation = (LPWSTR)ptr;
3715 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3716 if(space && size <= left) {
3717 pi2->pDevMode = (LPDEVMODEW)ptr;
3726 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3727 if(space && size <= left) {
3728 pi2->pDevMode = (LPDEVMODEW)ptr;
3735 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3736 if(space && size <= left) {
3737 pi2->pSepFile = (LPWSTR)ptr;
3744 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3745 if(space && size <= left) {
3746 pi2->pPrintProcessor = (LPWSTR)ptr;
3753 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3754 if(space && size <= left) {
3755 pi2->pDatatype = (LPWSTR)ptr;
3762 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3763 if(space && size <= left) {
3764 pi2->pParameters = (LPWSTR)ptr;
3772 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3773 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3774 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3775 "Default Priority");
3776 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3777 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3780 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3781 memset(pi2, 0, sizeof(*pi2));
3786 /*********************************************************************
3787 * WINSPOOL_GetPrinter_4
3789 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3791 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3792 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3794 DWORD size, left = cbBuf;
3795 BOOL space = (cbBuf > 0);
3800 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3801 if(space && size <= left) {
3802 pi4->pPrinterName = (LPWSTR)ptr;
3810 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3813 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3814 memset(pi4, 0, sizeof(*pi4));
3819 /*********************************************************************
3820 * WINSPOOL_GetPrinter_5
3822 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3824 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3825 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3827 DWORD size, left = cbBuf;
3828 BOOL space = (cbBuf > 0);
3833 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3834 if(space && size <= left) {
3835 pi5->pPrinterName = (LPWSTR)ptr;
3842 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3843 if(space && size <= left) {
3844 pi5->pPortName = (LPWSTR)ptr;
3852 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3853 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3855 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3859 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3860 memset(pi5, 0, sizeof(*pi5));
3865 /*********************************************************************
3866 * WINSPOOL_GetPrinter_7
3868 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3870 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3871 DWORD cbBuf, LPDWORD pcbNeeded)
3873 DWORD size, left = cbBuf;
3874 BOOL space = (cbBuf > 0);
3879 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3882 size = sizeof(pi7->pszObjectGUID);
3884 if (space && size <= left) {
3885 pi7->pszObjectGUID = (LPWSTR)ptr;
3892 /* We do not have a Directory Service */
3893 pi7->dwAction = DSPRINT_UNPUBLISH;
3896 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3897 memset(pi7, 0, sizeof(*pi7));
3902 /*********************************************************************
3903 * WINSPOOL_GetPrinter_9
3905 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3907 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3908 DWORD cbBuf, LPDWORD pcbNeeded)
3911 BOOL space = (cbBuf > 0);
3915 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3916 if(space && size <= cbBuf) {
3917 pi9->pDevMode = (LPDEVMODEW)buf;
3924 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3925 if(space && size <= cbBuf) {
3926 pi9->pDevMode = (LPDEVMODEW)buf;
3932 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3933 memset(pi9, 0, sizeof(*pi9));
3938 /*****************************************************************************
3939 * GetPrinterW [WINSPOOL.@]
3941 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3942 DWORD cbBuf, LPDWORD pcbNeeded)
3944 DWORD size, needed = 0, err;
3949 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3951 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3954 SetLastError( err );
3961 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3963 size = sizeof(PRINTER_INFO_2W);
3965 ptr = pPrinter + size;
3967 memset(pPrinter, 0, size);
3972 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3979 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3981 size = sizeof(PRINTER_INFO_4W);
3983 ptr = pPrinter + size;
3985 memset(pPrinter, 0, size);
3990 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3998 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4000 size = sizeof(PRINTER_INFO_5W);
4002 ptr = pPrinter + size;
4004 memset(pPrinter, 0, size);
4010 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4018 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4020 size = sizeof(PRINTER_INFO_6);
4021 if (size <= cbBuf) {
4022 /* FIXME: We do not update the status yet */
4023 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4035 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4037 size = sizeof(PRINTER_INFO_7W);
4038 if (size <= cbBuf) {
4039 ptr = pPrinter + size;
4041 memset(pPrinter, 0, size);
4047 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4054 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4055 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4059 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4061 size = sizeof(PRINTER_INFO_9W);
4063 ptr = pPrinter + size;
4065 memset(pPrinter, 0, size);
4071 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4078 FIXME("Unimplemented level %d\n", Level);
4079 SetLastError(ERROR_INVALID_LEVEL);
4080 RegCloseKey(hkeyPrinter);
4084 RegCloseKey(hkeyPrinter);
4086 TRACE("returning %d needed = %d\n", ret, needed);
4087 if(pcbNeeded) *pcbNeeded = needed;
4089 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4093 /*****************************************************************************
4094 * GetPrinterA [WINSPOOL.@]
4096 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4097 DWORD cbBuf, LPDWORD pcbNeeded)
4103 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4105 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4107 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4108 HeapFree(GetProcessHeap(), 0, buf);
4113 /*****************************************************************************
4114 * WINSPOOL_EnumPrintersW
4116 * Implementation of EnumPrintersW
4118 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4119 DWORD dwLevel, LPBYTE lpbPrinters,
4120 DWORD cbBuf, LPDWORD lpdwNeeded,
4121 LPDWORD lpdwReturned)
4124 HKEY hkeyPrinters, hkeyPrinter;
4125 WCHAR PrinterName[255];
4126 DWORD needed = 0, number = 0;
4127 DWORD used, i, left;
4131 memset(lpbPrinters, 0, cbBuf);
4137 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4138 if(dwType == PRINTER_ENUM_DEFAULT)
4141 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4142 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4143 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4145 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4151 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4152 FIXME("dwType = %08x\n", dwType);
4153 SetLastError(ERROR_INVALID_FLAGS);
4157 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4159 ERR("Can't create Printers key\n");
4163 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4164 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4165 RegCloseKey(hkeyPrinters);
4166 ERR("Can't query Printers key\n");
4169 TRACE("Found %d printers\n", number);
4173 used = number * sizeof(PRINTER_INFO_1W);
4176 used = number * sizeof(PRINTER_INFO_2W);
4179 used = number * sizeof(PRINTER_INFO_4W);
4182 used = number * sizeof(PRINTER_INFO_5W);
4186 SetLastError(ERROR_INVALID_LEVEL);
4187 RegCloseKey(hkeyPrinters);
4190 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4192 for(i = 0; i < number; i++) {
4193 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4195 ERR("Can't enum key number %d\n", i);
4196 RegCloseKey(hkeyPrinters);
4199 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4200 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4202 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4203 RegCloseKey(hkeyPrinters);
4208 buf = lpbPrinters + used;
4209 left = cbBuf - used;
4217 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4220 if(pi) pi += sizeof(PRINTER_INFO_1W);
4223 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4226 if(pi) pi += sizeof(PRINTER_INFO_2W);
4229 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4232 if(pi) pi += sizeof(PRINTER_INFO_4W);
4235 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4238 if(pi) pi += sizeof(PRINTER_INFO_5W);
4241 ERR("Shouldn't be here!\n");
4242 RegCloseKey(hkeyPrinter);
4243 RegCloseKey(hkeyPrinters);
4246 RegCloseKey(hkeyPrinter);
4248 RegCloseKey(hkeyPrinters);
4255 memset(lpbPrinters, 0, cbBuf);
4256 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4260 *lpdwReturned = number;
4261 SetLastError(ERROR_SUCCESS);
4266 /******************************************************************
4267 * EnumPrintersW [WINSPOOL.@]
4269 * Enumerates the available printers, print servers and print
4270 * providers, depending on the specified flags, name and level.
4274 * If level is set to 1:
4275 * Returns an array of PRINTER_INFO_1 data structures in the
4276 * lpbPrinters buffer.
4278 * If level is set to 2:
4279 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4280 * Returns an array of PRINTER_INFO_2 data structures in the
4281 * lpbPrinters buffer. Note that according to MSDN also an
4282 * OpenPrinter should be performed on every remote printer.
4284 * If level is set to 4 (officially WinNT only):
4285 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4286 * Fast: Only the registry is queried to retrieve printer names,
4287 * no connection to the driver is made.
4288 * Returns an array of PRINTER_INFO_4 data structures in the
4289 * lpbPrinters buffer.
4291 * If level is set to 5 (officially WinNT4/Win9x only):
4292 * Fast: Only the registry is queried to retrieve printer names,
4293 * no connection to the driver is made.
4294 * Returns an array of PRINTER_INFO_5 data structures in the
4295 * lpbPrinters buffer.
4297 * If level set to 3 or 6+:
4298 * returns zero (failure!)
4300 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4304 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4305 * - Only levels 2, 4 and 5 are implemented at the moment.
4306 * - 16-bit printer drivers are not enumerated.
4307 * - Returned amount of bytes used/needed does not match the real Windoze
4308 * implementation (as in this implementation, all strings are part
4309 * of the buffer, whereas Win32 keeps them somewhere else)
4310 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4313 * - In a regular Wine installation, no registry settings for printers
4314 * exist, which makes this function return an empty list.
4316 BOOL WINAPI EnumPrintersW(
4317 DWORD dwType, /* [in] Types of print objects to enumerate */
4318 LPWSTR lpszName, /* [in] name of objects to enumerate */
4319 DWORD dwLevel, /* [in] type of printer info structure */
4320 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4321 DWORD cbBuf, /* [in] max size of buffer in bytes */
4322 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4323 LPDWORD lpdwReturned /* [out] number of entries returned */
4326 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4327 lpdwNeeded, lpdwReturned);
4330 /******************************************************************
4331 * EnumPrintersA [WINSPOOL.@]
4336 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4337 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4340 UNICODE_STRING pNameU;
4344 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4345 pPrinters, cbBuf, pcbNeeded, pcReturned);
4347 pNameW = asciitounicode(&pNameU, pName);
4349 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4350 MS Office need this */
4351 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4353 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4355 RtlFreeUnicodeString(&pNameU);
4357 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4359 HeapFree(GetProcessHeap(), 0, pPrintersW);
4363 /*****************************************************************************
4364 * WINSPOOL_GetDriverInfoFromReg [internal]
4366 * Enters the information from the registry into the DRIVER_INFO struct
4369 * zero if the printer driver does not exist in the registry
4370 * (only if Level > 1) otherwise nonzero
4372 static BOOL WINSPOOL_GetDriverInfoFromReg(
4375 const printenv_t * env,
4377 LPBYTE ptr, /* DRIVER_INFO */
4378 LPBYTE pDriverStrings, /* strings buffer */
4379 DWORD cbBuf, /* size of string buffer */
4380 LPDWORD pcbNeeded) /* space needed for str. */
4384 WCHAR driverdir[MAX_PATH];
4386 LPBYTE strPtr = pDriverStrings;
4387 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4389 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4390 debugstr_w(DriverName), env,
4391 Level, di, pDriverStrings, cbBuf);
4393 if (di) ZeroMemory(di, di_sizeof[Level]);
4395 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4396 if (*pcbNeeded <= cbBuf)
4397 strcpyW((LPWSTR)strPtr, DriverName);
4399 /* pName for level 1 has a different offset! */
4401 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4405 /* .cVersion and .pName for level > 1 */
4407 di->cVersion = env->driverversion;
4408 di->pName = (LPWSTR) strPtr;
4409 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4412 /* Reserve Space for the largest subdir and a Backslash*/
4413 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4414 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4415 /* Should never Fail */
4418 lstrcatW(driverdir, env->versionsubdir);
4419 lstrcatW(driverdir, backslashW);
4421 /* dirlen must not include the terminating zero */
4422 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4424 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4425 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4426 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4431 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4434 if (*pcbNeeded <= cbBuf) {
4435 lstrcpyW((LPWSTR)strPtr, env->envname);
4436 if (di) di->pEnvironment = (LPWSTR)strPtr;
4437 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4440 /* .pDriverPath is the Graphics rendering engine.
4441 The full Path is required to avoid a crash in some apps */
4442 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4444 if (*pcbNeeded <= cbBuf)
4445 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4447 if (di) di->pDriverPath = (LPWSTR)strPtr;
4448 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4451 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4452 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4454 if (*pcbNeeded <= cbBuf)
4455 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4457 if (di) di->pDataFile = (LPWSTR)strPtr;
4458 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4461 /* .pConfigFile is the Driver user Interface */
4462 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4464 if (*pcbNeeded <= cbBuf)
4465 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4467 if (di) di->pConfigFile = (LPWSTR)strPtr;
4468 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4472 RegCloseKey(hkeyDriver);
4473 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4478 RegCloseKey(hkeyDriver);
4479 FIXME("level 5: incomplete\n");
4484 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4486 if (*pcbNeeded <= cbBuf)
4487 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4489 if (di) di->pHelpFile = (LPWSTR)strPtr;
4490 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4493 /* .pDependentFiles */
4494 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4496 if (*pcbNeeded <= cbBuf)
4497 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4499 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4500 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4502 else if (GetVersion() & 0x80000000) {
4503 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4504 size = 2 * sizeof(WCHAR);
4506 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4508 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4509 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4512 /* .pMonitorName is the optional Language Monitor */
4513 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4515 if (*pcbNeeded <= cbBuf)
4516 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4518 if (di) di->pMonitorName = (LPWSTR)strPtr;
4519 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4522 /* .pDefaultDataType */
4523 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4525 if(*pcbNeeded <= cbBuf)
4526 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4528 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4529 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4533 RegCloseKey(hkeyDriver);
4534 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4538 /* .pszzPreviousNames */
4539 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4541 if(*pcbNeeded <= cbBuf)
4542 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4544 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4545 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4549 RegCloseKey(hkeyDriver);
4550 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4554 /* support is missing, but not important enough for a FIXME */
4555 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4558 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4560 if(*pcbNeeded <= cbBuf)
4561 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4563 if (di) di->pszMfgName = (LPWSTR)strPtr;
4564 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4568 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4570 if(*pcbNeeded <= cbBuf)
4571 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4573 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4574 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4577 /* .pszHardwareID */
4578 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4580 if(*pcbNeeded <= cbBuf)
4581 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4583 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4584 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4588 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4590 if(*pcbNeeded <= cbBuf)
4591 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4593 if (di) di->pszProvider = (LPWSTR)strPtr;
4594 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4598 RegCloseKey(hkeyDriver);
4602 /* support is missing, but not important enough for a FIXME */
4603 TRACE("level 8: incomplete\n");
4605 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4606 RegCloseKey(hkeyDriver);
4610 /*****************************************************************************
4611 * GetPrinterDriverW [WINSPOOL.@]
4613 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4614 DWORD Level, LPBYTE pDriverInfo,
4615 DWORD cbBuf, LPDWORD pcbNeeded)
4618 WCHAR DriverName[100];
4619 DWORD ret, type, size, needed = 0;
4621 HKEY hkeyPrinter, hkeyDrivers;
4622 const printenv_t * env;
4624 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4625 Level,pDriverInfo,cbBuf, pcbNeeded);
4628 ZeroMemory(pDriverInfo, cbBuf);
4630 if (!(name = get_opened_printer_name(hPrinter))) {
4631 SetLastError(ERROR_INVALID_HANDLE);
4635 if (Level < 1 || Level == 7 || Level > 8) {
4636 SetLastError(ERROR_INVALID_LEVEL);
4640 env = validate_envW(pEnvironment);
4641 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4643 ret = open_printer_reg_key( name, &hkeyPrinter );
4646 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4647 SetLastError( ret );
4651 size = sizeof(DriverName);
4653 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4654 (LPBYTE)DriverName, &size);
4655 RegCloseKey(hkeyPrinter);
4656 if(ret != ERROR_SUCCESS) {
4657 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4661 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4663 ERR("Can't create Drivers key\n");
4667 size = di_sizeof[Level];
4668 if ((size <= cbBuf) && pDriverInfo)
4669 ptr = pDriverInfo + size;
4671 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4672 env, Level, pDriverInfo, ptr,
4673 (cbBuf < size) ? 0 : cbBuf - size,
4675 RegCloseKey(hkeyDrivers);
4679 RegCloseKey(hkeyDrivers);
4681 if(pcbNeeded) *pcbNeeded = size + needed;
4682 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4683 if(cbBuf >= size + needed) return TRUE;
4684 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4688 /*****************************************************************************
4689 * GetPrinterDriverA [WINSPOOL.@]
4691 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4692 DWORD Level, LPBYTE pDriverInfo,
4693 DWORD cbBuf, LPDWORD pcbNeeded)
4696 UNICODE_STRING pEnvW;
4702 ZeroMemory(pDriverInfo, cbBuf);
4703 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4706 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4707 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4710 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4712 HeapFree(GetProcessHeap(), 0, buf);
4714 RtlFreeUnicodeString(&pEnvW);
4718 /*****************************************************************************
4719 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4721 * Return the PATH for the Printer-Drivers (UNICODE)
4724 * pName [I] Servername (NT only) or NULL (local Computer)
4725 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4726 * Level [I] Structure-Level (must be 1)
4727 * pDriverDirectory [O] PTR to Buffer that receives the Result
4728 * cbBuf [I] Size of Buffer at pDriverDirectory
4729 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4730 * required for pDriverDirectory
4733 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4734 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4735 * if cbBuf is too small
4737 * Native Values returned in pDriverDirectory on Success:
4738 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4739 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4740 *| win9x(Windows 4.0): "%winsysdir%"
4742 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4745 *- Only NULL or "" is supported for pName
4748 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4749 DWORD Level, LPBYTE pDriverDirectory,
4750 DWORD cbBuf, LPDWORD pcbNeeded)
4752 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4753 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4755 if ((backend == NULL) && !load_backend()) return FALSE;
4758 /* (Level != 1) is ignored in win9x */
4759 SetLastError(ERROR_INVALID_LEVEL);
4762 if (pcbNeeded == NULL) {
4763 /* (pcbNeeded == NULL) is ignored in win9x */
4764 SetLastError(RPC_X_NULL_REF_POINTER);
4768 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4769 pDriverDirectory, cbBuf, pcbNeeded);
4774 /*****************************************************************************
4775 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4777 * Return the PATH for the Printer-Drivers (ANSI)
4779 * See GetPrinterDriverDirectoryW.
4782 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4785 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4786 DWORD Level, LPBYTE pDriverDirectory,
4787 DWORD cbBuf, LPDWORD pcbNeeded)
4789 UNICODE_STRING nameW, environmentW;
4792 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4793 WCHAR *driverDirectoryW = NULL;
4795 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4796 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4798 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4800 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4801 else nameW.Buffer = NULL;
4802 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4803 else environmentW.Buffer = NULL;
4805 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4806 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4809 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4810 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4812 *pcbNeeded = needed;
4813 ret = (needed <= cbBuf) ? TRUE : FALSE;
4815 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4817 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4819 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4820 RtlFreeUnicodeString(&environmentW);
4821 RtlFreeUnicodeString(&nameW);
4826 /*****************************************************************************
4827 * AddPrinterDriverA [WINSPOOL.@]
4829 * See AddPrinterDriverW.
4832 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4834 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4835 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4838 /******************************************************************************
4839 * AddPrinterDriverW (WINSPOOL.@)
4841 * Install a Printer Driver
4844 * pName [I] Servername or NULL (local Computer)
4845 * level [I] Level for the supplied DRIVER_INFO_*W struct
4846 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4853 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4855 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4856 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4859 /*****************************************************************************
4860 * AddPrintProcessorA [WINSPOOL.@]
4862 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4863 LPSTR pPrintProcessorName)
4865 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4866 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4870 /*****************************************************************************
4871 * AddPrintProcessorW [WINSPOOL.@]
4873 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4874 LPWSTR pPrintProcessorName)
4876 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4877 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4881 /*****************************************************************************
4882 * AddPrintProvidorA [WINSPOOL.@]
4884 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4886 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4890 /*****************************************************************************
4891 * AddPrintProvidorW [WINSPOOL.@]
4893 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4895 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4899 /*****************************************************************************
4900 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4902 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4903 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4905 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4906 pDevModeOutput, pDevModeInput);
4910 /*****************************************************************************
4911 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4913 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4914 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4916 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4917 pDevModeOutput, pDevModeInput);
4921 /*****************************************************************************
4922 * PrinterProperties [WINSPOOL.@]
4924 * Displays a dialog to set the properties of the printer.
4927 * nonzero on success or zero on failure
4930 * implemented as stub only
4932 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4933 HANDLE hPrinter /* [in] handle to printer object */
4935 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4936 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4940 /*****************************************************************************
4941 * EnumJobsA [WINSPOOL.@]
4944 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4945 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4948 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4949 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4951 if(pcbNeeded) *pcbNeeded = 0;
4952 if(pcReturned) *pcReturned = 0;
4957 /*****************************************************************************
4958 * EnumJobsW [WINSPOOL.@]
4961 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4962 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4965 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4966 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4968 if(pcbNeeded) *pcbNeeded = 0;
4969 if(pcReturned) *pcReturned = 0;
4973 /*****************************************************************************
4974 * WINSPOOL_EnumPrinterDrivers [internal]
4976 * Delivers information about all printer drivers installed on the
4977 * localhost or a given server
4980 * nonzero on success or zero on failure. If the buffer for the returned
4981 * information is too small the function will return an error
4984 * - only implemented for localhost, foreign hosts will return an error
4986 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4987 DWORD Level, LPBYTE pDriverInfo,
4989 DWORD cbBuf, LPDWORD pcbNeeded,
4990 LPDWORD pcFound, DWORD data_offset)
4994 const printenv_t * env;
4996 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4997 debugstr_w(pName), debugstr_w(pEnvironment),
4998 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5000 env = validate_envW(pEnvironment);
5001 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5005 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5007 ERR("Can't open Drivers key\n");
5011 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5012 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5013 RegCloseKey(hkeyDrivers);
5014 ERR("Can't query Drivers key\n");
5017 TRACE("Found %d Drivers\n", *pcFound);
5019 /* get size of single struct
5020 * unicode and ascii structure have the same size
5022 size = di_sizeof[Level];
5024 if (data_offset == 0)
5025 data_offset = size * (*pcFound);
5026 *pcbNeeded = data_offset;
5028 for( i = 0; i < *pcFound; i++) {
5029 WCHAR DriverNameW[255];
5030 PBYTE table_ptr = NULL;
5031 PBYTE data_ptr = NULL;
5034 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5036 ERR("Can't enum key number %d\n", i);
5037 RegCloseKey(hkeyDrivers);
5041 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5042 table_ptr = pDriverInfo + (driver_index + i) * size;
5043 if (pDriverInfo && *pcbNeeded <= cbBuf)
5044 data_ptr = pDriverInfo + *pcbNeeded;
5046 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5047 env, Level, table_ptr, data_ptr,
5048 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5050 RegCloseKey(hkeyDrivers);
5054 *pcbNeeded += needed;
5057 RegCloseKey(hkeyDrivers);
5059 if(cbBuf < *pcbNeeded){
5060 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5067 /*****************************************************************************
5068 * EnumPrinterDriversW [WINSPOOL.@]
5070 * see function EnumPrinterDrivers for RETURNS, BUGS
5072 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5073 LPBYTE pDriverInfo, DWORD cbBuf,
5074 LPDWORD pcbNeeded, LPDWORD pcReturned)
5076 static const WCHAR allW[] = {'a','l','l',0};
5080 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5082 SetLastError(RPC_X_NULL_REF_POINTER);
5086 /* check for local drivers */
5087 if((pName) && (pName[0])) {
5088 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5089 SetLastError(ERROR_ACCESS_DENIED);
5093 /* check input parameter */
5094 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5095 SetLastError(ERROR_INVALID_LEVEL);
5099 if(pDriverInfo && cbBuf > 0)
5100 memset( pDriverInfo, 0, cbBuf);
5102 /* Exception: pull all printers */
5103 if (pEnvironment && !strcmpW(pEnvironment, allW))
5105 DWORD i, needed, bufsize = cbBuf;
5106 DWORD total_needed = 0;
5107 DWORD total_found = 0;
5110 /* Precompute the overall total; we need this to know
5111 where pointers end and data begins (i.e. data_offset) */
5112 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5115 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5116 NULL, 0, 0, &needed, &found, 0);
5117 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5118 total_needed += needed;
5119 total_found += found;
5122 data_offset = di_sizeof[Level] * total_found;
5127 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5130 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5131 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5132 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5134 *pcReturned += found;
5135 *pcbNeeded = needed;
5136 data_offset = needed;
5137 total_found += found;
5142 /* Normal behavior */
5143 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5144 0, cbBuf, pcbNeeded, &found, 0);
5146 *pcReturned = found;
5151 /*****************************************************************************
5152 * EnumPrinterDriversA [WINSPOOL.@]
5154 * see function EnumPrinterDrivers for RETURNS, BUGS
5156 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5157 LPBYTE pDriverInfo, DWORD cbBuf,
5158 LPDWORD pcbNeeded, LPDWORD pcReturned)
5161 UNICODE_STRING pNameW, pEnvironmentW;
5162 PWSTR pwstrNameW, pwstrEnvironmentW;
5166 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5168 pwstrNameW = asciitounicode(&pNameW, pName);
5169 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5171 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5172 buf, cbBuf, pcbNeeded, pcReturned);
5174 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5176 HeapFree(GetProcessHeap(), 0, buf);
5178 RtlFreeUnicodeString(&pNameW);
5179 RtlFreeUnicodeString(&pEnvironmentW);
5184 /******************************************************************************
5185 * EnumPortsA (WINSPOOL.@)
5190 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5191 LPDWORD pcbNeeded, LPDWORD pcReturned)
5194 LPBYTE bufferW = NULL;
5195 LPWSTR nameW = NULL;
5197 DWORD numentries = 0;
5200 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5201 cbBuf, pcbNeeded, pcReturned);
5203 /* convert servername to unicode */
5205 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5206 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5207 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5209 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5210 needed = cbBuf * sizeof(WCHAR);
5211 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5212 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5214 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5215 if (pcbNeeded) needed = *pcbNeeded;
5216 /* HeapReAlloc return NULL, when bufferW was NULL */
5217 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5218 HeapAlloc(GetProcessHeap(), 0, needed);
5220 /* Try again with the large Buffer */
5221 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5223 needed = pcbNeeded ? *pcbNeeded : 0;
5224 numentries = pcReturned ? *pcReturned : 0;
5227 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5228 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5231 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5232 DWORD entrysize = 0;
5235 LPPORT_INFO_2W pi2w;
5236 LPPORT_INFO_2A pi2a;
5239 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5241 /* First pass: calculate the size for all Entries */
5242 pi2w = (LPPORT_INFO_2W) bufferW;
5243 pi2a = (LPPORT_INFO_2A) pPorts;
5245 while (index < numentries) {
5247 needed += entrysize; /* PORT_INFO_?A */
5248 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5250 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5251 NULL, 0, NULL, NULL);
5253 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5254 NULL, 0, NULL, NULL);
5255 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5256 NULL, 0, NULL, NULL);
5258 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5259 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5260 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5263 /* check for errors and quit on failure */
5264 if (cbBuf < needed) {
5265 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5269 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5270 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5271 cbBuf -= len ; /* free Bytes in the user-Buffer */
5272 pi2w = (LPPORT_INFO_2W) bufferW;
5273 pi2a = (LPPORT_INFO_2A) pPorts;
5275 /* Second Pass: Fill the User Buffer (if we have one) */
5276 while ((index < numentries) && pPorts) {
5278 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5279 pi2a->pPortName = ptr;
5280 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5281 ptr, cbBuf , NULL, NULL);
5285 pi2a->pMonitorName = ptr;
5286 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5287 ptr, cbBuf, NULL, NULL);
5291 pi2a->pDescription = ptr;
5292 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5293 ptr, cbBuf, NULL, NULL);
5297 pi2a->fPortType = pi2w->fPortType;
5298 pi2a->Reserved = 0; /* documented: "must be zero" */
5301 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5302 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5303 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5308 if (pcbNeeded) *pcbNeeded = needed;
5309 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5311 HeapFree(GetProcessHeap(), 0, nameW);
5312 HeapFree(GetProcessHeap(), 0, bufferW);
5314 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5315 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5321 /******************************************************************************
5322 * EnumPortsW (WINSPOOL.@)
5324 * Enumerate available Ports
5327 * pName [I] Servername or NULL (local Computer)
5328 * Level [I] Structure-Level (1 or 2)
5329 * pPorts [O] PTR to Buffer that receives the Result
5330 * cbBuf [I] Size of Buffer at pPorts
5331 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5332 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5336 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5339 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5342 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5343 cbBuf, pcbNeeded, pcReturned);
5345 if ((backend == NULL) && !load_backend()) return FALSE;
5347 /* Level is not checked in win9x */
5348 if (!Level || (Level > 2)) {
5349 WARN("level (%d) is ignored in win9x\n", Level);
5350 SetLastError(ERROR_INVALID_LEVEL);
5353 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5354 SetLastError(RPC_X_NULL_REF_POINTER);
5358 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5361 /******************************************************************************
5362 * GetDefaultPrinterW (WINSPOOL.@)
5365 * This function must read the value from data 'device' of key
5366 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5368 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5372 WCHAR *buffer, *ptr;
5376 SetLastError(ERROR_INVALID_PARAMETER);
5380 /* make the buffer big enough for the stuff from the profile/registry,
5381 * the content must fit into the local buffer to compute the correct
5382 * size even if the extern buffer is too small or not given.
5383 * (20 for ,driver,port) */
5385 len = max(100, (insize + 20));
5386 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5388 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5390 SetLastError (ERROR_FILE_NOT_FOUND);
5394 TRACE("%s\n", debugstr_w(buffer));
5396 if ((ptr = strchrW(buffer, ',')) == NULL)
5398 SetLastError(ERROR_INVALID_NAME);
5404 *namesize = strlenW(buffer) + 1;
5405 if(!name || (*namesize > insize))
5407 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5411 strcpyW(name, buffer);
5414 HeapFree( GetProcessHeap(), 0, buffer);
5419 /******************************************************************************
5420 * GetDefaultPrinterA (WINSPOOL.@)
5422 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5426 WCHAR *bufferW = NULL;
5430 SetLastError(ERROR_INVALID_PARAMETER);
5434 if(name && *namesize) {
5436 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5439 if(!GetDefaultPrinterW( bufferW, namesize)) {
5444 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5448 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5451 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5454 HeapFree( GetProcessHeap(), 0, bufferW);
5459 /******************************************************************************
5460 * SetDefaultPrinterW (WINSPOOL.204)
5462 * Set the Name of the Default Printer
5465 * pszPrinter [I] Name of the Printer or NULL
5472 * When the Parameter is NULL or points to an Empty String and
5473 * a Default Printer was already present, then this Function changes nothing.
5474 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5475 * the First enumerated local Printer is used.
5478 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5480 WCHAR default_printer[MAX_PATH];
5481 LPWSTR buffer = NULL;
5487 TRACE("(%s)\n", debugstr_w(pszPrinter));
5488 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5490 default_printer[0] = '\0';
5491 size = sizeof(default_printer)/sizeof(WCHAR);
5493 /* if we have a default Printer, do nothing. */
5494 if (GetDefaultPrinterW(default_printer, &size))
5498 /* we have no default Printer: search local Printers and use the first */
5499 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5501 default_printer[0] = '\0';
5502 size = sizeof(default_printer)/sizeof(WCHAR);
5503 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5505 pszPrinter = default_printer;
5506 TRACE("using %s\n", debugstr_w(pszPrinter));
5511 if (pszPrinter == NULL) {
5512 TRACE("no local printer found\n");
5513 SetLastError(ERROR_FILE_NOT_FOUND);
5518 /* "pszPrinter" is never empty or NULL here. */
5519 namelen = lstrlenW(pszPrinter);
5520 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5521 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5523 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5524 HeapFree(GetProcessHeap(), 0, buffer);
5525 SetLastError(ERROR_FILE_NOT_FOUND);
5529 /* read the devices entry for the printer (driver,port) to build the string for the
5530 default device entry (printer,driver,port) */
5531 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5532 buffer[namelen] = ',';
5533 namelen++; /* move index to the start of the driver */
5535 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5536 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5538 TRACE("set device to %s\n", debugstr_w(buffer));
5540 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5541 TRACE("failed to set the device entry: %d\n", GetLastError());
5542 lres = ERROR_INVALID_PRINTER_NAME;
5545 /* remove the next section, when INIFileMapping is implemented */
5548 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5549 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5556 if (lres != ERROR_FILE_NOT_FOUND)
5557 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5559 SetLastError(ERROR_INVALID_PRINTER_NAME);
5563 HeapFree(GetProcessHeap(), 0, buffer);
5564 return (lres == ERROR_SUCCESS);
5567 /******************************************************************************
5568 * SetDefaultPrinterA (WINSPOOL.202)
5570 * See SetDefaultPrinterW.
5573 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5575 LPWSTR bufferW = NULL;
5578 TRACE("(%s)\n", debugstr_a(pszPrinter));
5580 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5581 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5582 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5584 res = SetDefaultPrinterW(bufferW);
5585 HeapFree(GetProcessHeap(), 0, bufferW);
5589 /******************************************************************************
5590 * SetPrinterDataExA (WINSPOOL.@)
5592 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5593 LPCSTR pValueName, DWORD Type,
5594 LPBYTE pData, DWORD cbData)
5596 HKEY hkeyPrinter, hkeySubkey;
5599 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5600 debugstr_a(pValueName), Type, pData, cbData);
5602 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5606 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5608 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5609 RegCloseKey(hkeyPrinter);
5612 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5613 RegCloseKey(hkeySubkey);
5614 RegCloseKey(hkeyPrinter);
5618 /******************************************************************************
5619 * SetPrinterDataExW (WINSPOOL.@)
5621 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5622 LPCWSTR pValueName, DWORD Type,
5623 LPBYTE pData, DWORD cbData)
5625 HKEY hkeyPrinter, hkeySubkey;
5628 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5629 debugstr_w(pValueName), Type, pData, cbData);
5631 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5635 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5637 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5638 RegCloseKey(hkeyPrinter);
5641 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5642 RegCloseKey(hkeySubkey);
5643 RegCloseKey(hkeyPrinter);
5647 /******************************************************************************
5648 * SetPrinterDataA (WINSPOOL.@)
5650 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5651 LPBYTE pData, DWORD cbData)
5653 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5657 /******************************************************************************
5658 * SetPrinterDataW (WINSPOOL.@)
5660 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5661 LPBYTE pData, DWORD cbData)
5663 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5667 /******************************************************************************
5668 * GetPrinterDataExA (WINSPOOL.@)
5670 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5671 LPCSTR pValueName, LPDWORD pType,
5672 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5674 opened_printer_t *printer;
5675 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5678 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5679 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5681 printer = get_opened_printer(hPrinter);
5682 if(!printer) return ERROR_INVALID_HANDLE;
5684 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5685 if (ret) return ret;
5687 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5689 if (printer->name) {
5691 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5693 RegCloseKey(hkeyPrinters);
5696 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5697 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5698 RegCloseKey(hkeyPrinter);
5699 RegCloseKey(hkeyPrinters);
5704 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5705 0, pType, pData, pcbNeeded);
5707 if (!ret && !pData) ret = ERROR_MORE_DATA;
5709 RegCloseKey(hkeySubkey);
5710 RegCloseKey(hkeyPrinter);
5711 RegCloseKey(hkeyPrinters);
5713 TRACE("--> %d\n", ret);
5717 /******************************************************************************
5718 * GetPrinterDataExW (WINSPOOL.@)
5720 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5721 LPCWSTR pValueName, LPDWORD pType,
5722 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5724 opened_printer_t *printer;
5725 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5728 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5729 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5731 printer = get_opened_printer(hPrinter);
5732 if(!printer) return ERROR_INVALID_HANDLE;
5734 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5735 if (ret) return ret;
5737 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5739 if (printer->name) {
5741 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5743 RegCloseKey(hkeyPrinters);
5746 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5747 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5748 RegCloseKey(hkeyPrinter);
5749 RegCloseKey(hkeyPrinters);
5754 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5755 0, pType, pData, pcbNeeded);
5757 if (!ret && !pData) ret = ERROR_MORE_DATA;
5759 RegCloseKey(hkeySubkey);
5760 RegCloseKey(hkeyPrinter);
5761 RegCloseKey(hkeyPrinters);
5763 TRACE("--> %d\n", ret);
5767 /******************************************************************************
5768 * GetPrinterDataA (WINSPOOL.@)
5770 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5771 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5773 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5774 pData, nSize, pcbNeeded);
5777 /******************************************************************************
5778 * GetPrinterDataW (WINSPOOL.@)
5780 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5781 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5783 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5784 pData, nSize, pcbNeeded);
5787 /*******************************************************************************
5788 * EnumPrinterDataExW [WINSPOOL.@]
5790 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5791 LPBYTE pEnumValues, DWORD cbEnumValues,
5792 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5794 HKEY hkPrinter, hkSubKey;
5795 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5796 cbValueNameLen, cbMaxValueLen, cbValueLen,
5801 PPRINTER_ENUM_VALUESW ppev;
5803 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5805 if (pKeyName == NULL || *pKeyName == 0)
5806 return ERROR_INVALID_PARAMETER;
5808 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5809 if (ret != ERROR_SUCCESS)
5811 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5816 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5817 if (ret != ERROR_SUCCESS)
5819 r = RegCloseKey (hkPrinter);
5820 if (r != ERROR_SUCCESS)
5821 WARN ("RegCloseKey returned %i\n", r);
5822 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5823 debugstr_w (pKeyName), ret);
5827 ret = RegCloseKey (hkPrinter);
5828 if (ret != ERROR_SUCCESS)
5830 ERR ("RegCloseKey returned %i\n", ret);
5831 r = RegCloseKey (hkSubKey);
5832 if (r != ERROR_SUCCESS)
5833 WARN ("RegCloseKey returned %i\n", r);
5837 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5838 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5839 if (ret != ERROR_SUCCESS)
5841 r = RegCloseKey (hkSubKey);
5842 if (r != ERROR_SUCCESS)
5843 WARN ("RegCloseKey returned %i\n", r);
5844 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5848 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5849 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5851 if (cValues == 0) /* empty key */
5853 r = RegCloseKey (hkSubKey);
5854 if (r != ERROR_SUCCESS)
5855 WARN ("RegCloseKey returned %i\n", r);
5856 *pcbEnumValues = *pnEnumValues = 0;
5857 return ERROR_SUCCESS;
5860 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5862 hHeap = GetProcessHeap ();
5865 ERR ("GetProcessHeap failed\n");
5866 r = RegCloseKey (hkSubKey);
5867 if (r != ERROR_SUCCESS)
5868 WARN ("RegCloseKey returned %i\n", r);
5869 return ERROR_OUTOFMEMORY;
5872 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5873 if (lpValueName == NULL)
5875 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5876 r = RegCloseKey (hkSubKey);
5877 if (r != ERROR_SUCCESS)
5878 WARN ("RegCloseKey returned %i\n", r);
5879 return ERROR_OUTOFMEMORY;
5882 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5883 if (lpValue == NULL)
5885 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5886 if (HeapFree (hHeap, 0, lpValueName) == 0)
5887 WARN ("HeapFree failed with code %i\n", GetLastError ());
5888 r = RegCloseKey (hkSubKey);
5889 if (r != ERROR_SUCCESS)
5890 WARN ("RegCloseKey returned %i\n", r);
5891 return ERROR_OUTOFMEMORY;
5894 TRACE ("pass 1: calculating buffer required for all names and values\n");
5896 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5898 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5900 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5902 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5903 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5904 NULL, NULL, lpValue, &cbValueLen);
5905 if (ret != ERROR_SUCCESS)
5907 if (HeapFree (hHeap, 0, lpValue) == 0)
5908 WARN ("HeapFree failed with code %i\n", GetLastError ());
5909 if (HeapFree (hHeap, 0, lpValueName) == 0)
5910 WARN ("HeapFree failed with code %i\n", GetLastError ());
5911 r = RegCloseKey (hkSubKey);
5912 if (r != ERROR_SUCCESS)
5913 WARN ("RegCloseKey returned %i\n", r);
5914 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5918 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5919 debugstr_w (lpValueName), dwIndex,
5920 cbValueNameLen + 1, cbValueLen);
5922 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5923 cbBufSize += cbValueLen;
5926 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5928 *pcbEnumValues = cbBufSize;
5929 *pnEnumValues = cValues;
5931 if (cbEnumValues < cbBufSize) /* buffer too small */
5933 if (HeapFree (hHeap, 0, lpValue) == 0)
5934 WARN ("HeapFree failed with code %i\n", GetLastError ());
5935 if (HeapFree (hHeap, 0, lpValueName) == 0)
5936 WARN ("HeapFree failed with code %i\n", GetLastError ());
5937 r = RegCloseKey (hkSubKey);
5938 if (r != ERROR_SUCCESS)
5939 WARN ("RegCloseKey returned %i\n", r);
5940 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5941 return ERROR_MORE_DATA;
5944 TRACE ("pass 2: copying all names and values to buffer\n");
5946 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5947 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5949 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5951 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5952 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5953 NULL, &dwType, lpValue, &cbValueLen);
5954 if (ret != ERROR_SUCCESS)
5956 if (HeapFree (hHeap, 0, lpValue) == 0)
5957 WARN ("HeapFree failed with code %i\n", GetLastError ());
5958 if (HeapFree (hHeap, 0, lpValueName) == 0)
5959 WARN ("HeapFree failed with code %i\n", GetLastError ());
5960 r = RegCloseKey (hkSubKey);
5961 if (r != ERROR_SUCCESS)
5962 WARN ("RegCloseKey returned %i\n", r);
5963 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5967 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5968 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5969 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5970 pEnumValues += cbValueNameLen;
5972 /* return # of *bytes* (including trailing \0), not # of chars */
5973 ppev[dwIndex].cbValueName = cbValueNameLen;
5975 ppev[dwIndex].dwType = dwType;
5977 memcpy (pEnumValues, lpValue, cbValueLen);
5978 ppev[dwIndex].pData = pEnumValues;
5979 pEnumValues += cbValueLen;
5981 ppev[dwIndex].cbData = cbValueLen;
5983 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5984 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5987 if (HeapFree (hHeap, 0, lpValue) == 0)
5989 ret = GetLastError ();
5990 ERR ("HeapFree failed with code %i\n", ret);
5991 if (HeapFree (hHeap, 0, lpValueName) == 0)
5992 WARN ("HeapFree failed with code %i\n", GetLastError ());
5993 r = RegCloseKey (hkSubKey);
5994 if (r != ERROR_SUCCESS)
5995 WARN ("RegCloseKey returned %i\n", r);
5999 if (HeapFree (hHeap, 0, lpValueName) == 0)
6001 ret = GetLastError ();
6002 ERR ("HeapFree failed with code %i\n", ret);
6003 r = RegCloseKey (hkSubKey);
6004 if (r != ERROR_SUCCESS)
6005 WARN ("RegCloseKey returned %i\n", r);
6009 ret = RegCloseKey (hkSubKey);
6010 if (ret != ERROR_SUCCESS)
6012 ERR ("RegCloseKey returned %i\n", ret);
6016 return ERROR_SUCCESS;
6019 /*******************************************************************************
6020 * EnumPrinterDataExA [WINSPOOL.@]
6022 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6023 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6024 * what Windows 2000 SP1 does.
6027 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6028 LPBYTE pEnumValues, DWORD cbEnumValues,
6029 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6033 DWORD ret, dwIndex, dwBufSize;
6037 TRACE ("%p %s\n", hPrinter, pKeyName);
6039 if (pKeyName == NULL || *pKeyName == 0)
6040 return ERROR_INVALID_PARAMETER;
6042 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6045 ret = GetLastError ();
6046 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6050 hHeap = GetProcessHeap ();
6053 ERR ("GetProcessHeap failed\n");
6054 return ERROR_OUTOFMEMORY;
6057 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6058 if (pKeyNameW == NULL)
6060 ERR ("Failed to allocate %i bytes from process heap\n",
6061 (LONG)(len * sizeof (WCHAR)));
6062 return ERROR_OUTOFMEMORY;
6065 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6067 ret = GetLastError ();
6068 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6069 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6070 WARN ("HeapFree failed with code %i\n", GetLastError ());
6074 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6075 pcbEnumValues, pnEnumValues);
6076 if (ret != ERROR_SUCCESS)
6078 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6079 WARN ("HeapFree failed with code %i\n", GetLastError ());
6080 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6084 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6086 ret = GetLastError ();
6087 ERR ("HeapFree failed with code %i\n", ret);
6091 if (*pnEnumValues == 0) /* empty key */
6092 return ERROR_SUCCESS;
6095 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6097 PPRINTER_ENUM_VALUESW ppev =
6098 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6100 if (dwBufSize < ppev->cbValueName)
6101 dwBufSize = ppev->cbValueName;
6103 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6104 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6105 dwBufSize = ppev->cbData;
6108 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6110 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6111 if (pBuffer == NULL)
6113 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6114 return ERROR_OUTOFMEMORY;
6117 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6119 PPRINTER_ENUM_VALUESW ppev =
6120 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6122 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6123 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6127 ret = GetLastError ();
6128 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6129 if (HeapFree (hHeap, 0, pBuffer) == 0)
6130 WARN ("HeapFree failed with code %i\n", GetLastError ());
6134 memcpy (ppev->pValueName, pBuffer, len);
6136 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6138 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6139 ppev->dwType != REG_MULTI_SZ)
6142 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6143 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6146 ret = GetLastError ();
6147 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6148 if (HeapFree (hHeap, 0, pBuffer) == 0)
6149 WARN ("HeapFree failed with code %i\n", GetLastError ());
6153 memcpy (ppev->pData, pBuffer, len);
6155 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6156 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6159 if (HeapFree (hHeap, 0, pBuffer) == 0)
6161 ret = GetLastError ();
6162 ERR ("HeapFree failed with code %i\n", ret);
6166 return ERROR_SUCCESS;
6169 /******************************************************************************
6170 * AbortPrinter (WINSPOOL.@)
6172 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6174 FIXME("(%p), stub!\n", hPrinter);
6178 /******************************************************************************
6179 * AddPortA (WINSPOOL.@)
6184 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6186 LPWSTR nameW = NULL;
6187 LPWSTR monitorW = NULL;
6191 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6194 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6195 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6196 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6200 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6201 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6202 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6204 res = AddPortW(nameW, hWnd, monitorW);
6205 HeapFree(GetProcessHeap(), 0, nameW);
6206 HeapFree(GetProcessHeap(), 0, monitorW);
6210 /******************************************************************************
6211 * AddPortW (WINSPOOL.@)
6213 * Add a Port for a specific Monitor
6216 * pName [I] Servername or NULL (local Computer)
6217 * hWnd [I] Handle to parent Window for the Dialog-Box
6218 * pMonitorName [I] Name of the Monitor that manage the Port
6225 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6227 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6229 if ((backend == NULL) && !load_backend()) return FALSE;
6231 if (!pMonitorName) {
6232 SetLastError(RPC_X_NULL_REF_POINTER);
6236 return backend->fpAddPort(pName, hWnd, pMonitorName);
6239 /******************************************************************************
6240 * AddPortExA (WINSPOOL.@)
6245 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6248 PORT_INFO_2A * pi2A;
6249 LPWSTR nameW = NULL;
6250 LPWSTR monitorW = NULL;
6254 pi2A = (PORT_INFO_2A *) pBuffer;
6256 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6257 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6259 if ((level < 1) || (level > 2)) {
6260 SetLastError(ERROR_INVALID_LEVEL);
6265 SetLastError(ERROR_INVALID_PARAMETER);
6270 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6271 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6272 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6276 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6277 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6278 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6281 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6283 if (pi2A->pPortName) {
6284 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6285 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6286 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6290 if (pi2A->pMonitorName) {
6291 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6292 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6293 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6296 if (pi2A->pDescription) {
6297 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6298 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6299 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6301 pi2W.fPortType = pi2A->fPortType;
6302 pi2W.Reserved = pi2A->Reserved;
6305 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6307 HeapFree(GetProcessHeap(), 0, nameW);
6308 HeapFree(GetProcessHeap(), 0, monitorW);
6309 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6310 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6311 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6316 /******************************************************************************
6317 * AddPortExW (WINSPOOL.@)
6319 * Add a Port for a specific Monitor, without presenting a user interface
6322 * pName [I] Servername or NULL (local Computer)
6323 * level [I] Structure-Level (1 or 2) for pBuffer
6324 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6325 * pMonitorName [I] Name of the Monitor that manage the Port
6332 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6336 pi2 = (PORT_INFO_2W *) pBuffer;
6338 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6339 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6340 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6341 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6343 if ((backend == NULL) && !load_backend()) return FALSE;
6345 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6346 SetLastError(ERROR_INVALID_PARAMETER);
6350 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6353 /******************************************************************************
6354 * AddPrinterConnectionA (WINSPOOL.@)
6356 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6358 FIXME("%s\n", debugstr_a(pName));
6362 /******************************************************************************
6363 * AddPrinterConnectionW (WINSPOOL.@)
6365 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6367 FIXME("%s\n", debugstr_w(pName));
6371 /******************************************************************************
6372 * AddPrinterDriverExW (WINSPOOL.@)
6374 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6377 * pName [I] Servername or NULL (local Computer)
6378 * level [I] Level for the supplied DRIVER_INFO_*W struct
6379 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6380 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6387 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6389 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6391 if ((backend == NULL) && !load_backend()) return FALSE;
6393 if (level < 2 || level == 5 || level == 7 || level > 8) {
6394 SetLastError(ERROR_INVALID_LEVEL);
6399 SetLastError(ERROR_INVALID_PARAMETER);
6403 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6406 /******************************************************************************
6407 * AddPrinterDriverExA (WINSPOOL.@)
6409 * See AddPrinterDriverExW.
6412 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6414 DRIVER_INFO_8A *diA;
6416 LPWSTR nameW = NULL;
6421 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6423 diA = (DRIVER_INFO_8A *) pDriverInfo;
6424 ZeroMemory(&diW, sizeof(diW));
6426 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6427 SetLastError(ERROR_INVALID_LEVEL);
6432 SetLastError(ERROR_INVALID_PARAMETER);
6436 /* convert servername to unicode */
6438 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6439 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6440 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6444 diW.cVersion = diA->cVersion;
6447 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6448 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6449 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6452 if (diA->pEnvironment) {
6453 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6454 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6455 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6458 if (diA->pDriverPath) {
6459 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6460 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6461 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6464 if (diA->pDataFile) {
6465 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6466 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6467 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6470 if (diA->pConfigFile) {
6471 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6472 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6473 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6476 if ((Level > 2) && diA->pDependentFiles) {
6477 lenA = multi_sz_lenA(diA->pDependentFiles);
6478 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6479 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6480 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6483 if ((Level > 2) && diA->pMonitorName) {
6484 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6485 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6486 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6489 if ((Level > 3) && diA->pDefaultDataType) {
6490 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6491 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6492 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6495 if ((Level > 3) && diA->pszzPreviousNames) {
6496 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6497 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6498 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6499 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6502 if ((Level > 5) && diA->pszMfgName) {
6503 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6504 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6505 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6508 if ((Level > 5) && diA->pszOEMUrl) {
6509 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6510 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6511 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6514 if ((Level > 5) && diA->pszHardwareID) {
6515 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6516 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6517 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6520 if ((Level > 5) && diA->pszProvider) {
6521 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6522 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6523 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6527 FIXME("level %u is incomplete\n", Level);
6530 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6531 TRACE("got %u with %u\n", res, GetLastError());
6532 HeapFree(GetProcessHeap(), 0, nameW);
6533 HeapFree(GetProcessHeap(), 0, diW.pName);
6534 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6535 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6536 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6537 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6538 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6539 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6540 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6541 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6542 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6543 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6544 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6545 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6547 TRACE("=> %u with %u\n", res, GetLastError());
6551 /******************************************************************************
6552 * ConfigurePortA (WINSPOOL.@)
6554 * See ConfigurePortW.
6557 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6559 LPWSTR nameW = NULL;
6560 LPWSTR portW = NULL;
6564 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6566 /* convert servername to unicode */
6568 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6569 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6570 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6573 /* convert portname to unicode */
6575 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6576 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6577 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6580 res = ConfigurePortW(nameW, hWnd, portW);
6581 HeapFree(GetProcessHeap(), 0, nameW);
6582 HeapFree(GetProcessHeap(), 0, portW);
6586 /******************************************************************************
6587 * ConfigurePortW (WINSPOOL.@)
6589 * Display the Configuration-Dialog for a specific Port
6592 * pName [I] Servername or NULL (local Computer)
6593 * hWnd [I] Handle to parent Window for the Dialog-Box
6594 * pPortName [I] Name of the Port, that should be configured
6601 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6604 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6606 if ((backend == NULL) && !load_backend()) return FALSE;
6609 SetLastError(RPC_X_NULL_REF_POINTER);
6613 return backend->fpConfigurePort(pName, hWnd, pPortName);
6616 /******************************************************************************
6617 * ConnectToPrinterDlg (WINSPOOL.@)
6619 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6621 FIXME("%p %x\n", hWnd, Flags);
6625 /******************************************************************************
6626 * DeletePrinterConnectionA (WINSPOOL.@)
6628 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6630 FIXME("%s\n", debugstr_a(pName));
6634 /******************************************************************************
6635 * DeletePrinterConnectionW (WINSPOOL.@)
6637 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6639 FIXME("%s\n", debugstr_w(pName));
6643 /******************************************************************************
6644 * DeletePrinterDriverExW (WINSPOOL.@)
6646 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6647 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6652 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6653 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6655 if(pName && pName[0])
6657 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6658 SetLastError(ERROR_INVALID_PARAMETER);
6664 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6665 SetLastError(ERROR_INVALID_PARAMETER);
6669 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6673 ERR("Can't open drivers key\n");
6677 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6680 RegCloseKey(hkey_drivers);
6685 /******************************************************************************
6686 * DeletePrinterDriverExA (WINSPOOL.@)
6688 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6689 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6691 UNICODE_STRING NameW, EnvW, DriverW;
6694 asciitounicode(&NameW, pName);
6695 asciitounicode(&EnvW, pEnvironment);
6696 asciitounicode(&DriverW, pDriverName);
6698 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6700 RtlFreeUnicodeString(&DriverW);
6701 RtlFreeUnicodeString(&EnvW);
6702 RtlFreeUnicodeString(&NameW);
6707 /******************************************************************************
6708 * DeletePrinterDataExW (WINSPOOL.@)
6710 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6713 FIXME("%p %s %s\n", hPrinter,
6714 debugstr_w(pKeyName), debugstr_w(pValueName));
6715 return ERROR_INVALID_PARAMETER;
6718 /******************************************************************************
6719 * DeletePrinterDataExA (WINSPOOL.@)
6721 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6724 FIXME("%p %s %s\n", hPrinter,
6725 debugstr_a(pKeyName), debugstr_a(pValueName));
6726 return ERROR_INVALID_PARAMETER;
6729 /******************************************************************************
6730 * DeletePrintProcessorA (WINSPOOL.@)
6732 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6734 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6735 debugstr_a(pPrintProcessorName));
6739 /******************************************************************************
6740 * DeletePrintProcessorW (WINSPOOL.@)
6742 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6744 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6745 debugstr_w(pPrintProcessorName));
6749 /******************************************************************************
6750 * DeletePrintProvidorA (WINSPOOL.@)
6752 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6754 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6755 debugstr_a(pPrintProviderName));
6759 /******************************************************************************
6760 * DeletePrintProvidorW (WINSPOOL.@)
6762 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6764 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6765 debugstr_w(pPrintProviderName));
6769 /******************************************************************************
6770 * EnumFormsA (WINSPOOL.@)
6772 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6773 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6775 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6776 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6780 /******************************************************************************
6781 * EnumFormsW (WINSPOOL.@)
6783 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6784 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6786 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6787 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6791 /*****************************************************************************
6792 * EnumMonitorsA [WINSPOOL.@]
6794 * See EnumMonitorsW.
6797 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6798 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6801 LPBYTE bufferW = NULL;
6802 LPWSTR nameW = NULL;
6804 DWORD numentries = 0;
6807 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6808 cbBuf, pcbNeeded, pcReturned);
6810 /* convert servername to unicode */
6812 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6813 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6814 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6816 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6817 needed = cbBuf * sizeof(WCHAR);
6818 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6819 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6821 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6822 if (pcbNeeded) needed = *pcbNeeded;
6823 /* HeapReAlloc return NULL, when bufferW was NULL */
6824 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6825 HeapAlloc(GetProcessHeap(), 0, needed);
6827 /* Try again with the large Buffer */
6828 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6830 numentries = pcReturned ? *pcReturned : 0;
6833 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6834 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6837 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6838 DWORD entrysize = 0;
6841 LPMONITOR_INFO_2W mi2w;
6842 LPMONITOR_INFO_2A mi2a;
6844 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6845 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6847 /* First pass: calculate the size for all Entries */
6848 mi2w = (LPMONITOR_INFO_2W) bufferW;
6849 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6851 while (index < numentries) {
6853 needed += entrysize; /* MONITOR_INFO_?A */
6854 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6856 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6857 NULL, 0, NULL, NULL);
6859 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6860 NULL, 0, NULL, NULL);
6861 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6862 NULL, 0, NULL, NULL);
6864 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6865 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6866 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6869 /* check for errors and quit on failure */
6870 if (cbBuf < needed) {
6871 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6875 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6876 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6877 cbBuf -= len ; /* free Bytes in the user-Buffer */
6878 mi2w = (LPMONITOR_INFO_2W) bufferW;
6879 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6881 /* Second Pass: Fill the User Buffer (if we have one) */
6882 while ((index < numentries) && pMonitors) {
6884 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6886 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6887 ptr, cbBuf , NULL, NULL);
6891 mi2a->pEnvironment = ptr;
6892 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6893 ptr, cbBuf, NULL, NULL);
6897 mi2a->pDLLName = ptr;
6898 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6899 ptr, cbBuf, NULL, NULL);
6903 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6904 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6905 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6909 if (pcbNeeded) *pcbNeeded = needed;
6910 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6912 HeapFree(GetProcessHeap(), 0, nameW);
6913 HeapFree(GetProcessHeap(), 0, bufferW);
6915 TRACE("returning %d with %d (%d byte for %d entries)\n",
6916 (res), GetLastError(), needed, numentries);
6922 /*****************************************************************************
6923 * EnumMonitorsW [WINSPOOL.@]
6925 * Enumerate available Port-Monitors
6928 * pName [I] Servername or NULL (local Computer)
6929 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6930 * pMonitors [O] PTR to Buffer that receives the Result
6931 * cbBuf [I] Size of Buffer at pMonitors
6932 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6933 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6937 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6940 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6941 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6944 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6945 cbBuf, pcbNeeded, pcReturned);
6947 if ((backend == NULL) && !load_backend()) return FALSE;
6949 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6950 SetLastError(RPC_X_NULL_REF_POINTER);
6954 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6957 /******************************************************************************
6958 * SpoolerInit (WINSPOOL.@)
6960 * Initialize the Spooler
6967 * The function fails on windows, when the spooler service is not running
6970 BOOL WINAPI SpoolerInit(void)
6973 if ((backend == NULL) && !load_backend()) return FALSE;
6977 /******************************************************************************
6978 * XcvDataW (WINSPOOL.@)
6980 * Execute commands in the Printmonitor DLL
6983 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6984 * pszDataName [i] Name of the command to execute
6985 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6986 * cbInputData [i] Size in Bytes of Buffer at pInputData
6987 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6988 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6989 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6990 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6997 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6998 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7000 * Minimal List of commands, that a Printmonitor DLL should support:
7002 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7003 *| "AddPort" : Add a Port
7004 *| "DeletePort": Delete a Port
7006 * Many Printmonitors support additional commands. Examples for localspl.dll:
7007 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7008 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7011 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7012 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7013 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7015 opened_printer_t *printer;
7017 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7018 pInputData, cbInputData, pOutputData,
7019 cbOutputData, pcbOutputNeeded, pdwStatus);
7021 if ((backend == NULL) && !load_backend()) return FALSE;
7023 printer = get_opened_printer(hXcv);
7024 if (!printer || (!printer->backend_printer)) {
7025 SetLastError(ERROR_INVALID_HANDLE);
7029 if (!pcbOutputNeeded) {
7030 SetLastError(ERROR_INVALID_PARAMETER);
7034 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7035 SetLastError(RPC_X_NULL_REF_POINTER);
7039 *pcbOutputNeeded = 0;
7041 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7042 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7046 /*****************************************************************************
7047 * EnumPrinterDataA [WINSPOOL.@]
7050 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7051 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7052 DWORD cbData, LPDWORD pcbData )
7054 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7055 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7056 return ERROR_NO_MORE_ITEMS;
7059 /*****************************************************************************
7060 * EnumPrinterDataW [WINSPOOL.@]
7063 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7064 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7065 DWORD cbData, LPDWORD pcbData )
7067 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7068 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7069 return ERROR_NO_MORE_ITEMS;
7072 /*****************************************************************************
7073 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7076 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7077 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7078 LPDWORD pcbNeeded, LPDWORD pcReturned)
7080 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7081 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7082 pcbNeeded, pcReturned);
7086 /*****************************************************************************
7087 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7090 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7091 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7092 LPDWORD pcbNeeded, LPDWORD pcReturned)
7094 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7095 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7096 pcbNeeded, pcReturned);
7100 /*****************************************************************************
7101 * EnumPrintProcessorsA [WINSPOOL.@]
7103 * See EnumPrintProcessorsW.
7106 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7107 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7110 LPBYTE bufferW = NULL;
7111 LPWSTR nameW = NULL;
7114 DWORD numentries = 0;
7117 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7118 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7120 /* convert names to unicode */
7122 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7123 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7124 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7127 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7128 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7129 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7132 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7133 needed = cbBuf * sizeof(WCHAR);
7134 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7135 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7137 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7138 if (pcbNeeded) needed = *pcbNeeded;
7139 /* HeapReAlloc return NULL, when bufferW was NULL */
7140 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7141 HeapAlloc(GetProcessHeap(), 0, needed);
7143 /* Try again with the large Buffer */
7144 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7146 numentries = pcReturned ? *pcReturned : 0;
7150 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7153 PPRINTPROCESSOR_INFO_1W ppiw;
7154 PPRINTPROCESSOR_INFO_1A ppia;
7156 /* First pass: calculate the size for all Entries */
7157 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7158 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7160 while (index < numentries) {
7162 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7163 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7165 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7166 NULL, 0, NULL, NULL);
7168 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7169 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7172 /* check for errors and quit on failure */
7173 if (cbBuf < needed) {
7174 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7179 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7180 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7181 cbBuf -= len ; /* free Bytes in the user-Buffer */
7182 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7183 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7185 /* Second Pass: Fill the User Buffer (if we have one) */
7186 while ((index < numentries) && pPPInfo) {
7188 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7190 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7191 ptr, cbBuf , NULL, NULL);
7195 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7196 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7201 if (pcbNeeded) *pcbNeeded = needed;
7202 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7204 HeapFree(GetProcessHeap(), 0, nameW);
7205 HeapFree(GetProcessHeap(), 0, envW);
7206 HeapFree(GetProcessHeap(), 0, bufferW);
7208 TRACE("returning %d with %d (%d byte for %d entries)\n",
7209 (res), GetLastError(), needed, numentries);
7214 /*****************************************************************************
7215 * EnumPrintProcessorsW [WINSPOOL.@]
7217 * Enumerate available Print Processors
7220 * pName [I] Servername or NULL (local Computer)
7221 * pEnvironment [I] Printing-Environment or NULL (Default)
7222 * Level [I] Structure-Level (Only 1 is allowed)
7223 * pPPInfo [O] PTR to Buffer that receives the Result
7224 * cbBuf [I] Size of Buffer at pPPInfo
7225 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7226 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7230 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7233 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7234 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7237 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7238 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7240 if ((backend == NULL) && !load_backend()) return FALSE;
7242 if (!pcbNeeded || !pcReturned) {
7243 SetLastError(RPC_X_NULL_REF_POINTER);
7247 if (!pPPInfo && (cbBuf > 0)) {
7248 SetLastError(ERROR_INVALID_USER_BUFFER);
7252 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7253 cbBuf, pcbNeeded, pcReturned);
7256 /*****************************************************************************
7257 * ExtDeviceMode [WINSPOOL.@]
7260 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7261 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7264 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7265 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7266 debugstr_a(pProfile), fMode);
7270 /*****************************************************************************
7271 * FindClosePrinterChangeNotification [WINSPOOL.@]
7274 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7276 FIXME("Stub: %p\n", hChange);
7280 /*****************************************************************************
7281 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7284 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7285 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7287 FIXME("Stub: %p %x %x %p\n",
7288 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7289 return INVALID_HANDLE_VALUE;
7292 /*****************************************************************************
7293 * FindNextPrinterChangeNotification [WINSPOOL.@]
7296 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7297 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7299 FIXME("Stub: %p %p %p %p\n",
7300 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7304 /*****************************************************************************
7305 * FreePrinterNotifyInfo [WINSPOOL.@]
7308 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7310 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7314 /*****************************************************************************
7317 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7318 * ansi depending on the unicode parameter.
7320 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7330 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7333 memcpy(ptr, str, *size);
7340 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7343 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7350 /*****************************************************************************
7353 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7354 LPDWORD pcbNeeded, BOOL unicode)
7356 DWORD size, left = cbBuf;
7357 BOOL space = (cbBuf > 0);
7364 ji1->JobId = job->job_id;
7367 string_to_buf(job->document_title, ptr, left, &size, unicode);
7368 if(space && size <= left)
7370 ji1->pDocument = (LPWSTR)ptr;
7378 if (job->printer_name)
7380 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7381 if(space && size <= left)
7383 ji1->pPrinterName = (LPWSTR)ptr;
7395 /*****************************************************************************
7398 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7399 LPDWORD pcbNeeded, BOOL unicode)
7401 DWORD size, left = cbBuf;
7403 BOOL space = (cbBuf > 0);
7405 LPDEVMODEA dmA = NULL;
7412 ji2->JobId = job->job_id;
7415 string_to_buf(job->document_title, ptr, left, &size, unicode);
7416 if(space && size <= left)
7418 ji2->pDocument = (LPWSTR)ptr;
7426 if (job->printer_name)
7428 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7429 if(space && size <= left)
7431 ji2->pPrinterName = (LPWSTR)ptr;
7444 dmA = DEVMODEdupWtoA(job->devmode);
7445 devmode = (LPDEVMODEW) dmA;
7446 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7450 devmode = job->devmode;
7451 size = devmode->dmSize + devmode->dmDriverExtra;
7455 FIXME("Can't convert DEVMODE W to A\n");
7458 /* align DEVMODE to a DWORD boundary */
7459 shift = (4 - (*pcbNeeded & 3)) & 3;
7465 memcpy(ptr, devmode, size-shift);
7466 ji2->pDevMode = (LPDEVMODEW)ptr;
7467 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7480 /*****************************************************************************
7483 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7484 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7487 DWORD needed = 0, size;
7491 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7493 EnterCriticalSection(&printer_handles_cs);
7494 job = get_job(hPrinter, JobId);
7501 size = sizeof(JOB_INFO_1W);
7506 memset(pJob, 0, size);
7510 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7515 size = sizeof(JOB_INFO_2W);
7520 memset(pJob, 0, size);
7524 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7529 size = sizeof(JOB_INFO_3);
7533 memset(pJob, 0, size);
7542 SetLastError(ERROR_INVALID_LEVEL);
7546 *pcbNeeded = needed;
7548 LeaveCriticalSection(&printer_handles_cs);
7552 /*****************************************************************************
7553 * GetJobA [WINSPOOL.@]
7556 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7557 DWORD cbBuf, LPDWORD pcbNeeded)
7559 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7562 /*****************************************************************************
7563 * GetJobW [WINSPOOL.@]
7566 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7567 DWORD cbBuf, LPDWORD pcbNeeded)
7569 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7572 /*****************************************************************************
7575 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7578 char *unixname, *cmdA;
7580 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7586 if(!(unixname = wine_get_unix_file_name(filename)))
7589 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7590 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7591 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7593 TRACE("printing with: %s\n", cmdA);
7595 if((file_fd = open(unixname, O_RDONLY)) == -1)
7600 ERR("pipe() failed!\n");
7604 if ((pid = fork()) == 0)
7610 /* reset signals that we previously set to SIG_IGN */
7611 signal(SIGPIPE, SIG_DFL);
7613 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7618 ERR("fork() failed!\n");
7622 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7623 write(fds[1], buf, no_read);
7630 wret = waitpid(pid, &status, 0);
7631 } while (wret < 0 && errno == EINTR);
7634 ERR("waitpid() failed!\n");
7637 if (!WIFEXITED(status) || WEXITSTATUS(status))
7639 ERR("child process failed! %d\n", status);
7646 if(file_fd != -1) close(file_fd);
7647 if(fds[0] != -1) close(fds[0]);
7648 if(fds[1] != -1) close(fds[1]);
7650 HeapFree(GetProcessHeap(), 0, cmdA);
7651 HeapFree(GetProcessHeap(), 0, unixname);
7658 /*****************************************************************************
7661 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7664 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7667 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7668 sprintfW(cmd, fmtW, printer_name);
7670 r = schedule_pipe(cmd, filename);
7672 HeapFree(GetProcessHeap(), 0, cmd);
7676 #ifdef SONAME_LIBCUPS
7677 /*****************************************************************************
7678 * get_cups_jobs_ticket_options
7680 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7681 * The CUPS scheduler only looks for these in Print-File requests, and since
7682 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7685 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7687 FILE *fp = fopen( file, "r" );
7688 char buf[257]; /* DSC max of 256 + '\0' */
7689 const char *ps_adobe = "%!PS-Adobe-";
7690 const char *cups_job = "%cupsJobTicket:";
7692 if (!fp) return num_options;
7693 if (!fgets( buf, sizeof(buf), fp )) goto end;
7694 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7695 while (fgets( buf, sizeof(buf), fp ))
7697 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7698 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7707 /*****************************************************************************
7710 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7712 #ifdef SONAME_LIBCUPS
7715 char *unixname, *queue, *unix_doc_title;
7718 int num_options = 0, i;
7719 cups_option_t *options = NULL;
7721 if(!(unixname = wine_get_unix_file_name(filename)))
7724 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7725 queue = HeapAlloc(GetProcessHeap(), 0, len);
7726 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7728 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7729 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7730 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7732 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7734 TRACE( "printing via cups with options:\n" );
7735 for (i = 0; i < num_options; i++)
7736 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7738 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7740 pcupsFreeOptions( num_options, options );
7742 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7743 HeapFree(GetProcessHeap(), 0, queue);
7744 HeapFree(GetProcessHeap(), 0, unixname);
7750 return schedule_lpr(printer_name, filename);
7754 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7761 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7765 if(HIWORD(wparam) == BN_CLICKED)
7767 if(LOWORD(wparam) == IDOK)
7770 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7773 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7774 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7776 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7778 WCHAR caption[200], message[200];
7781 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7782 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7783 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7784 if(mb_ret == IDCANCEL)
7786 HeapFree(GetProcessHeap(), 0, filename);
7790 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7791 if(hf == INVALID_HANDLE_VALUE)
7793 WCHAR caption[200], message[200];
7795 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7796 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7797 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7798 HeapFree(GetProcessHeap(), 0, filename);
7802 DeleteFileW(filename);
7803 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7805 EndDialog(hwnd, IDOK);
7808 if(LOWORD(wparam) == IDCANCEL)
7810 EndDialog(hwnd, IDCANCEL);
7819 /*****************************************************************************
7822 static BOOL get_filename(LPWSTR *filename)
7824 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7825 file_dlg_proc, (LPARAM)filename) == IDOK;
7828 /*****************************************************************************
7831 static BOOL schedule_file(LPCWSTR filename)
7833 LPWSTR output = NULL;
7835 if(get_filename(&output))
7838 TRACE("copy to %s\n", debugstr_w(output));
7839 r = CopyFileW(filename, output, FALSE);
7840 HeapFree(GetProcessHeap(), 0, output);
7846 /*****************************************************************************
7849 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7851 int in_fd, out_fd, no_read;
7854 char *unixname, *outputA;
7857 if(!(unixname = wine_get_unix_file_name(filename)))
7860 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7861 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7862 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7864 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7865 in_fd = open(unixname, O_RDONLY);
7866 if(out_fd == -1 || in_fd == -1)
7869 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7870 write(out_fd, buf, no_read);
7874 if(in_fd != -1) close(in_fd);
7875 if(out_fd != -1) close(out_fd);
7876 HeapFree(GetProcessHeap(), 0, outputA);
7877 HeapFree(GetProcessHeap(), 0, unixname);
7881 /*****************************************************************************
7882 * ScheduleJob [WINSPOOL.@]
7885 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7887 opened_printer_t *printer;
7889 struct list *cursor, *cursor2;
7891 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7892 EnterCriticalSection(&printer_handles_cs);
7893 printer = get_opened_printer(hPrinter);
7897 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7899 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7902 if(job->job_id != dwJobID) continue;
7904 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7905 if(hf != INVALID_HANDLE_VALUE)
7907 PRINTER_INFO_5W *pi5 = NULL;
7908 LPWSTR portname = job->portname;
7912 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7913 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7917 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7918 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7919 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7920 portname = pi5->pPortName;
7922 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7923 debugstr_w(portname));
7927 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7928 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7930 DWORD type, count = sizeof(output);
7931 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7934 if(output[0] == '|')
7936 ret = schedule_pipe(output + 1, job->filename);
7940 ret = schedule_unixfile(output, job->filename);
7942 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7944 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7946 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7948 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7950 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7952 ret = schedule_file(job->filename);
7956 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7958 HeapFree(GetProcessHeap(), 0, pi5);
7960 DeleteFileW(job->filename);
7962 list_remove(cursor);
7963 HeapFree(GetProcessHeap(), 0, job->document_title);
7964 HeapFree(GetProcessHeap(), 0, job->printer_name);
7965 HeapFree(GetProcessHeap(), 0, job->portname);
7966 HeapFree(GetProcessHeap(), 0, job->filename);
7967 HeapFree(GetProcessHeap(), 0, job->devmode);
7968 HeapFree(GetProcessHeap(), 0, job);
7972 LeaveCriticalSection(&printer_handles_cs);
7976 /*****************************************************************************
7977 * StartDocDlgA [WINSPOOL.@]
7979 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7981 UNICODE_STRING usBuffer;
7984 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7987 docW.cbSize = sizeof(docW);
7988 if (doc->lpszDocName)
7990 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7991 if (!(docW.lpszDocName = docnameW)) return NULL;
7993 if (doc->lpszOutput)
7995 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7996 if (!(docW.lpszOutput = outputW)) return NULL;
7998 if (doc->lpszDatatype)
8000 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8001 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8003 docW.fwType = doc->fwType;
8005 retW = StartDocDlgW(hPrinter, &docW);
8009 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8010 ret = HeapAlloc(GetProcessHeap(), 0, len);
8011 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8012 HeapFree(GetProcessHeap(), 0, retW);
8015 HeapFree(GetProcessHeap(), 0, datatypeW);
8016 HeapFree(GetProcessHeap(), 0, outputW);
8017 HeapFree(GetProcessHeap(), 0, docnameW);
8022 /*****************************************************************************
8023 * StartDocDlgW [WINSPOOL.@]
8025 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8026 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8027 * port is "FILE:". Also returns the full path if passed a relative path.
8029 * The caller should free the returned string from the process heap.
8031 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8036 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8038 PRINTER_INFO_5W *pi5;
8039 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8040 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8042 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8043 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8044 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8046 HeapFree(GetProcessHeap(), 0, pi5);
8049 HeapFree(GetProcessHeap(), 0, pi5);
8052 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8056 if (get_filename(&name))
8058 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8060 HeapFree(GetProcessHeap(), 0, name);
8063 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8064 GetFullPathNameW(name, len, ret, NULL);
8065 HeapFree(GetProcessHeap(), 0, name);
8070 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8073 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8074 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8076 attr = GetFileAttributesW(ret);
8077 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8079 HeapFree(GetProcessHeap(), 0, ret);