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};
188 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
189 static const WCHAR backslashW[] = {'\\',0};
190 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
191 'i','o','n',' ','F','i','l','e',0};
192 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
193 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
194 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
195 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
196 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
197 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
198 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
199 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
200 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
201 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
202 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
203 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
204 static const WCHAR NameW[] = {'N','a','m','e',0};
205 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
206 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
207 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
208 static const WCHAR PortW[] = {'P','o','r','t',0};
209 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
210 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
211 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
212 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
213 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
214 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
215 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
216 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
217 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
218 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
219 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
220 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
221 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
222 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
223 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
224 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
225 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
226 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
227 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
228 static WCHAR rawW[] = {'R','A','W',0};
229 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
230 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
231 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
232 static const WCHAR commaW[] = {',',0};
233 static WCHAR emptyStringW[] = {0};
235 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
237 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
238 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
239 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
241 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
242 'D','o','c','u','m','e','n','t',0};
244 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
245 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
246 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
247 0, sizeof(DRIVER_INFO_8W)};
250 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
251 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
252 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
253 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
254 sizeof(PRINTER_INFO_9W)};
256 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
257 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
258 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
260 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
262 /******************************************************************
263 * validate the user-supplied printing-environment [internal]
266 * env [I] PTR to Environment-String or NULL
270 * Success: PTR to printenv_t
273 * An empty string is handled the same way as NULL.
274 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
278 static const printenv_t * validate_envW(LPCWSTR env)
280 const printenv_t *result = NULL;
283 TRACE("testing %s\n", debugstr_w(env));
286 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
288 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
290 result = all_printenv[i];
295 if (result == NULL) {
296 FIXME("unsupported Environment: %s\n", debugstr_w(env));
297 SetLastError(ERROR_INVALID_ENVIRONMENT);
299 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
303 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
305 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
311 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
312 if passed a NULL string. This returns NULLs to the result.
314 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
318 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
319 return usBufferPtr->Buffer;
321 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
325 static LPWSTR strdupW(LPCWSTR p)
331 len = (strlenW(p) + 1) * sizeof(WCHAR);
332 ret = HeapAlloc(GetProcessHeap(), 0, len);
337 static LPSTR strdupWtoA( LPCWSTR str )
342 if (!str) return NULL;
343 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
344 ret = HeapAlloc( GetProcessHeap(), 0, len );
345 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
349 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
353 if (!dm) return NULL;
354 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
355 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
359 /***********************************************************
361 * Creates an ansi copy of supplied devmode
363 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
368 if (!dmW) return NULL;
369 size = dmW->dmSize - CCHDEVICENAME -
370 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
372 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
373 if (!dmA) return NULL;
375 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
376 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
378 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
380 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
381 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
385 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
386 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
387 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
388 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
390 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
394 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
399 /******************************************************************
400 * verify, that the filename is a local file
403 static inline BOOL is_local_file(LPWSTR name)
405 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
408 /* ################################ */
410 static int multi_sz_lenA(const char *str)
412 const char *ptr = str;
416 ptr += lstrlenA(ptr) + 1;
419 return ptr - str + 1;
423 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
426 /* If forcing, or no profile string entry for device yet, set the entry
428 * The always change entry if not WINEPS yet is discussable.
431 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
433 !strstr(qbuf,"WINEPS.DRV")
435 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
438 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
439 WriteProfileStringA("windows","device",buf);
440 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
441 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
444 HeapFree(GetProcessHeap(),0,buf);
448 static BOOL add_printer_driver(WCHAR *name)
452 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
455 di3.pEnvironment = envname_x86W;
456 di3.pDriverPath = driver_nt;
457 di3.pDataFile = generic_ppdW;
458 di3.pConfigFile = driver_nt;
459 di3.pDefaultDataType = rawW;
461 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
462 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
465 di3.pEnvironment = envname_win40W;
466 di3.pDriverPath = driver_9x;
467 di3.pConfigFile = driver_9x;
468 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
469 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
474 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
478 #ifdef SONAME_LIBCUPS
480 static void *cupshandle;
483 DO_FUNC(cupsFreeDests); \
484 DO_FUNC(cupsFreeOptions); \
485 DO_FUNC(cupsGetDests); \
486 DO_FUNC(cupsGetPPD); \
487 DO_FUNC(cupsParseOptions); \
488 DO_FUNC(cupsPrintFile);
490 #define DO_FUNC(f) static typeof(f) *p##f
494 static BOOL CUPS_LoadPrinters(void)
497 BOOL hadprinter = FALSE, haddefault = FALSE;
501 HKEY hkeyPrinter, hkeyPrinters;
503 WCHAR nameW[MAX_PATH];
504 HANDLE added_printer;
506 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
508 TRACE("%s\n", loaderror);
511 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
513 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
517 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
519 ERR("Can't create Printers key\n");
523 nrofdests = pcupsGetDests(&dests);
524 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
525 for (i=0;i<nrofdests;i++) {
526 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
528 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
529 lstrcpyW(port, CUPS_Port);
530 lstrcatW(port, nameW);
532 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
533 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
534 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
536 TRACE("Printer already exists\n");
537 /* overwrite old LPR:* port */
538 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
539 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
540 RegCloseKey(hkeyPrinter);
542 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
543 ' ','u','s','i','n','g',' ','C','U','P','S',0};
545 add_printer_driver(nameW);
547 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
548 pi2.pPrinterName = nameW;
549 pi2.pDatatype = rawW;
550 pi2.pPrintProcessor = WinPrintW;
551 pi2.pDriverName = nameW;
552 pi2.pComment = comment_cups;
553 pi2.pLocation = emptyStringW;
554 pi2.pPortName = port;
555 pi2.pParameters = emptyStringW;
556 pi2.pShareName = emptyStringW;
557 pi2.pSepFile = emptyStringW;
559 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
560 if (added_printer) ClosePrinter( added_printer );
561 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
562 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
564 HeapFree(GetProcessHeap(),0,port);
567 if (dests[i].is_default) {
568 SetDefaultPrinterW(nameW);
572 if (hadprinter && !haddefault) {
573 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
574 SetDefaultPrinterW(nameW);
576 pcupsFreeDests(nrofdests, dests);
577 RegCloseKey(hkeyPrinters);
582 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
584 PRINTER_INFO_2A pinfo2a;
587 char *e,*s,*name,*prettyname,*devname;
588 BOOL ret = FALSE, set_default = FALSE;
589 char *port = NULL, *env_default;
590 HKEY hkeyPrinter, hkeyPrinters;
591 WCHAR devnameW[MAX_PATH];
592 HANDLE added_printer;
594 while (isspace(*pent)) pent++;
595 r = strchr(pent,':');
599 name_len = strlen(pent);
600 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
601 memcpy(name, pent, name_len);
602 name[name_len] = '\0';
608 TRACE("name=%s entry=%s\n",name, pent);
610 if(ispunct(*name)) { /* a tc entry, not a real printer */
611 TRACE("skipping tc entry\n");
615 if(strstr(pent,":server")) { /* server only version so skip */
616 TRACE("skipping server entry\n");
620 /* Determine whether this is a postscript printer. */
623 env_default = getenv("PRINTER");
625 /* Get longest name, usually the one at the right for later display. */
626 while((s=strchr(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;
632 for(prettyname = s+1; isspace(*prettyname); prettyname++)
635 e = prettyname + strlen(prettyname);
636 while(isspace(*--e)) *e = '\0';
637 TRACE("\t%s\n", debugstr_a(prettyname));
638 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
640 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
641 * if it is too long, we use it as comment below. */
642 devname = prettyname;
643 if (strlen(devname)>=CCHDEVICENAME-1)
645 if (strlen(devname)>=CCHDEVICENAME-1) {
650 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
651 sprintf(port,"LPR:%s",name);
653 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
655 ERR("Can't create Printers key\n");
660 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
662 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
663 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
665 TRACE("Printer already exists\n");
666 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
667 RegCloseKey(hkeyPrinter);
669 static CHAR data_type[] = "RAW",
670 print_proc[] = "WinPrint",
671 comment[] = "WINEPS Printer using LPR",
672 params[] = "<parameters?>",
673 share_name[] = "<share name?>",
674 sep_file[] = "<sep file?>";
676 add_printer_driver(devnameW);
678 memset(&pinfo2a,0,sizeof(pinfo2a));
679 pinfo2a.pPrinterName = devname;
680 pinfo2a.pDatatype = data_type;
681 pinfo2a.pPrintProcessor = print_proc;
682 pinfo2a.pDriverName = devname;
683 pinfo2a.pComment = comment;
684 pinfo2a.pLocation = prettyname;
685 pinfo2a.pPortName = port;
686 pinfo2a.pParameters = params;
687 pinfo2a.pShareName = share_name;
688 pinfo2a.pSepFile = sep_file;
690 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
691 if (added_printer) ClosePrinter( added_printer );
692 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
693 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
695 RegCloseKey(hkeyPrinters);
697 if (isfirst || set_default)
698 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
701 HeapFree(GetProcessHeap(), 0, port);
702 HeapFree(GetProcessHeap(), 0, name);
707 PRINTCAP_LoadPrinters(void) {
708 BOOL hadprinter = FALSE;
712 BOOL had_bash = FALSE;
714 f = fopen("/etc/printcap","r");
718 while(fgets(buf,sizeof(buf),f)) {
721 end=strchr(buf,'\n');
725 while(isspace(*start)) start++;
726 if(*start == '#' || *start == '\0')
729 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
730 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
731 HeapFree(GetProcessHeap(),0,pent);
735 if (end && *--end == '\\') {
742 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
745 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
751 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
752 HeapFree(GetProcessHeap(),0,pent);
758 static inline DWORD set_reg_DWORD(HKEY hkey, const WCHAR *keyname, const DWORD value)
760 return RegSetValueExW(hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
763 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
766 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
767 (lstrlenW(value) + 1) * sizeof(WCHAR));
769 return ERROR_FILE_NOT_FOUND;
772 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
774 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
775 DWORD ret = ERROR_FILE_NOT_FOUND;
777 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
778 and we support these drivers. NT writes DEVMODEW so somehow
779 we'll need to distinguish between these when we support NT
784 ret = RegSetValueExW( key, name, 0, REG_BINARY,
785 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
786 HeapFree( GetProcessHeap(), 0, dmA );
792 /******************************************************************
793 * get_servername_from_name (internal)
795 * for an external server, a copy of the serverpart from the full name is returned
798 static LPWSTR get_servername_from_name(LPCWSTR name)
802 WCHAR buffer[MAX_PATH];
805 if (name == NULL) return NULL;
806 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
808 server = strdupW(&name[2]); /* skip over both backslash */
809 if (server == NULL) return NULL;
811 /* strip '\' and the printername */
812 ptr = strchrW(server, '\\');
813 if (ptr) ptr[0] = '\0';
815 TRACE("found %s\n", debugstr_w(server));
817 len = sizeof(buffer)/sizeof(buffer[0]);
818 if (GetComputerNameW(buffer, &len)) {
819 if (lstrcmpW(buffer, server) == 0) {
820 /* The requested Servername is our computername */
821 HeapFree(GetProcessHeap(), 0, server);
828 /******************************************************************
829 * get_basename_from_name (internal)
831 * skip over the serverpart from the full name
834 static LPCWSTR get_basename_from_name(LPCWSTR name)
836 if (name == NULL) return NULL;
837 if ((name[0] == '\\') && (name[1] == '\\')) {
838 /* skip over the servername and search for the following '\' */
839 name = strchrW(&name[2], '\\');
840 if ((name) && (name[1])) {
841 /* found a separator ('\') followed by a name:
842 skip over the separator and return the rest */
847 /* no basename present (we found only a servername) */
854 static void free_printer_entry( opened_printer_t *printer )
856 /* the queue is shared, so don't free that here */
857 HeapFree( GetProcessHeap(), 0, printer->printername );
858 HeapFree( GetProcessHeap(), 0, printer->name );
859 HeapFree( GetProcessHeap(), 0, printer->devmode );
860 HeapFree( GetProcessHeap(), 0, printer );
863 /******************************************************************
864 * get_opened_printer_entry
865 * Get the first place empty in the opened printer table
868 * - pDefault is ignored
870 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
872 UINT_PTR handle = nb_printer_handles, i;
873 jobqueue_t *queue = NULL;
874 opened_printer_t *printer = NULL;
878 if ((backend == NULL) && !load_backend()) return NULL;
880 servername = get_servername_from_name(name);
882 FIXME("server %s not supported\n", debugstr_w(servername));
883 HeapFree(GetProcessHeap(), 0, servername);
884 SetLastError(ERROR_INVALID_PRINTER_NAME);
888 printername = get_basename_from_name(name);
889 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
891 /* an empty printername is invalid */
892 if (printername && (!printername[0])) {
893 SetLastError(ERROR_INVALID_PARAMETER);
897 EnterCriticalSection(&printer_handles_cs);
899 for (i = 0; i < nb_printer_handles; i++)
901 if (!printer_handles[i])
903 if(handle == nb_printer_handles)
908 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
909 queue = printer_handles[i]->queue;
913 if (handle >= nb_printer_handles)
915 opened_printer_t **new_array;
917 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
918 (nb_printer_handles + 16) * sizeof(*new_array) );
920 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
921 (nb_printer_handles + 16) * sizeof(*new_array) );
928 printer_handles = new_array;
929 nb_printer_handles += 16;
932 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
938 /* get a printer handle from the backend */
939 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
944 /* clone the base name. This is NULL for the printserver */
945 printer->printername = strdupW(printername);
947 /* clone the full name */
948 printer->name = strdupW(name);
949 if (name && (!printer->name)) {
954 if (pDefault && pDefault->pDevMode)
955 printer->devmode = dup_devmode( pDefault->pDevMode );
958 printer->queue = queue;
961 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
962 if (!printer->queue) {
966 list_init(&printer->queue->jobs);
967 printer->queue->ref = 0;
969 InterlockedIncrement(&printer->queue->ref);
971 printer_handles[handle] = printer;
974 LeaveCriticalSection(&printer_handles_cs);
975 if (!handle && printer) {
976 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
977 free_printer_entry( printer );
980 return (HANDLE)handle;
983 /******************************************************************
985 * Get the pointer to the opened printer referred by the handle
987 static opened_printer_t *get_opened_printer(HANDLE hprn)
989 UINT_PTR idx = (UINT_PTR)hprn;
990 opened_printer_t *ret = NULL;
992 EnterCriticalSection(&printer_handles_cs);
994 if ((idx > 0) && (idx <= nb_printer_handles)) {
995 ret = printer_handles[idx - 1];
997 LeaveCriticalSection(&printer_handles_cs);
1001 /******************************************************************
1002 * get_opened_printer_name
1003 * Get the pointer to the opened printer name referred by the handle
1005 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1007 opened_printer_t *printer = get_opened_printer(hprn);
1008 if(!printer) return NULL;
1009 return printer->name;
1012 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1018 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1019 if (err) return err;
1021 err = RegOpenKeyW( printers, name, key );
1022 if (err) err = ERROR_INVALID_PRINTER_NAME;
1023 RegCloseKey( printers );
1027 /******************************************************************
1028 * WINSPOOL_GetOpenedPrinterRegKey
1031 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1033 LPCWSTR name = get_opened_printer_name(hPrinter);
1035 if(!name) return ERROR_INVALID_HANDLE;
1036 return open_printer_reg_key( name, phkey );
1039 static void old_printer_check( BOOL delete_phase )
1041 PRINTER_INFO_5W* pi;
1042 DWORD needed, type, num, delete, i, size;
1043 const DWORD one = 1;
1047 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1048 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1050 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1051 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1052 for (i = 0; i < num; i++)
1054 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1055 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1058 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1062 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1068 size = sizeof( delete );
1069 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1073 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1074 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1076 DeletePrinter( hprn );
1077 ClosePrinter( hprn );
1079 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1083 HeapFree(GetProcessHeap(), 0, pi);
1086 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1087 'M','U','T','E','X','_','_','\0'};
1089 void WINSPOOL_LoadSystemPrinters(void)
1091 HKEY hkey, hkeyPrinters;
1092 DWORD needed, num, i;
1093 WCHAR PrinterName[256];
1097 /* FIXME: The init code should be moved to spoolsv.exe */
1098 mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1101 ERR( "Failed to create mutex\n" );
1104 if (GetLastError() == ERROR_ALREADY_EXISTS)
1106 WaitForSingleObject( mutex, INFINITE );
1107 ReleaseMutex( mutex );
1108 TRACE( "Init already done\n" );
1112 /* This ensures that all printer entries have a valid Name value. If causes
1113 problems later if they don't. If one is found to be missed we create one
1114 and set it equal to the name of the key */
1115 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1116 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1117 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1118 for(i = 0; i < num; i++) {
1119 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1120 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1121 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1122 set_reg_szW(hkey, NameW, PrinterName);
1129 RegCloseKey(hkeyPrinters);
1132 old_printer_check( FALSE );
1134 #ifdef SONAME_LIBCUPS
1135 done = CUPS_LoadPrinters();
1138 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1139 PRINTCAP_LoadPrinters();
1141 old_printer_check( TRUE );
1143 ReleaseMutex( mutex );
1147 /******************************************************************
1150 * Get the pointer to the specified job.
1151 * Should hold the printer_handles_cs before calling.
1153 static job_t *get_job(HANDLE hprn, DWORD JobId)
1155 opened_printer_t *printer = get_opened_printer(hprn);
1158 if(!printer) return NULL;
1159 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1161 if(job->job_id == JobId)
1167 /***********************************************************
1170 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1173 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1176 Formname = (dmA->dmSize > off_formname);
1177 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1178 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1179 dmW->dmDeviceName, CCHDEVICENAME);
1181 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1182 dmA->dmSize - CCHDEVICENAME);
1184 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1185 off_formname - CCHDEVICENAME);
1186 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1187 dmW->dmFormName, CCHFORMNAME);
1188 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1189 (off_formname + CCHFORMNAME));
1192 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1193 dmA->dmDriverExtra);
1197 /******************************************************************
1198 * convert_printerinfo_W_to_A [internal]
1201 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1202 DWORD level, DWORD outlen, DWORD numentries)
1208 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1210 len = pi_sizeof[level] * numentries;
1211 ptr = (LPSTR) out + len;
1214 /* copy the numbers of all PRINTER_INFO_* first */
1215 memcpy(out, pPrintersW, len);
1217 while (id < numentries) {
1221 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1222 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1224 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1225 if (piW->pDescription) {
1226 piA->pDescription = ptr;
1227 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1228 ptr, outlen, NULL, NULL);
1234 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1235 ptr, outlen, NULL, NULL);
1239 if (piW->pComment) {
1240 piA->pComment = ptr;
1241 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1242 ptr, outlen, NULL, NULL);
1251 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1252 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1255 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1256 if (piW->pServerName) {
1257 piA->pServerName = ptr;
1258 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1259 ptr, outlen, NULL, NULL);
1263 if (piW->pPrinterName) {
1264 piA->pPrinterName = ptr;
1265 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1266 ptr, outlen, NULL, NULL);
1270 if (piW->pShareName) {
1271 piA->pShareName = ptr;
1272 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1273 ptr, outlen, NULL, NULL);
1277 if (piW->pPortName) {
1278 piA->pPortName = ptr;
1279 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1280 ptr, outlen, NULL, NULL);
1284 if (piW->pDriverName) {
1285 piA->pDriverName = ptr;
1286 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1287 ptr, outlen, NULL, NULL);
1291 if (piW->pComment) {
1292 piA->pComment = ptr;
1293 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1294 ptr, outlen, NULL, NULL);
1298 if (piW->pLocation) {
1299 piA->pLocation = ptr;
1300 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1301 ptr, outlen, NULL, NULL);
1306 dmA = DEVMODEdupWtoA(piW->pDevMode);
1308 /* align DEVMODEA to a DWORD boundary */
1309 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1313 piA->pDevMode = (LPDEVMODEA) ptr;
1314 len = dmA->dmSize + dmA->dmDriverExtra;
1315 memcpy(ptr, dmA, len);
1316 HeapFree(GetProcessHeap(), 0, dmA);
1322 if (piW->pSepFile) {
1323 piA->pSepFile = ptr;
1324 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1325 ptr, outlen, NULL, NULL);
1329 if (piW->pPrintProcessor) {
1330 piA->pPrintProcessor = ptr;
1331 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1332 ptr, outlen, NULL, NULL);
1336 if (piW->pDatatype) {
1337 piA->pDatatype = ptr;
1338 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1339 ptr, outlen, NULL, NULL);
1343 if (piW->pParameters) {
1344 piA->pParameters = ptr;
1345 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1346 ptr, outlen, NULL, NULL);
1350 if (piW->pSecurityDescriptor) {
1351 piA->pSecurityDescriptor = NULL;
1352 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1359 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1360 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1362 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1364 if (piW->pPrinterName) {
1365 piA->pPrinterName = ptr;
1366 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1367 ptr, outlen, NULL, NULL);
1371 if (piW->pServerName) {
1372 piA->pServerName = ptr;
1373 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1374 ptr, outlen, NULL, NULL);
1383 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1384 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1386 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1388 if (piW->pPrinterName) {
1389 piA->pPrinterName = ptr;
1390 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1391 ptr, outlen, NULL, NULL);
1395 if (piW->pPortName) {
1396 piA->pPortName = ptr;
1397 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1398 ptr, outlen, NULL, NULL);
1405 case 6: /* 6A and 6W are the same structure */
1410 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1411 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1413 TRACE("(%u) #%u\n", level, id);
1414 if (piW->pszObjectGUID) {
1415 piA->pszObjectGUID = ptr;
1416 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1417 ptr, outlen, NULL, NULL);
1427 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1428 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1431 TRACE("(%u) #%u\n", level, id);
1432 dmA = DEVMODEdupWtoA(piW->pDevMode);
1434 /* align DEVMODEA to a DWORD boundary */
1435 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1439 piA->pDevMode = (LPDEVMODEA) ptr;
1440 len = dmA->dmSize + dmA->dmDriverExtra;
1441 memcpy(ptr, dmA, len);
1442 HeapFree(GetProcessHeap(), 0, dmA);
1452 FIXME("for level %u\n", level);
1454 pPrintersW += pi_sizeof[level];
1455 out += pi_sizeof[level];
1460 /******************************************************************
1461 * convert_driverinfo_W_to_A [internal]
1464 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1465 DWORD level, DWORD outlen, DWORD numentries)
1471 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1473 len = di_sizeof[level] * numentries;
1474 ptr = (LPSTR) out + len;
1477 /* copy the numbers of all PRINTER_INFO_* first */
1478 memcpy(out, pDriversW, len);
1480 #define COPY_STRING(fld) \
1483 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1484 ptr += len; outlen -= len;\
1486 #define COPY_MULTIZ_STRING(fld) \
1487 { LPWSTR p = diW->fld; if (p){ \
1490 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1491 ptr += len; outlen -= len; p += len;\
1493 while(len > 1 && outlen > 0); \
1496 while (id < numentries)
1502 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1503 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1505 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1512 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1513 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1515 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1518 COPY_STRING(pEnvironment);
1519 COPY_STRING(pDriverPath);
1520 COPY_STRING(pDataFile);
1521 COPY_STRING(pConfigFile);
1526 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1527 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1529 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1532 COPY_STRING(pEnvironment);
1533 COPY_STRING(pDriverPath);
1534 COPY_STRING(pDataFile);
1535 COPY_STRING(pConfigFile);
1536 COPY_STRING(pHelpFile);
1537 COPY_MULTIZ_STRING(pDependentFiles);
1538 COPY_STRING(pMonitorName);
1539 COPY_STRING(pDefaultDataType);
1544 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1545 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1547 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1550 COPY_STRING(pEnvironment);
1551 COPY_STRING(pDriverPath);
1552 COPY_STRING(pDataFile);
1553 COPY_STRING(pConfigFile);
1554 COPY_STRING(pHelpFile);
1555 COPY_MULTIZ_STRING(pDependentFiles);
1556 COPY_STRING(pMonitorName);
1557 COPY_STRING(pDefaultDataType);
1558 COPY_MULTIZ_STRING(pszzPreviousNames);
1563 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1564 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1566 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1569 COPY_STRING(pEnvironment);
1570 COPY_STRING(pDriverPath);
1571 COPY_STRING(pDataFile);
1572 COPY_STRING(pConfigFile);
1577 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1578 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1580 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1583 COPY_STRING(pEnvironment);
1584 COPY_STRING(pDriverPath);
1585 COPY_STRING(pDataFile);
1586 COPY_STRING(pConfigFile);
1587 COPY_STRING(pHelpFile);
1588 COPY_MULTIZ_STRING(pDependentFiles);
1589 COPY_STRING(pMonitorName);
1590 COPY_STRING(pDefaultDataType);
1591 COPY_MULTIZ_STRING(pszzPreviousNames);
1592 COPY_STRING(pszMfgName);
1593 COPY_STRING(pszOEMUrl);
1594 COPY_STRING(pszHardwareID);
1595 COPY_STRING(pszProvider);
1600 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1601 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1603 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1606 COPY_STRING(pEnvironment);
1607 COPY_STRING(pDriverPath);
1608 COPY_STRING(pDataFile);
1609 COPY_STRING(pConfigFile);
1610 COPY_STRING(pHelpFile);
1611 COPY_MULTIZ_STRING(pDependentFiles);
1612 COPY_STRING(pMonitorName);
1613 COPY_STRING(pDefaultDataType);
1614 COPY_MULTIZ_STRING(pszzPreviousNames);
1615 COPY_STRING(pszMfgName);
1616 COPY_STRING(pszOEMUrl);
1617 COPY_STRING(pszHardwareID);
1618 COPY_STRING(pszProvider);
1619 COPY_STRING(pszPrintProcessor);
1620 COPY_STRING(pszVendorSetup);
1621 COPY_MULTIZ_STRING(pszzColorProfiles);
1622 COPY_STRING(pszInfPath);
1623 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1629 FIXME("for level %u\n", level);
1632 pDriversW += di_sizeof[level];
1633 out += di_sizeof[level];
1638 #undef COPY_MULTIZ_STRING
1642 /***********************************************************
1645 static void *printer_info_AtoW( const void *data, DWORD level )
1648 UNICODE_STRING usBuffer;
1650 if (!data) return NULL;
1652 if (level < 1 || level > 9) return NULL;
1654 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1655 if (!ret) return NULL;
1657 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1663 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1664 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1666 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1667 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1668 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1669 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1670 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1671 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1672 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1673 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1674 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1675 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1676 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1677 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1684 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1685 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1687 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1692 FIXME( "Unhandled level %d\n", level );
1693 HeapFree( GetProcessHeap(), 0, ret );
1700 /***********************************************************
1703 static void free_printer_info( void *data, DWORD level )
1711 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1713 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1714 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1715 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1716 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1717 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1718 HeapFree( GetProcessHeap(), 0, piW->pComment );
1719 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1720 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1721 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1722 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1723 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1724 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1731 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1733 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1738 FIXME( "Unhandled level %d\n", level );
1741 HeapFree( GetProcessHeap(), 0, data );
1745 /******************************************************************
1746 * DeviceCapabilities [WINSPOOL.@]
1747 * DeviceCapabilitiesA [WINSPOOL.@]
1750 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1751 LPSTR pOutput, LPDEVMODEA lpdm)
1755 if (!GDI_CallDeviceCapabilities16)
1757 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1759 if (!GDI_CallDeviceCapabilities16) return -1;
1761 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1763 /* If DC_PAPERSIZE map POINT16s to POINTs */
1764 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1765 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1766 POINT *pt = (POINT *)pOutput;
1768 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1769 for(i = 0; i < ret; i++, pt++)
1774 HeapFree( GetProcessHeap(), 0, tmp );
1780 /*****************************************************************************
1781 * DeviceCapabilitiesW [WINSPOOL.@]
1783 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1786 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1787 WORD fwCapability, LPWSTR pOutput,
1788 const DEVMODEW *pDevMode)
1790 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1791 LPSTR pDeviceA = strdupWtoA(pDevice);
1792 LPSTR pPortA = strdupWtoA(pPort);
1795 if(pOutput && (fwCapability == DC_BINNAMES ||
1796 fwCapability == DC_FILEDEPENDENCIES ||
1797 fwCapability == DC_PAPERNAMES)) {
1798 /* These need A -> W translation */
1801 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1805 switch(fwCapability) {
1810 case DC_FILEDEPENDENCIES:
1814 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1815 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1817 for(i = 0; i < ret; i++)
1818 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1819 pOutput + (i * size), size);
1820 HeapFree(GetProcessHeap(), 0, pOutputA);
1822 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1823 (LPSTR)pOutput, dmA);
1825 HeapFree(GetProcessHeap(),0,pPortA);
1826 HeapFree(GetProcessHeap(),0,pDeviceA);
1827 HeapFree(GetProcessHeap(),0,dmA);
1831 /******************************************************************
1832 * DocumentPropertiesA [WINSPOOL.@]
1834 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1836 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1837 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1838 LPDEVMODEA pDevModeInput,DWORD fMode )
1840 LPSTR lpName = pDeviceName;
1841 static CHAR port[] = "LPT1:";
1844 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1845 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1849 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1851 ERR("no name from hPrinter?\n");
1852 SetLastError(ERROR_INVALID_HANDLE);
1855 lpName = strdupWtoA(lpNameW);
1858 if (!GDI_CallExtDeviceMode16)
1860 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1862 if (!GDI_CallExtDeviceMode16) {
1863 ERR("No CallExtDeviceMode16?\n");
1867 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1868 pDevModeInput, NULL, fMode);
1871 HeapFree(GetProcessHeap(),0,lpName);
1876 /*****************************************************************************
1877 * DocumentPropertiesW (WINSPOOL.@)
1879 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1881 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1883 LPDEVMODEW pDevModeOutput,
1884 LPDEVMODEW pDevModeInput, DWORD fMode)
1887 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1888 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1889 LPDEVMODEA pDevModeOutputA = NULL;
1892 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1893 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1895 if(pDevModeOutput) {
1896 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1897 if(ret < 0) return ret;
1898 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1900 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1901 pDevModeInputA, fMode);
1902 if(pDevModeOutput) {
1903 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1904 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1906 if(fMode == 0 && ret > 0)
1907 ret += (CCHDEVICENAME + CCHFORMNAME);
1908 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1909 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1913 /*****************************************************************************
1914 * IsValidDevmodeA [WINSPOOL.@]
1916 * Validate a DEVMODE structure and fix errors if possible.
1919 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1921 FIXME("(%p,%ld): stub\n", pDevMode, size);
1929 /*****************************************************************************
1930 * IsValidDevmodeW [WINSPOOL.@]
1932 * Validate a DEVMODE structure and fix errors if possible.
1935 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1937 FIXME("(%p,%ld): stub\n", pDevMode, size);
1945 /******************************************************************
1946 * OpenPrinterA [WINSPOOL.@]
1951 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1952 LPPRINTER_DEFAULTSA pDefault)
1954 UNICODE_STRING lpPrinterNameW;
1955 UNICODE_STRING usBuffer;
1956 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1957 PWSTR pwstrPrinterNameW;
1960 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1963 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1964 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1965 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1966 pDefaultW = &DefaultW;
1968 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1970 RtlFreeUnicodeString(&usBuffer);
1971 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1973 RtlFreeUnicodeString(&lpPrinterNameW);
1977 /******************************************************************
1978 * OpenPrinterW [WINSPOOL.@]
1980 * Open a Printer / Printserver or a Printer-Object
1983 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1984 * phPrinter [O] The resulting Handle is stored here
1985 * pDefault [I] PTR to Default Printer Settings or NULL
1992 * lpPrinterName is one of:
1993 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1994 *| Printer: "PrinterName"
1995 *| Printer-Object: "PrinterName,Job xxx"
1996 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1997 *| XcvPort: "Servername,XcvPort PortName"
2000 *| Printer-Object not supported
2001 *| pDefaults is ignored
2004 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2007 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2010 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2011 SetLastError(ERROR_INVALID_PARAMETER);
2015 /* Get the unique handle of the printer or Printserver */
2016 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2017 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2018 return (*phPrinter != 0);
2021 /******************************************************************
2022 * AddMonitorA [WINSPOOL.@]
2027 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2029 LPWSTR nameW = NULL;
2032 LPMONITOR_INFO_2A mi2a;
2033 MONITOR_INFO_2W mi2w;
2035 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2036 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2037 debugstr_a(mi2a ? mi2a->pName : NULL),
2038 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2039 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2042 SetLastError(ERROR_INVALID_LEVEL);
2046 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2052 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2053 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2054 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2057 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2059 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2060 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2061 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2063 if (mi2a->pEnvironment) {
2064 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2065 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2066 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2068 if (mi2a->pDLLName) {
2069 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2070 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2071 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2074 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2076 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2077 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2078 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2080 HeapFree(GetProcessHeap(), 0, nameW);
2084 /******************************************************************************
2085 * AddMonitorW [WINSPOOL.@]
2087 * Install a Printmonitor
2090 * pName [I] Servername or NULL (local Computer)
2091 * Level [I] Structure-Level (Must be 2)
2092 * pMonitors [I] PTR to MONITOR_INFO_2
2099 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2102 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2104 LPMONITOR_INFO_2W mi2w;
2106 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2107 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2108 debugstr_w(mi2w ? mi2w->pName : NULL),
2109 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2110 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2112 if ((backend == NULL) && !load_backend()) return FALSE;
2115 SetLastError(ERROR_INVALID_LEVEL);
2119 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2124 return backend->fpAddMonitor(pName, Level, pMonitors);
2127 /******************************************************************
2128 * DeletePrinterDriverA [WINSPOOL.@]
2131 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2133 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2136 /******************************************************************
2137 * DeletePrinterDriverW [WINSPOOL.@]
2140 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2142 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2145 /******************************************************************
2146 * DeleteMonitorA [WINSPOOL.@]
2148 * See DeleteMonitorW.
2151 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2153 LPWSTR nameW = NULL;
2154 LPWSTR EnvironmentW = NULL;
2155 LPWSTR MonitorNameW = NULL;
2160 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2161 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2162 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2166 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2167 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2168 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2171 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2172 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2173 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2176 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2178 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2179 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2180 HeapFree(GetProcessHeap(), 0, nameW);
2184 /******************************************************************
2185 * DeleteMonitorW [WINSPOOL.@]
2187 * Delete a specific Printmonitor from a Printing-Environment
2190 * pName [I] Servername or NULL (local Computer)
2191 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2192 * pMonitorName [I] Name of the Monitor, that should be deleted
2199 * pEnvironment is ignored in Windows for the local Computer.
2202 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2205 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2206 debugstr_w(pMonitorName));
2208 if ((backend == NULL) && !load_backend()) return FALSE;
2210 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2214 /******************************************************************
2215 * DeletePortA [WINSPOOL.@]
2220 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2222 LPWSTR nameW = NULL;
2223 LPWSTR portW = NULL;
2227 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2229 /* convert servername to unicode */
2231 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2232 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2233 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2236 /* convert portname to unicode */
2238 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2239 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2240 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2243 res = DeletePortW(nameW, hWnd, portW);
2244 HeapFree(GetProcessHeap(), 0, nameW);
2245 HeapFree(GetProcessHeap(), 0, portW);
2249 /******************************************************************
2250 * DeletePortW [WINSPOOL.@]
2252 * Delete a specific Port
2255 * pName [I] Servername or NULL (local Computer)
2256 * hWnd [I] Handle to parent Window for the Dialog-Box
2257 * pPortName [I] Name of the Port, that should be deleted
2264 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2266 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2268 if ((backend == NULL) && !load_backend()) return FALSE;
2271 SetLastError(RPC_X_NULL_REF_POINTER);
2275 return backend->fpDeletePort(pName, hWnd, pPortName);
2278 /******************************************************************************
2279 * WritePrinter [WINSPOOL.@]
2281 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2283 opened_printer_t *printer;
2286 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2288 EnterCriticalSection(&printer_handles_cs);
2289 printer = get_opened_printer(hPrinter);
2292 SetLastError(ERROR_INVALID_HANDLE);
2298 SetLastError(ERROR_SPL_NO_STARTDOC);
2302 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2304 LeaveCriticalSection(&printer_handles_cs);
2308 /*****************************************************************************
2309 * AddFormA [WINSPOOL.@]
2311 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2313 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2317 /*****************************************************************************
2318 * AddFormW [WINSPOOL.@]
2320 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2322 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2326 /*****************************************************************************
2327 * AddJobA [WINSPOOL.@]
2329 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2332 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2336 SetLastError(ERROR_INVALID_LEVEL);
2340 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2343 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2344 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2345 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2346 if(*pcbNeeded > cbBuf) {
2347 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2350 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2351 addjobA->JobId = addjobW->JobId;
2352 addjobA->Path = (char *)(addjobA + 1);
2353 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2359 /*****************************************************************************
2360 * AddJobW [WINSPOOL.@]
2362 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2364 opened_printer_t *printer;
2367 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2368 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2369 WCHAR path[MAX_PATH], filename[MAX_PATH];
2371 ADDJOB_INFO_1W *addjob;
2373 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2375 EnterCriticalSection(&printer_handles_cs);
2377 printer = get_opened_printer(hPrinter);
2380 SetLastError(ERROR_INVALID_HANDLE);
2385 SetLastError(ERROR_INVALID_LEVEL);
2389 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2393 job->job_id = InterlockedIncrement(&next_job_id);
2395 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2396 if(path[len - 1] != '\\')
2398 memcpy(path + len, spool_path, sizeof(spool_path));
2399 sprintfW(filename, fmtW, path, job->job_id);
2401 len = strlenW(filename);
2402 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2403 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2404 job->portname = NULL;
2405 job->document_title = strdupW(default_doc_title);
2406 job->printer_name = strdupW(printer->name);
2407 job->devmode = dup_devmode( printer->devmode );
2408 list_add_tail(&printer->queue->jobs, &job->entry);
2410 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2411 if(*pcbNeeded <= cbBuf) {
2412 addjob = (ADDJOB_INFO_1W*)pData;
2413 addjob->JobId = job->job_id;
2414 addjob->Path = (WCHAR *)(addjob + 1);
2415 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2418 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2421 LeaveCriticalSection(&printer_handles_cs);
2425 /*****************************************************************************
2426 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2428 * Return the PATH for the Print-Processors
2430 * See GetPrintProcessorDirectoryW.
2434 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2435 DWORD level, LPBYTE Info,
2436 DWORD cbBuf, LPDWORD pcbNeeded)
2438 LPWSTR serverW = NULL;
2443 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2444 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2448 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2449 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2450 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2454 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2455 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2456 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2459 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2460 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2462 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2465 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2466 cbBuf, NULL, NULL) > 0;
2469 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2470 HeapFree(GetProcessHeap(), 0, envW);
2471 HeapFree(GetProcessHeap(), 0, serverW);
2475 /*****************************************************************************
2476 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2478 * Return the PATH for the Print-Processors
2481 * server [I] Servername (NT only) or NULL (local Computer)
2482 * env [I] Printing-Environment (see below) or NULL (Default)
2483 * level [I] Structure-Level (must be 1)
2484 * Info [O] PTR to Buffer that receives the Result
2485 * cbBuf [I] Size of Buffer at "Info"
2486 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2487 * required for the Buffer at "Info"
2490 * Success: TRUE and in pcbNeeded the Bytes used in Info
2491 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2492 * if cbBuf is too small
2494 * Native Values returned in Info on Success:
2495 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2496 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2497 *| win9x(Windows 4.0): "%winsysdir%"
2499 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2502 * Only NULL or "" is supported for server
2505 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2506 DWORD level, LPBYTE Info,
2507 DWORD cbBuf, LPDWORD pcbNeeded)
2510 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2511 Info, cbBuf, pcbNeeded);
2513 if ((backend == NULL) && !load_backend()) return FALSE;
2516 /* (Level != 1) is ignored in win9x */
2517 SetLastError(ERROR_INVALID_LEVEL);
2521 if (pcbNeeded == NULL) {
2522 /* (pcbNeeded == NULL) is ignored in win9x */
2523 SetLastError(RPC_X_NULL_REF_POINTER);
2527 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2530 /*****************************************************************************
2531 * WINSPOOL_OpenDriverReg [internal]
2533 * opens the registry for the printer drivers depending on the given input
2534 * variable pEnvironment
2537 * the opened hkey on success
2540 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2544 const printenv_t * env;
2546 TRACE("(%s)\n", debugstr_w(pEnvironment));
2548 env = validate_envW(pEnvironment);
2549 if (!env) return NULL;
2551 buffer = HeapAlloc( GetProcessHeap(), 0,
2552 (strlenW(DriversW) + strlenW(env->envname) +
2553 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2555 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2556 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2557 HeapFree(GetProcessHeap(), 0, buffer);
2562 /*****************************************************************************
2563 * set_devices_and_printerports [internal]
2565 * set the [Devices] and [PrinterPorts] entries for a printer.
2568 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2570 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2574 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2576 /* FIXME: the driver must change to "winspool" */
2577 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2579 lstrcpyW(devline, driver_nt);
2580 lstrcatW(devline, commaW);
2581 lstrcatW(devline, pi->pPortName);
2583 TRACE("using %s\n", debugstr_w(devline));
2584 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2585 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2586 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2587 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2591 lstrcatW(devline, timeout_15_45);
2592 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2593 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2594 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2595 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2598 HeapFree(GetProcessHeap(), 0, devline);
2602 /*****************************************************************************
2603 * AddPrinterW [WINSPOOL.@]
2605 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2607 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2610 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2613 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2616 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2617 SetLastError(ERROR_INVALID_PARAMETER);
2621 ERR("Level = %d, unsupported!\n", Level);
2622 SetLastError(ERROR_INVALID_LEVEL);
2626 SetLastError(ERROR_INVALID_PARAMETER);
2629 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2631 ERR("Can't create Printers key\n");
2634 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2635 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
2636 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2637 RegCloseKey(hkeyPrinter);
2638 RegCloseKey(hkeyPrinters);
2641 RegCloseKey(hkeyPrinter);
2643 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2645 ERR("Can't create Drivers key\n");
2646 RegCloseKey(hkeyPrinters);
2649 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2651 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2652 RegCloseKey(hkeyPrinters);
2653 RegCloseKey(hkeyDrivers);
2654 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2657 RegCloseKey(hkeyDriver);
2658 RegCloseKey(hkeyDrivers);
2660 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2661 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2662 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2663 RegCloseKey(hkeyPrinters);
2667 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2669 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2670 SetLastError(ERROR_INVALID_PRINTER_NAME);
2671 RegCloseKey(hkeyPrinters);
2675 set_devices_and_printerports(pi);
2676 RegSetValueExW(hkeyPrinter, AttributesW, 0, REG_DWORD,
2677 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2678 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2680 /* See if we can load the driver. We may need the devmode structure anyway
2683 * Note that DocumentPropertiesW will briefly try to open the printer we
2684 * just create to find a DEVMODE struct (it will use the WINEPS default
2685 * one in case it is not there, so we are ok).
2687 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2690 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2691 size = sizeof(DEVMODEW);
2697 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2699 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2701 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2702 HeapFree( GetProcessHeap(), 0, dm );
2707 /* set devmode to printer name */
2708 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2712 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
2713 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2715 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2716 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2717 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2718 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2720 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2721 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2722 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2723 RegSetValueExW(hkeyPrinter, PriorityW, 0, REG_DWORD,
2724 (LPBYTE)&pi->Priority, sizeof(DWORD));
2725 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2726 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2727 RegSetValueExW(hkeyPrinter, StartTimeW, 0, REG_DWORD,
2728 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2729 RegSetValueExW(hkeyPrinter, StatusW, 0, REG_DWORD,
2730 (LPBYTE)&pi->Status, sizeof(DWORD));
2731 RegSetValueExW(hkeyPrinter, UntilTimeW, 0, REG_DWORD,
2732 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2734 RegCloseKey(hkeyPrinter);
2735 RegCloseKey(hkeyPrinters);
2736 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2737 ERR("OpenPrinter failing\n");
2743 /*****************************************************************************
2744 * AddPrinterA [WINSPOOL.@]
2746 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2748 UNICODE_STRING pNameW;
2750 PRINTER_INFO_2W *piW;
2751 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2754 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2756 ERR("Level = %d, unsupported!\n", Level);
2757 SetLastError(ERROR_INVALID_LEVEL);
2760 pwstrNameW = asciitounicode(&pNameW,pName);
2761 piW = printer_info_AtoW( piA, Level );
2763 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2765 free_printer_info( piW, Level );
2766 RtlFreeUnicodeString(&pNameW);
2771 /*****************************************************************************
2772 * ClosePrinter [WINSPOOL.@]
2774 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2776 UINT_PTR i = (UINT_PTR)hPrinter;
2777 opened_printer_t *printer = NULL;
2780 TRACE("(%p)\n", hPrinter);
2782 EnterCriticalSection(&printer_handles_cs);
2784 if ((i > 0) && (i <= nb_printer_handles))
2785 printer = printer_handles[i - 1];
2790 struct list *cursor, *cursor2;
2792 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2794 if (printer->backend_printer) {
2795 backend->fpClosePrinter(printer->backend_printer);
2799 EndDocPrinter(hPrinter);
2801 if(InterlockedDecrement(&printer->queue->ref) == 0)
2803 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2805 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2806 ScheduleJob(hPrinter, job->job_id);
2808 HeapFree(GetProcessHeap(), 0, printer->queue);
2811 free_printer_entry( printer );
2812 printer_handles[i - 1] = NULL;
2815 LeaveCriticalSection(&printer_handles_cs);
2819 /*****************************************************************************
2820 * DeleteFormA [WINSPOOL.@]
2822 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2824 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2828 /*****************************************************************************
2829 * DeleteFormW [WINSPOOL.@]
2831 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2833 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2837 /*****************************************************************************
2838 * DeletePrinter [WINSPOOL.@]
2840 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2842 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2843 HKEY hkeyPrinters, hkey;
2844 WCHAR def[MAX_PATH];
2845 DWORD size = sizeof( def ) / sizeof( def[0] );
2848 SetLastError(ERROR_INVALID_HANDLE);
2851 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2852 RegDeleteTreeW(hkeyPrinters, lpNameW);
2853 RegCloseKey(hkeyPrinters);
2855 WriteProfileStringW(devicesW, lpNameW, NULL);
2856 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2858 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2859 RegDeleteValueW(hkey, lpNameW);
2863 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2864 RegDeleteValueW(hkey, lpNameW);
2868 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2870 WriteProfileStringW( windowsW, deviceW, NULL );
2871 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2873 RegDeleteValueW( hkey, deviceW );
2874 RegCloseKey( hkey );
2876 SetDefaultPrinterW( NULL );
2882 /*****************************************************************************
2883 * SetPrinterA [WINSPOOL.@]
2885 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2892 dataW = printer_info_AtoW( data, level );
2893 if (!dataW) return FALSE;
2896 ret = SetPrinterW( printer, level, dataW, command );
2898 if (dataW != data) free_printer_info( dataW, level );
2903 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2905 set_reg_szW( key, NameW, pi->pPrinterName );
2906 set_reg_szW( key, Share_NameW, pi->pShareName );
2907 set_reg_szW( key, PortW, pi->pPortName );
2908 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
2909 set_reg_szW( key, DescriptionW, pi->pComment );
2910 set_reg_szW( key, LocationW, pi->pLocation );
2913 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2915 set_reg_szW( key, Separator_FileW, pi->pSepFile );
2916 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
2917 set_reg_szW( key, DatatypeW, pi->pDatatype );
2918 set_reg_szW( key, ParametersW, pi->pParameters );
2920 set_reg_DWORD( key, AttributesW, pi->Attributes );
2921 set_reg_DWORD( key, PriorityW, pi->Priority );
2922 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
2923 set_reg_DWORD( key, StartTimeW, pi->StartTime );
2924 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
2927 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2929 if (!pi->pDevMode) return FALSE;
2931 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2935 /******************************************************************************
2936 * SetPrinterW [WINSPOOL.@]
2938 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2943 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2945 if (command != 0) FIXME( "Ignoring command %d\n", command );
2947 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2954 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2955 set_printer_2( key, pi2 );
2962 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2963 ret = set_printer_9( key, pi );
2968 FIXME( "Unimplemented level %d\n", level );
2969 SetLastError( ERROR_INVALID_LEVEL );
2976 /*****************************************************************************
2977 * SetJobA [WINSPOOL.@]
2979 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2980 LPBYTE pJob, DWORD Command)
2984 UNICODE_STRING usBuffer;
2986 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2988 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2989 are all ignored by SetJob, so we don't bother copying them */
2997 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2998 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3000 JobW = (LPBYTE)info1W;
3001 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3002 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3003 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3004 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3005 info1W->Status = info1A->Status;
3006 info1W->Priority = info1A->Priority;
3007 info1W->Position = info1A->Position;
3008 info1W->PagesPrinted = info1A->PagesPrinted;
3013 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3014 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3016 JobW = (LPBYTE)info2W;
3017 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3018 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3019 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3020 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3021 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3022 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3023 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3024 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3025 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3026 info2W->Status = info2A->Status;
3027 info2W->Priority = info2A->Priority;
3028 info2W->Position = info2A->Position;
3029 info2W->StartTime = info2A->StartTime;
3030 info2W->UntilTime = info2A->UntilTime;
3031 info2W->PagesPrinted = info2A->PagesPrinted;
3035 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3036 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3039 SetLastError(ERROR_INVALID_LEVEL);
3043 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3049 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3050 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3051 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3052 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3053 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3058 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3059 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3060 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3061 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3062 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3063 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3064 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3065 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3066 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3070 HeapFree(GetProcessHeap(), 0, JobW);
3075 /*****************************************************************************
3076 * SetJobW [WINSPOOL.@]
3078 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3079 LPBYTE pJob, DWORD Command)
3084 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3085 FIXME("Ignoring everything other than document title\n");
3087 EnterCriticalSection(&printer_handles_cs);
3088 job = get_job(hPrinter, JobId);
3098 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3099 HeapFree(GetProcessHeap(), 0, job->document_title);
3100 job->document_title = strdupW(info1->pDocument);
3105 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3106 HeapFree(GetProcessHeap(), 0, job->document_title);
3107 job->document_title = strdupW(info2->pDocument);
3108 HeapFree(GetProcessHeap(), 0, job->devmode);
3109 job->devmode = dup_devmode( info2->pDevMode );
3115 SetLastError(ERROR_INVALID_LEVEL);
3120 LeaveCriticalSection(&printer_handles_cs);
3124 /*****************************************************************************
3125 * EndDocPrinter [WINSPOOL.@]
3127 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3129 opened_printer_t *printer;
3131 TRACE("(%p)\n", hPrinter);
3133 EnterCriticalSection(&printer_handles_cs);
3135 printer = get_opened_printer(hPrinter);
3138 SetLastError(ERROR_INVALID_HANDLE);
3144 SetLastError(ERROR_SPL_NO_STARTDOC);
3148 CloseHandle(printer->doc->hf);
3149 ScheduleJob(hPrinter, printer->doc->job_id);
3150 HeapFree(GetProcessHeap(), 0, printer->doc);
3151 printer->doc = NULL;
3154 LeaveCriticalSection(&printer_handles_cs);
3158 /*****************************************************************************
3159 * EndPagePrinter [WINSPOOL.@]
3161 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3163 FIXME("(%p): stub\n", hPrinter);
3167 /*****************************************************************************
3168 * StartDocPrinterA [WINSPOOL.@]
3170 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3172 UNICODE_STRING usBuffer;
3174 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3177 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3178 or one (DOC_INFO_3) extra DWORDs */
3182 doc2W.JobId = doc2->JobId;
3185 doc2W.dwMode = doc2->dwMode;
3188 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3189 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3190 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3194 SetLastError(ERROR_INVALID_LEVEL);
3198 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3200 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3201 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3202 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3207 /*****************************************************************************
3208 * StartDocPrinterW [WINSPOOL.@]
3210 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3212 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3213 opened_printer_t *printer;
3214 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3215 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3216 JOB_INFO_1W job_info;
3217 DWORD needed, ret = 0;
3222 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3223 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3224 debugstr_w(doc->pDatatype));
3226 if(Level < 1 || Level > 3)
3228 SetLastError(ERROR_INVALID_LEVEL);
3232 EnterCriticalSection(&printer_handles_cs);
3233 printer = get_opened_printer(hPrinter);
3236 SetLastError(ERROR_INVALID_HANDLE);
3242 SetLastError(ERROR_INVALID_PRINTER_STATE);
3246 /* Even if we're printing to a file we still add a print job, we'll
3247 just ignore the spool file name */
3249 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3251 ERR("AddJob failed gle %u\n", GetLastError());
3255 /* use pOutputFile only, when it is a real filename */
3256 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3257 filename = doc->pOutputFile;
3259 filename = addjob->Path;
3261 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3262 if(hf == INVALID_HANDLE_VALUE)
3265 memset(&job_info, 0, sizeof(job_info));
3266 job_info.pDocument = doc->pDocName;
3267 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3269 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3270 printer->doc->hf = hf;
3271 ret = printer->doc->job_id = addjob->JobId;
3272 job = get_job(hPrinter, ret);
3273 job->portname = strdupW(doc->pOutputFile);
3276 LeaveCriticalSection(&printer_handles_cs);
3281 /*****************************************************************************
3282 * StartPagePrinter [WINSPOOL.@]
3284 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3286 FIXME("(%p): stub\n", hPrinter);
3290 /*****************************************************************************
3291 * GetFormA [WINSPOOL.@]
3293 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3294 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3296 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3297 Level,pForm,cbBuf,pcbNeeded);
3301 /*****************************************************************************
3302 * GetFormW [WINSPOOL.@]
3304 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3305 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3307 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3308 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3312 /*****************************************************************************
3313 * SetFormA [WINSPOOL.@]
3315 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3318 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3322 /*****************************************************************************
3323 * SetFormW [WINSPOOL.@]
3325 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3328 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3332 /*****************************************************************************
3333 * ReadPrinter [WINSPOOL.@]
3335 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3336 LPDWORD pNoBytesRead)
3338 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3342 /*****************************************************************************
3343 * ResetPrinterA [WINSPOOL.@]
3345 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3347 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3351 /*****************************************************************************
3352 * ResetPrinterW [WINSPOOL.@]
3354 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3356 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3360 /*****************************************************************************
3361 * WINSPOOL_GetDWORDFromReg
3363 * Return DWORD associated with ValueName from hkey.
3365 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3367 DWORD sz = sizeof(DWORD), type, value = 0;
3370 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3372 if(ret != ERROR_SUCCESS) {
3373 WARN("Got ret = %d on name %s\n", ret, ValueName);
3376 if(type != REG_DWORD) {
3377 ERR("Got type %d\n", type);
3384 /*****************************************************************************
3385 * get_filename_from_reg [internal]
3387 * Get ValueName from hkey storing result in out
3388 * when the Value in the registry has only a filename, use driverdir as prefix
3389 * outlen is space left in out
3390 * String is stored either as unicode or ascii
3394 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3395 LPBYTE out, DWORD outlen, LPDWORD needed)
3397 WCHAR filename[MAX_PATH];
3401 LPWSTR buffer = filename;
3405 size = sizeof(filename);
3407 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3408 if (ret == ERROR_MORE_DATA) {
3409 TRACE("need dynamic buffer: %u\n", size);
3410 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3412 /* No Memory is bad */
3416 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3419 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3420 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3426 /* do we have a full path ? */
3427 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3428 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3431 /* we must build the full Path */
3433 if ((out) && (outlen > dirlen)) {
3434 lstrcpyW((LPWSTR)out, driverdir);
3442 /* write the filename */
3443 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3444 if ((out) && (outlen >= size)) {
3445 lstrcpyW((LPWSTR)out, ptr);
3452 ptr += lstrlenW(ptr)+1;
3453 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3456 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3458 /* write the multisz-termination */
3459 if (type == REG_MULTI_SZ) {
3460 size = sizeof(WCHAR);
3463 if (out && (outlen >= size)) {
3464 memset (out, 0, size);
3470 /*****************************************************************************
3471 * WINSPOOL_GetStringFromReg
3473 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3474 * String is stored as unicode.
3476 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3477 DWORD buflen, DWORD *needed)
3479 DWORD sz = buflen, type;
3482 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3483 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3484 WARN("Got ret = %d\n", ret);
3488 /* add space for terminating '\0' */
3489 sz += sizeof(WCHAR);
3493 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3498 /*****************************************************************************
3499 * WINSPOOL_GetDefaultDevMode
3501 * Get a default DevMode values for wineps.
3505 static void WINSPOOL_GetDefaultDevMode(
3507 DWORD buflen, DWORD *needed)
3510 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3512 /* fill default DEVMODE - should be read from ppd... */
3513 ZeroMemory( &dm, sizeof(dm) );
3514 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3515 dm.dmSpecVersion = DM_SPECVERSION;
3516 dm.dmDriverVersion = 1;
3517 dm.dmSize = sizeof(DEVMODEW);
3518 dm.dmDriverExtra = 0;
3520 DM_ORIENTATION | DM_PAPERSIZE |
3521 DM_PAPERLENGTH | DM_PAPERWIDTH |
3524 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3525 DM_YRESOLUTION | DM_TTOPTION;
3527 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3528 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3529 dm.u1.s1.dmPaperLength = 2970;
3530 dm.u1.s1.dmPaperWidth = 2100;
3532 dm.u1.s1.dmScale = 100;
3533 dm.u1.s1.dmCopies = 1;
3534 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3535 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3538 dm.dmYResolution = 300; /* 300dpi */
3539 dm.dmTTOption = DMTT_BITMAP;
3542 /* dm.dmLogPixels */
3543 /* dm.dmBitsPerPel */
3544 /* dm.dmPelsWidth */
3545 /* dm.dmPelsHeight */
3546 /* dm.u2.dmDisplayFlags */
3547 /* dm.dmDisplayFrequency */
3548 /* dm.dmICMMethod */
3549 /* dm.dmICMIntent */
3550 /* dm.dmMediaType */
3551 /* dm.dmDitherType */
3552 /* dm.dmReserved1 */
3553 /* dm.dmReserved2 */
3554 /* dm.dmPanningWidth */
3555 /* dm.dmPanningHeight */
3557 if(buflen >= sizeof(DEVMODEW))
3558 memcpy(ptr, &dm, sizeof(DEVMODEW));
3559 *needed = sizeof(DEVMODEW);
3562 /*****************************************************************************
3563 * WINSPOOL_GetDevModeFromReg
3565 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3566 * DevMode is stored either as unicode or ascii.
3568 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3570 DWORD buflen, DWORD *needed)
3572 DWORD sz = buflen, type;
3575 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3576 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3577 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3578 if (sz < sizeof(DEVMODEA))
3580 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3583 /* ensures that dmSize is not erratically bogus if registry is invalid */
3584 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3585 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3586 sz += (CCHDEVICENAME + CCHFORMNAME);
3587 if (ptr && (buflen >= sz)) {
3588 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3589 memcpy(ptr, dmW, sz);
3590 HeapFree(GetProcessHeap(),0,dmW);
3596 /*********************************************************************
3597 * WINSPOOL_GetPrinter_1
3599 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3601 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3602 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3604 DWORD size, left = cbBuf;
3605 BOOL space = (cbBuf > 0);
3610 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3611 if(space && size <= left) {
3612 pi1->pName = (LPWSTR)ptr;
3620 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3621 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3622 if(space && size <= left) {
3623 pi1->pDescription = (LPWSTR)ptr;
3631 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3632 if(space && size <= left) {
3633 pi1->pComment = (LPWSTR)ptr;
3641 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3643 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3644 memset(pi1, 0, sizeof(*pi1));
3648 /*********************************************************************
3649 * WINSPOOL_GetPrinter_2
3651 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3653 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3654 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3656 DWORD size, left = cbBuf;
3657 BOOL space = (cbBuf > 0);
3662 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3663 if(space && size <= left) {
3664 pi2->pPrinterName = (LPWSTR)ptr;
3671 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3672 if(space && size <= left) {
3673 pi2->pShareName = (LPWSTR)ptr;
3680 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3681 if(space && size <= left) {
3682 pi2->pPortName = (LPWSTR)ptr;
3689 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3690 if(space && size <= left) {
3691 pi2->pDriverName = (LPWSTR)ptr;
3698 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3699 if(space && size <= left) {
3700 pi2->pComment = (LPWSTR)ptr;
3707 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3708 if(space && size <= left) {
3709 pi2->pLocation = (LPWSTR)ptr;
3716 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3717 if(space && size <= left) {
3718 pi2->pDevMode = (LPDEVMODEW)ptr;
3727 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3728 if(space && size <= left) {
3729 pi2->pDevMode = (LPDEVMODEW)ptr;
3736 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3737 if(space && size <= left) {
3738 pi2->pSepFile = (LPWSTR)ptr;
3745 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3746 if(space && size <= left) {
3747 pi2->pPrintProcessor = (LPWSTR)ptr;
3754 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3755 if(space && size <= left) {
3756 pi2->pDatatype = (LPWSTR)ptr;
3763 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3764 if(space && size <= left) {
3765 pi2->pParameters = (LPWSTR)ptr;
3773 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3774 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3775 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3776 "Default Priority");
3777 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3778 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3781 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3782 memset(pi2, 0, sizeof(*pi2));
3787 /*********************************************************************
3788 * WINSPOOL_GetPrinter_4
3790 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3792 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3793 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3795 DWORD size, left = cbBuf;
3796 BOOL space = (cbBuf > 0);
3801 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3802 if(space && size <= left) {
3803 pi4->pPrinterName = (LPWSTR)ptr;
3811 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3814 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3815 memset(pi4, 0, sizeof(*pi4));
3820 /*********************************************************************
3821 * WINSPOOL_GetPrinter_5
3823 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3825 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3826 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3828 DWORD size, left = cbBuf;
3829 BOOL space = (cbBuf > 0);
3834 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3835 if(space && size <= left) {
3836 pi5->pPrinterName = (LPWSTR)ptr;
3843 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3844 if(space && size <= left) {
3845 pi5->pPortName = (LPWSTR)ptr;
3853 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3854 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3856 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3860 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3861 memset(pi5, 0, sizeof(*pi5));
3866 /*********************************************************************
3867 * WINSPOOL_GetPrinter_7
3869 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3871 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3872 DWORD cbBuf, LPDWORD pcbNeeded)
3874 DWORD size, left = cbBuf;
3875 BOOL space = (cbBuf > 0);
3880 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3883 size = sizeof(pi7->pszObjectGUID);
3885 if (space && size <= left) {
3886 pi7->pszObjectGUID = (LPWSTR)ptr;
3893 /* We do not have a Directory Service */
3894 pi7->dwAction = DSPRINT_UNPUBLISH;
3897 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3898 memset(pi7, 0, sizeof(*pi7));
3903 /*********************************************************************
3904 * WINSPOOL_GetPrinter_9
3906 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3908 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3909 DWORD cbBuf, LPDWORD pcbNeeded)
3912 BOOL space = (cbBuf > 0);
3916 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3917 if(space && size <= cbBuf) {
3918 pi9->pDevMode = (LPDEVMODEW)buf;
3925 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3926 if(space && size <= cbBuf) {
3927 pi9->pDevMode = (LPDEVMODEW)buf;
3933 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3934 memset(pi9, 0, sizeof(*pi9));
3939 /*****************************************************************************
3940 * GetPrinterW [WINSPOOL.@]
3942 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3943 DWORD cbBuf, LPDWORD pcbNeeded)
3945 DWORD size, needed = 0, err;
3950 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3952 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3955 SetLastError( err );
3962 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3964 size = sizeof(PRINTER_INFO_2W);
3966 ptr = pPrinter + size;
3968 memset(pPrinter, 0, size);
3973 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3980 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3982 size = sizeof(PRINTER_INFO_4W);
3984 ptr = pPrinter + size;
3986 memset(pPrinter, 0, size);
3991 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3999 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4001 size = sizeof(PRINTER_INFO_5W);
4003 ptr = pPrinter + size;
4005 memset(pPrinter, 0, size);
4011 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4019 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4021 size = sizeof(PRINTER_INFO_6);
4022 if (size <= cbBuf) {
4023 /* FIXME: We do not update the status yet */
4024 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4036 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4038 size = sizeof(PRINTER_INFO_7W);
4039 if (size <= cbBuf) {
4040 ptr = pPrinter + size;
4042 memset(pPrinter, 0, size);
4048 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4055 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4056 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4060 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4062 size = sizeof(PRINTER_INFO_9W);
4064 ptr = pPrinter + size;
4066 memset(pPrinter, 0, size);
4072 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4079 FIXME("Unimplemented level %d\n", Level);
4080 SetLastError(ERROR_INVALID_LEVEL);
4081 RegCloseKey(hkeyPrinter);
4085 RegCloseKey(hkeyPrinter);
4087 TRACE("returning %d needed = %d\n", ret, needed);
4088 if(pcbNeeded) *pcbNeeded = needed;
4090 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4094 /*****************************************************************************
4095 * GetPrinterA [WINSPOOL.@]
4097 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4098 DWORD cbBuf, LPDWORD pcbNeeded)
4104 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4106 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4108 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4109 HeapFree(GetProcessHeap(), 0, buf);
4114 /*****************************************************************************
4115 * WINSPOOL_EnumPrintersW
4117 * Implementation of EnumPrintersW
4119 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4120 DWORD dwLevel, LPBYTE lpbPrinters,
4121 DWORD cbBuf, LPDWORD lpdwNeeded,
4122 LPDWORD lpdwReturned)
4125 HKEY hkeyPrinters, hkeyPrinter;
4126 WCHAR PrinterName[255];
4127 DWORD needed = 0, number = 0;
4128 DWORD used, i, left;
4132 memset(lpbPrinters, 0, cbBuf);
4138 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4139 if(dwType == PRINTER_ENUM_DEFAULT)
4142 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4143 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4144 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4146 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4152 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4153 FIXME("dwType = %08x\n", dwType);
4154 SetLastError(ERROR_INVALID_FLAGS);
4158 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4160 ERR("Can't create Printers key\n");
4164 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4165 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4166 RegCloseKey(hkeyPrinters);
4167 ERR("Can't query Printers key\n");
4170 TRACE("Found %d printers\n", number);
4174 used = number * sizeof(PRINTER_INFO_1W);
4177 used = number * sizeof(PRINTER_INFO_2W);
4180 used = number * sizeof(PRINTER_INFO_4W);
4183 used = number * sizeof(PRINTER_INFO_5W);
4187 SetLastError(ERROR_INVALID_LEVEL);
4188 RegCloseKey(hkeyPrinters);
4191 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4193 for(i = 0; i < number; i++) {
4194 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4196 ERR("Can't enum key number %d\n", i);
4197 RegCloseKey(hkeyPrinters);
4200 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4201 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4203 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4204 RegCloseKey(hkeyPrinters);
4209 buf = lpbPrinters + used;
4210 left = cbBuf - used;
4218 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4221 if(pi) pi += sizeof(PRINTER_INFO_1W);
4224 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4227 if(pi) pi += sizeof(PRINTER_INFO_2W);
4230 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4233 if(pi) pi += sizeof(PRINTER_INFO_4W);
4236 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4239 if(pi) pi += sizeof(PRINTER_INFO_5W);
4242 ERR("Shouldn't be here!\n");
4243 RegCloseKey(hkeyPrinter);
4244 RegCloseKey(hkeyPrinters);
4247 RegCloseKey(hkeyPrinter);
4249 RegCloseKey(hkeyPrinters);
4256 memset(lpbPrinters, 0, cbBuf);
4257 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4261 *lpdwReturned = number;
4262 SetLastError(ERROR_SUCCESS);
4267 /******************************************************************
4268 * EnumPrintersW [WINSPOOL.@]
4270 * Enumerates the available printers, print servers and print
4271 * providers, depending on the specified flags, name and level.
4275 * If level is set to 1:
4276 * Returns an array of PRINTER_INFO_1 data structures in the
4277 * lpbPrinters buffer.
4279 * If level is set to 2:
4280 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4281 * Returns an array of PRINTER_INFO_2 data structures in the
4282 * lpbPrinters buffer. Note that according to MSDN also an
4283 * OpenPrinter should be performed on every remote printer.
4285 * If level is set to 4 (officially WinNT only):
4286 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4287 * Fast: Only the registry is queried to retrieve printer names,
4288 * no connection to the driver is made.
4289 * Returns an array of PRINTER_INFO_4 data structures in the
4290 * lpbPrinters buffer.
4292 * If level is set to 5 (officially WinNT4/Win9x only):
4293 * Fast: Only the registry is queried to retrieve printer names,
4294 * no connection to the driver is made.
4295 * Returns an array of PRINTER_INFO_5 data structures in the
4296 * lpbPrinters buffer.
4298 * If level set to 3 or 6+:
4299 * returns zero (failure!)
4301 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4305 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4306 * - Only levels 2, 4 and 5 are implemented at the moment.
4307 * - 16-bit printer drivers are not enumerated.
4308 * - Returned amount of bytes used/needed does not match the real Windoze
4309 * implementation (as in this implementation, all strings are part
4310 * of the buffer, whereas Win32 keeps them somewhere else)
4311 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4314 * - In a regular Wine installation, no registry settings for printers
4315 * exist, which makes this function return an empty list.
4317 BOOL WINAPI EnumPrintersW(
4318 DWORD dwType, /* [in] Types of print objects to enumerate */
4319 LPWSTR lpszName, /* [in] name of objects to enumerate */
4320 DWORD dwLevel, /* [in] type of printer info structure */
4321 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4322 DWORD cbBuf, /* [in] max size of buffer in bytes */
4323 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4324 LPDWORD lpdwReturned /* [out] number of entries returned */
4327 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4328 lpdwNeeded, lpdwReturned);
4331 /******************************************************************
4332 * EnumPrintersA [WINSPOOL.@]
4337 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4338 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4341 UNICODE_STRING pNameU;
4345 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4346 pPrinters, cbBuf, pcbNeeded, pcReturned);
4348 pNameW = asciitounicode(&pNameU, pName);
4350 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4351 MS Office need this */
4352 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4354 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4356 RtlFreeUnicodeString(&pNameU);
4358 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4360 HeapFree(GetProcessHeap(), 0, pPrintersW);
4364 /*****************************************************************************
4365 * WINSPOOL_GetDriverInfoFromReg [internal]
4367 * Enters the information from the registry into the DRIVER_INFO struct
4370 * zero if the printer driver does not exist in the registry
4371 * (only if Level > 1) otherwise nonzero
4373 static BOOL WINSPOOL_GetDriverInfoFromReg(
4376 const printenv_t * env,
4378 LPBYTE ptr, /* DRIVER_INFO */
4379 LPBYTE pDriverStrings, /* strings buffer */
4380 DWORD cbBuf, /* size of string buffer */
4381 LPDWORD pcbNeeded) /* space needed for str. */
4385 WCHAR driverdir[MAX_PATH];
4387 LPBYTE strPtr = pDriverStrings;
4388 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4390 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4391 debugstr_w(DriverName), env,
4392 Level, di, pDriverStrings, cbBuf);
4394 if (di) ZeroMemory(di, di_sizeof[Level]);
4396 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4397 if (*pcbNeeded <= cbBuf)
4398 strcpyW((LPWSTR)strPtr, DriverName);
4400 /* pName for level 1 has a different offset! */
4402 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4406 /* .cVersion and .pName for level > 1 */
4408 di->cVersion = env->driverversion;
4409 di->pName = (LPWSTR) strPtr;
4410 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4413 /* Reserve Space for the largest subdir and a Backslash*/
4414 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4415 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4416 /* Should never Fail */
4419 lstrcatW(driverdir, env->versionsubdir);
4420 lstrcatW(driverdir, backslashW);
4422 /* dirlen must not include the terminating zero */
4423 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4425 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4426 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4427 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4432 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4435 if (*pcbNeeded <= cbBuf) {
4436 lstrcpyW((LPWSTR)strPtr, env->envname);
4437 if (di) di->pEnvironment = (LPWSTR)strPtr;
4438 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4441 /* .pDriverPath is the Graphics rendering engine.
4442 The full Path is required to avoid a crash in some apps */
4443 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4445 if (*pcbNeeded <= cbBuf)
4446 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4448 if (di) di->pDriverPath = (LPWSTR)strPtr;
4449 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4452 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4453 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4455 if (*pcbNeeded <= cbBuf)
4456 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4458 if (di) di->pDataFile = (LPWSTR)strPtr;
4459 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4462 /* .pConfigFile is the Driver user Interface */
4463 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4465 if (*pcbNeeded <= cbBuf)
4466 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4468 if (di) di->pConfigFile = (LPWSTR)strPtr;
4469 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4473 RegCloseKey(hkeyDriver);
4474 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4479 RegCloseKey(hkeyDriver);
4480 FIXME("level 5: incomplete\n");
4485 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4487 if (*pcbNeeded <= cbBuf)
4488 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4490 if (di) di->pHelpFile = (LPWSTR)strPtr;
4491 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4494 /* .pDependentFiles */
4495 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4497 if (*pcbNeeded <= cbBuf)
4498 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4500 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4501 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4503 else if (GetVersion() & 0x80000000) {
4504 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4505 size = 2 * sizeof(WCHAR);
4507 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4509 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4510 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4513 /* .pMonitorName is the optional Language Monitor */
4514 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4516 if (*pcbNeeded <= cbBuf)
4517 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4519 if (di) di->pMonitorName = (LPWSTR)strPtr;
4520 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4523 /* .pDefaultDataType */
4524 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4526 if(*pcbNeeded <= cbBuf)
4527 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4529 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4530 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4534 RegCloseKey(hkeyDriver);
4535 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4539 /* .pszzPreviousNames */
4540 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4542 if(*pcbNeeded <= cbBuf)
4543 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4545 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4546 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4550 RegCloseKey(hkeyDriver);
4551 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4555 /* support is missing, but not important enough for a FIXME */
4556 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4559 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4561 if(*pcbNeeded <= cbBuf)
4562 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4564 if (di) di->pszMfgName = (LPWSTR)strPtr;
4565 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4569 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4571 if(*pcbNeeded <= cbBuf)
4572 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4574 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4575 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4578 /* .pszHardwareID */
4579 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4581 if(*pcbNeeded <= cbBuf)
4582 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4584 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4585 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4589 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4591 if(*pcbNeeded <= cbBuf)
4592 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4594 if (di) di->pszProvider = (LPWSTR)strPtr;
4595 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4599 RegCloseKey(hkeyDriver);
4603 /* support is missing, but not important enough for a FIXME */
4604 TRACE("level 8: incomplete\n");
4606 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4607 RegCloseKey(hkeyDriver);
4611 /*****************************************************************************
4612 * GetPrinterDriverW [WINSPOOL.@]
4614 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4615 DWORD Level, LPBYTE pDriverInfo,
4616 DWORD cbBuf, LPDWORD pcbNeeded)
4619 WCHAR DriverName[100];
4620 DWORD ret, type, size, needed = 0;
4622 HKEY hkeyPrinter, hkeyDrivers;
4623 const printenv_t * env;
4625 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4626 Level,pDriverInfo,cbBuf, pcbNeeded);
4629 ZeroMemory(pDriverInfo, cbBuf);
4631 if (!(name = get_opened_printer_name(hPrinter))) {
4632 SetLastError(ERROR_INVALID_HANDLE);
4636 if (Level < 1 || Level == 7 || Level > 8) {
4637 SetLastError(ERROR_INVALID_LEVEL);
4641 env = validate_envW(pEnvironment);
4642 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4644 ret = open_printer_reg_key( name, &hkeyPrinter );
4647 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4648 SetLastError( ret );
4652 size = sizeof(DriverName);
4654 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4655 (LPBYTE)DriverName, &size);
4656 RegCloseKey(hkeyPrinter);
4657 if(ret != ERROR_SUCCESS) {
4658 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4662 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4664 ERR("Can't create Drivers key\n");
4668 size = di_sizeof[Level];
4669 if ((size <= cbBuf) && pDriverInfo)
4670 ptr = pDriverInfo + size;
4672 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4673 env, Level, pDriverInfo, ptr,
4674 (cbBuf < size) ? 0 : cbBuf - size,
4676 RegCloseKey(hkeyDrivers);
4680 RegCloseKey(hkeyDrivers);
4682 if(pcbNeeded) *pcbNeeded = size + needed;
4683 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4684 if(cbBuf >= size + needed) return TRUE;
4685 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4689 /*****************************************************************************
4690 * GetPrinterDriverA [WINSPOOL.@]
4692 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4693 DWORD Level, LPBYTE pDriverInfo,
4694 DWORD cbBuf, LPDWORD pcbNeeded)
4697 UNICODE_STRING pEnvW;
4703 ZeroMemory(pDriverInfo, cbBuf);
4704 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4707 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4708 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4711 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4713 HeapFree(GetProcessHeap(), 0, buf);
4715 RtlFreeUnicodeString(&pEnvW);
4719 /*****************************************************************************
4720 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4722 * Return the PATH for the Printer-Drivers (UNICODE)
4725 * pName [I] Servername (NT only) or NULL (local Computer)
4726 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4727 * Level [I] Structure-Level (must be 1)
4728 * pDriverDirectory [O] PTR to Buffer that receives the Result
4729 * cbBuf [I] Size of Buffer at pDriverDirectory
4730 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4731 * required for pDriverDirectory
4734 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4735 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4736 * if cbBuf is too small
4738 * Native Values returned in pDriverDirectory on Success:
4739 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4740 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4741 *| win9x(Windows 4.0): "%winsysdir%"
4743 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4746 *- Only NULL or "" is supported for pName
4749 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4750 DWORD Level, LPBYTE pDriverDirectory,
4751 DWORD cbBuf, LPDWORD pcbNeeded)
4753 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4754 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4756 if ((backend == NULL) && !load_backend()) return FALSE;
4759 /* (Level != 1) is ignored in win9x */
4760 SetLastError(ERROR_INVALID_LEVEL);
4763 if (pcbNeeded == NULL) {
4764 /* (pcbNeeded == NULL) is ignored in win9x */
4765 SetLastError(RPC_X_NULL_REF_POINTER);
4769 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4770 pDriverDirectory, cbBuf, pcbNeeded);
4775 /*****************************************************************************
4776 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4778 * Return the PATH for the Printer-Drivers (ANSI)
4780 * See GetPrinterDriverDirectoryW.
4783 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4786 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4787 DWORD Level, LPBYTE pDriverDirectory,
4788 DWORD cbBuf, LPDWORD pcbNeeded)
4790 UNICODE_STRING nameW, environmentW;
4793 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4794 WCHAR *driverDirectoryW = NULL;
4796 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4797 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4799 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4801 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4802 else nameW.Buffer = NULL;
4803 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4804 else environmentW.Buffer = NULL;
4806 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4807 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4810 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4811 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4813 *pcbNeeded = needed;
4814 ret = (needed <= cbBuf) ? TRUE : FALSE;
4816 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4818 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4820 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4821 RtlFreeUnicodeString(&environmentW);
4822 RtlFreeUnicodeString(&nameW);
4827 /*****************************************************************************
4828 * AddPrinterDriverA [WINSPOOL.@]
4830 * See AddPrinterDriverW.
4833 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4835 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4836 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4839 /******************************************************************************
4840 * AddPrinterDriverW (WINSPOOL.@)
4842 * Install a Printer Driver
4845 * pName [I] Servername or NULL (local Computer)
4846 * level [I] Level for the supplied DRIVER_INFO_*W struct
4847 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4854 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4856 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4857 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4860 /*****************************************************************************
4861 * AddPrintProcessorA [WINSPOOL.@]
4863 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4864 LPSTR pPrintProcessorName)
4866 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4867 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4871 /*****************************************************************************
4872 * AddPrintProcessorW [WINSPOOL.@]
4874 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4875 LPWSTR pPrintProcessorName)
4877 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4878 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4882 /*****************************************************************************
4883 * AddPrintProvidorA [WINSPOOL.@]
4885 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4887 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4891 /*****************************************************************************
4892 * AddPrintProvidorW [WINSPOOL.@]
4894 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4896 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4900 /*****************************************************************************
4901 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4903 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4904 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4906 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4907 pDevModeOutput, pDevModeInput);
4911 /*****************************************************************************
4912 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4914 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4915 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4917 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4918 pDevModeOutput, pDevModeInput);
4922 /*****************************************************************************
4923 * PrinterProperties [WINSPOOL.@]
4925 * Displays a dialog to set the properties of the printer.
4928 * nonzero on success or zero on failure
4931 * implemented as stub only
4933 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4934 HANDLE hPrinter /* [in] handle to printer object */
4936 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4937 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4941 /*****************************************************************************
4942 * EnumJobsA [WINSPOOL.@]
4945 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4946 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4949 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4950 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4952 if(pcbNeeded) *pcbNeeded = 0;
4953 if(pcReturned) *pcReturned = 0;
4958 /*****************************************************************************
4959 * EnumJobsW [WINSPOOL.@]
4962 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4963 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4966 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4967 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4969 if(pcbNeeded) *pcbNeeded = 0;
4970 if(pcReturned) *pcReturned = 0;
4974 /*****************************************************************************
4975 * WINSPOOL_EnumPrinterDrivers [internal]
4977 * Delivers information about all printer drivers installed on the
4978 * localhost or a given server
4981 * nonzero on success or zero on failure. If the buffer for the returned
4982 * information is too small the function will return an error
4985 * - only implemented for localhost, foreign hosts will return an error
4987 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4988 DWORD Level, LPBYTE pDriverInfo,
4990 DWORD cbBuf, LPDWORD pcbNeeded,
4991 LPDWORD pcFound, DWORD data_offset)
4995 const printenv_t * env;
4997 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4998 debugstr_w(pName), debugstr_w(pEnvironment),
4999 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5001 env = validate_envW(pEnvironment);
5002 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5006 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5008 ERR("Can't open Drivers key\n");
5012 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5013 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5014 RegCloseKey(hkeyDrivers);
5015 ERR("Can't query Drivers key\n");
5018 TRACE("Found %d Drivers\n", *pcFound);
5020 /* get size of single struct
5021 * unicode and ascii structure have the same size
5023 size = di_sizeof[Level];
5025 if (data_offset == 0)
5026 data_offset = size * (*pcFound);
5027 *pcbNeeded = data_offset;
5029 for( i = 0; i < *pcFound; i++) {
5030 WCHAR DriverNameW[255];
5031 PBYTE table_ptr = NULL;
5032 PBYTE data_ptr = NULL;
5035 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5037 ERR("Can't enum key number %d\n", i);
5038 RegCloseKey(hkeyDrivers);
5042 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5043 table_ptr = pDriverInfo + (driver_index + i) * size;
5044 if (pDriverInfo && *pcbNeeded <= cbBuf)
5045 data_ptr = pDriverInfo + *pcbNeeded;
5047 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5048 env, Level, table_ptr, data_ptr,
5049 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5051 RegCloseKey(hkeyDrivers);
5055 *pcbNeeded += needed;
5058 RegCloseKey(hkeyDrivers);
5060 if(cbBuf < *pcbNeeded){
5061 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5068 /*****************************************************************************
5069 * EnumPrinterDriversW [WINSPOOL.@]
5071 * see function EnumPrinterDrivers for RETURNS, BUGS
5073 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5074 LPBYTE pDriverInfo, DWORD cbBuf,
5075 LPDWORD pcbNeeded, LPDWORD pcReturned)
5077 static const WCHAR allW[] = {'a','l','l',0};
5081 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5083 SetLastError(RPC_X_NULL_REF_POINTER);
5087 /* check for local drivers */
5088 if((pName) && (pName[0])) {
5089 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5090 SetLastError(ERROR_ACCESS_DENIED);
5094 /* check input parameter */
5095 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5096 SetLastError(ERROR_INVALID_LEVEL);
5100 if(pDriverInfo && cbBuf > 0)
5101 memset( pDriverInfo, 0, cbBuf);
5103 /* Exception: pull all printers */
5104 if (pEnvironment && !strcmpW(pEnvironment, allW))
5106 DWORD i, needed, bufsize = cbBuf;
5107 DWORD total_needed = 0;
5108 DWORD total_found = 0;
5111 /* Precompute the overall total; we need this to know
5112 where pointers end and data begins (i.e. data_offset) */
5113 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5116 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5117 NULL, 0, 0, &needed, &found, 0);
5118 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5119 total_needed += needed;
5120 total_found += found;
5123 data_offset = di_sizeof[Level] * total_found;
5128 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5131 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5132 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5133 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5135 *pcReturned += found;
5136 *pcbNeeded = needed;
5137 data_offset = needed;
5138 total_found += found;
5143 /* Normal behavior */
5144 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5145 0, cbBuf, pcbNeeded, &found, 0);
5147 *pcReturned = found;
5152 /*****************************************************************************
5153 * EnumPrinterDriversA [WINSPOOL.@]
5155 * see function EnumPrinterDrivers for RETURNS, BUGS
5157 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5158 LPBYTE pDriverInfo, DWORD cbBuf,
5159 LPDWORD pcbNeeded, LPDWORD pcReturned)
5162 UNICODE_STRING pNameW, pEnvironmentW;
5163 PWSTR pwstrNameW, pwstrEnvironmentW;
5167 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5169 pwstrNameW = asciitounicode(&pNameW, pName);
5170 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5172 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5173 buf, cbBuf, pcbNeeded, pcReturned);
5175 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5177 HeapFree(GetProcessHeap(), 0, buf);
5179 RtlFreeUnicodeString(&pNameW);
5180 RtlFreeUnicodeString(&pEnvironmentW);
5185 /******************************************************************************
5186 * EnumPortsA (WINSPOOL.@)
5191 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5192 LPDWORD pcbNeeded, LPDWORD pcReturned)
5195 LPBYTE bufferW = NULL;
5196 LPWSTR nameW = NULL;
5198 DWORD numentries = 0;
5201 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5202 cbBuf, pcbNeeded, pcReturned);
5204 /* convert servername to unicode */
5206 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5207 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5208 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5210 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5211 needed = cbBuf * sizeof(WCHAR);
5212 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5213 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5215 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5216 if (pcbNeeded) needed = *pcbNeeded;
5217 /* HeapReAlloc return NULL, when bufferW was NULL */
5218 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5219 HeapAlloc(GetProcessHeap(), 0, needed);
5221 /* Try again with the large Buffer */
5222 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5224 needed = pcbNeeded ? *pcbNeeded : 0;
5225 numentries = pcReturned ? *pcReturned : 0;
5228 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5229 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5232 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5233 DWORD entrysize = 0;
5236 LPPORT_INFO_2W pi2w;
5237 LPPORT_INFO_2A pi2a;
5240 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5242 /* First pass: calculate the size for all Entries */
5243 pi2w = (LPPORT_INFO_2W) bufferW;
5244 pi2a = (LPPORT_INFO_2A) pPorts;
5246 while (index < numentries) {
5248 needed += entrysize; /* PORT_INFO_?A */
5249 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5251 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5252 NULL, 0, NULL, NULL);
5254 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5255 NULL, 0, NULL, NULL);
5256 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5257 NULL, 0, NULL, NULL);
5259 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5260 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5261 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5264 /* check for errors and quit on failure */
5265 if (cbBuf < needed) {
5266 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5270 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5271 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5272 cbBuf -= len ; /* free Bytes in the user-Buffer */
5273 pi2w = (LPPORT_INFO_2W) bufferW;
5274 pi2a = (LPPORT_INFO_2A) pPorts;
5276 /* Second Pass: Fill the User Buffer (if we have one) */
5277 while ((index < numentries) && pPorts) {
5279 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5280 pi2a->pPortName = ptr;
5281 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5282 ptr, cbBuf , NULL, NULL);
5286 pi2a->pMonitorName = ptr;
5287 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5288 ptr, cbBuf, NULL, NULL);
5292 pi2a->pDescription = ptr;
5293 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5294 ptr, cbBuf, NULL, NULL);
5298 pi2a->fPortType = pi2w->fPortType;
5299 pi2a->Reserved = 0; /* documented: "must be zero" */
5302 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5303 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5304 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5309 if (pcbNeeded) *pcbNeeded = needed;
5310 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5312 HeapFree(GetProcessHeap(), 0, nameW);
5313 HeapFree(GetProcessHeap(), 0, bufferW);
5315 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5316 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5322 /******************************************************************************
5323 * EnumPortsW (WINSPOOL.@)
5325 * Enumerate available Ports
5328 * pName [I] Servername or NULL (local Computer)
5329 * Level [I] Structure-Level (1 or 2)
5330 * pPorts [O] PTR to Buffer that receives the Result
5331 * cbBuf [I] Size of Buffer at pPorts
5332 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5333 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5337 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5340 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5343 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5344 cbBuf, pcbNeeded, pcReturned);
5346 if ((backend == NULL) && !load_backend()) return FALSE;
5348 /* Level is not checked in win9x */
5349 if (!Level || (Level > 2)) {
5350 WARN("level (%d) is ignored in win9x\n", Level);
5351 SetLastError(ERROR_INVALID_LEVEL);
5354 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5355 SetLastError(RPC_X_NULL_REF_POINTER);
5359 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5362 /******************************************************************************
5363 * GetDefaultPrinterW (WINSPOOL.@)
5366 * This function must read the value from data 'device' of key
5367 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5369 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5373 WCHAR *buffer, *ptr;
5377 SetLastError(ERROR_INVALID_PARAMETER);
5381 /* make the buffer big enough for the stuff from the profile/registry,
5382 * the content must fit into the local buffer to compute the correct
5383 * size even if the extern buffer is too small or not given.
5384 * (20 for ,driver,port) */
5386 len = max(100, (insize + 20));
5387 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5389 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5391 SetLastError (ERROR_FILE_NOT_FOUND);
5395 TRACE("%s\n", debugstr_w(buffer));
5397 if ((ptr = strchrW(buffer, ',')) == NULL)
5399 SetLastError(ERROR_INVALID_NAME);
5405 *namesize = strlenW(buffer) + 1;
5406 if(!name || (*namesize > insize))
5408 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5412 strcpyW(name, buffer);
5415 HeapFree( GetProcessHeap(), 0, buffer);
5420 /******************************************************************************
5421 * GetDefaultPrinterA (WINSPOOL.@)
5423 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5427 WCHAR *bufferW = NULL;
5431 SetLastError(ERROR_INVALID_PARAMETER);
5435 if(name && *namesize) {
5437 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5440 if(!GetDefaultPrinterW( bufferW, namesize)) {
5445 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5449 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5452 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5455 HeapFree( GetProcessHeap(), 0, bufferW);
5460 /******************************************************************************
5461 * SetDefaultPrinterW (WINSPOOL.204)
5463 * Set the Name of the Default Printer
5466 * pszPrinter [I] Name of the Printer or NULL
5473 * When the Parameter is NULL or points to an Empty String and
5474 * a Default Printer was already present, then this Function changes nothing.
5475 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5476 * the First enumerated local Printer is used.
5479 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5481 WCHAR default_printer[MAX_PATH];
5482 LPWSTR buffer = NULL;
5488 TRACE("(%s)\n", debugstr_w(pszPrinter));
5489 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5491 default_printer[0] = '\0';
5492 size = sizeof(default_printer)/sizeof(WCHAR);
5494 /* if we have a default Printer, do nothing. */
5495 if (GetDefaultPrinterW(default_printer, &size))
5499 /* we have no default Printer: search local Printers and use the first */
5500 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5502 default_printer[0] = '\0';
5503 size = sizeof(default_printer)/sizeof(WCHAR);
5504 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5506 pszPrinter = default_printer;
5507 TRACE("using %s\n", debugstr_w(pszPrinter));
5512 if (pszPrinter == NULL) {
5513 TRACE("no local printer found\n");
5514 SetLastError(ERROR_FILE_NOT_FOUND);
5519 /* "pszPrinter" is never empty or NULL here. */
5520 namelen = lstrlenW(pszPrinter);
5521 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5522 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5524 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5525 HeapFree(GetProcessHeap(), 0, buffer);
5526 SetLastError(ERROR_FILE_NOT_FOUND);
5530 /* read the devices entry for the printer (driver,port) to build the string for the
5531 default device entry (printer,driver,port) */
5532 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5533 buffer[namelen] = ',';
5534 namelen++; /* move index to the start of the driver */
5536 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5537 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5539 TRACE("set device to %s\n", debugstr_w(buffer));
5541 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5542 TRACE("failed to set the device entry: %d\n", GetLastError());
5543 lres = ERROR_INVALID_PRINTER_NAME;
5546 /* remove the next section, when INIFileMapping is implemented */
5549 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5550 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5557 if (lres != ERROR_FILE_NOT_FOUND)
5558 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5560 SetLastError(ERROR_INVALID_PRINTER_NAME);
5564 HeapFree(GetProcessHeap(), 0, buffer);
5565 return (lres == ERROR_SUCCESS);
5568 /******************************************************************************
5569 * SetDefaultPrinterA (WINSPOOL.202)
5571 * See SetDefaultPrinterW.
5574 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5576 LPWSTR bufferW = NULL;
5579 TRACE("(%s)\n", debugstr_a(pszPrinter));
5581 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5582 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5583 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5585 res = SetDefaultPrinterW(bufferW);
5586 HeapFree(GetProcessHeap(), 0, bufferW);
5590 /******************************************************************************
5591 * SetPrinterDataExA (WINSPOOL.@)
5593 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5594 LPCSTR pValueName, DWORD Type,
5595 LPBYTE pData, DWORD cbData)
5597 HKEY hkeyPrinter, hkeySubkey;
5600 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5601 debugstr_a(pValueName), Type, pData, cbData);
5603 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5607 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5609 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5610 RegCloseKey(hkeyPrinter);
5613 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5614 RegCloseKey(hkeySubkey);
5615 RegCloseKey(hkeyPrinter);
5619 /******************************************************************************
5620 * SetPrinterDataExW (WINSPOOL.@)
5622 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5623 LPCWSTR pValueName, DWORD Type,
5624 LPBYTE pData, DWORD cbData)
5626 HKEY hkeyPrinter, hkeySubkey;
5629 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5630 debugstr_w(pValueName), Type, pData, cbData);
5632 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5636 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5638 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5639 RegCloseKey(hkeyPrinter);
5642 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5643 RegCloseKey(hkeySubkey);
5644 RegCloseKey(hkeyPrinter);
5648 /******************************************************************************
5649 * SetPrinterDataA (WINSPOOL.@)
5651 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5652 LPBYTE pData, DWORD cbData)
5654 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5658 /******************************************************************************
5659 * SetPrinterDataW (WINSPOOL.@)
5661 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5662 LPBYTE pData, DWORD cbData)
5664 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5668 /******************************************************************************
5669 * GetPrinterDataExA (WINSPOOL.@)
5671 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5672 LPCSTR pValueName, LPDWORD pType,
5673 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5675 opened_printer_t *printer;
5676 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5679 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5680 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5682 printer = get_opened_printer(hPrinter);
5683 if(!printer) return ERROR_INVALID_HANDLE;
5685 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5686 if (ret) return ret;
5688 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5690 if (printer->name) {
5692 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5694 RegCloseKey(hkeyPrinters);
5697 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5698 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5699 RegCloseKey(hkeyPrinter);
5700 RegCloseKey(hkeyPrinters);
5705 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5706 0, pType, pData, pcbNeeded);
5708 if (!ret && !pData) ret = ERROR_MORE_DATA;
5710 RegCloseKey(hkeySubkey);
5711 RegCloseKey(hkeyPrinter);
5712 RegCloseKey(hkeyPrinters);
5714 TRACE("--> %d\n", ret);
5718 /******************************************************************************
5719 * GetPrinterDataExW (WINSPOOL.@)
5721 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5722 LPCWSTR pValueName, LPDWORD pType,
5723 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5725 opened_printer_t *printer;
5726 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5729 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5730 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5732 printer = get_opened_printer(hPrinter);
5733 if(!printer) return ERROR_INVALID_HANDLE;
5735 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5736 if (ret) return ret;
5738 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5740 if (printer->name) {
5742 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5744 RegCloseKey(hkeyPrinters);
5747 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5748 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5749 RegCloseKey(hkeyPrinter);
5750 RegCloseKey(hkeyPrinters);
5755 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5756 0, pType, pData, pcbNeeded);
5758 if (!ret && !pData) ret = ERROR_MORE_DATA;
5760 RegCloseKey(hkeySubkey);
5761 RegCloseKey(hkeyPrinter);
5762 RegCloseKey(hkeyPrinters);
5764 TRACE("--> %d\n", ret);
5768 /******************************************************************************
5769 * GetPrinterDataA (WINSPOOL.@)
5771 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5772 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5774 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5775 pData, nSize, pcbNeeded);
5778 /******************************************************************************
5779 * GetPrinterDataW (WINSPOOL.@)
5781 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5782 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5784 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5785 pData, nSize, pcbNeeded);
5788 /*******************************************************************************
5789 * EnumPrinterDataExW [WINSPOOL.@]
5791 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5792 LPBYTE pEnumValues, DWORD cbEnumValues,
5793 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5795 HKEY hkPrinter, hkSubKey;
5796 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5797 cbValueNameLen, cbMaxValueLen, cbValueLen,
5802 PPRINTER_ENUM_VALUESW ppev;
5804 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5806 if (pKeyName == NULL || *pKeyName == 0)
5807 return ERROR_INVALID_PARAMETER;
5809 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5810 if (ret != ERROR_SUCCESS)
5812 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5817 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5818 if (ret != ERROR_SUCCESS)
5820 r = RegCloseKey (hkPrinter);
5821 if (r != ERROR_SUCCESS)
5822 WARN ("RegCloseKey returned %i\n", r);
5823 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5824 debugstr_w (pKeyName), ret);
5828 ret = RegCloseKey (hkPrinter);
5829 if (ret != ERROR_SUCCESS)
5831 ERR ("RegCloseKey returned %i\n", ret);
5832 r = RegCloseKey (hkSubKey);
5833 if (r != ERROR_SUCCESS)
5834 WARN ("RegCloseKey returned %i\n", r);
5838 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5839 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5840 if (ret != ERROR_SUCCESS)
5842 r = RegCloseKey (hkSubKey);
5843 if (r != ERROR_SUCCESS)
5844 WARN ("RegCloseKey returned %i\n", r);
5845 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5849 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5850 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5852 if (cValues == 0) /* empty key */
5854 r = RegCloseKey (hkSubKey);
5855 if (r != ERROR_SUCCESS)
5856 WARN ("RegCloseKey returned %i\n", r);
5857 *pcbEnumValues = *pnEnumValues = 0;
5858 return ERROR_SUCCESS;
5861 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5863 hHeap = GetProcessHeap ();
5866 ERR ("GetProcessHeap failed\n");
5867 r = RegCloseKey (hkSubKey);
5868 if (r != ERROR_SUCCESS)
5869 WARN ("RegCloseKey returned %i\n", r);
5870 return ERROR_OUTOFMEMORY;
5873 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5874 if (lpValueName == NULL)
5876 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5877 r = RegCloseKey (hkSubKey);
5878 if (r != ERROR_SUCCESS)
5879 WARN ("RegCloseKey returned %i\n", r);
5880 return ERROR_OUTOFMEMORY;
5883 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5884 if (lpValue == NULL)
5886 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5887 if (HeapFree (hHeap, 0, lpValueName) == 0)
5888 WARN ("HeapFree failed with code %i\n", GetLastError ());
5889 r = RegCloseKey (hkSubKey);
5890 if (r != ERROR_SUCCESS)
5891 WARN ("RegCloseKey returned %i\n", r);
5892 return ERROR_OUTOFMEMORY;
5895 TRACE ("pass 1: calculating buffer required for all names and values\n");
5897 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5899 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5901 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5903 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5904 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5905 NULL, NULL, lpValue, &cbValueLen);
5906 if (ret != ERROR_SUCCESS)
5908 if (HeapFree (hHeap, 0, lpValue) == 0)
5909 WARN ("HeapFree failed with code %i\n", GetLastError ());
5910 if (HeapFree (hHeap, 0, lpValueName) == 0)
5911 WARN ("HeapFree failed with code %i\n", GetLastError ());
5912 r = RegCloseKey (hkSubKey);
5913 if (r != ERROR_SUCCESS)
5914 WARN ("RegCloseKey returned %i\n", r);
5915 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5919 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5920 debugstr_w (lpValueName), dwIndex,
5921 cbValueNameLen + 1, cbValueLen);
5923 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5924 cbBufSize += cbValueLen;
5927 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5929 *pcbEnumValues = cbBufSize;
5930 *pnEnumValues = cValues;
5932 if (cbEnumValues < cbBufSize) /* buffer too small */
5934 if (HeapFree (hHeap, 0, lpValue) == 0)
5935 WARN ("HeapFree failed with code %i\n", GetLastError ());
5936 if (HeapFree (hHeap, 0, lpValueName) == 0)
5937 WARN ("HeapFree failed with code %i\n", GetLastError ());
5938 r = RegCloseKey (hkSubKey);
5939 if (r != ERROR_SUCCESS)
5940 WARN ("RegCloseKey returned %i\n", r);
5941 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5942 return ERROR_MORE_DATA;
5945 TRACE ("pass 2: copying all names and values to buffer\n");
5947 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5948 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5950 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5952 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5953 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5954 NULL, &dwType, lpValue, &cbValueLen);
5955 if (ret != ERROR_SUCCESS)
5957 if (HeapFree (hHeap, 0, lpValue) == 0)
5958 WARN ("HeapFree failed with code %i\n", GetLastError ());
5959 if (HeapFree (hHeap, 0, lpValueName) == 0)
5960 WARN ("HeapFree failed with code %i\n", GetLastError ());
5961 r = RegCloseKey (hkSubKey);
5962 if (r != ERROR_SUCCESS)
5963 WARN ("RegCloseKey returned %i\n", r);
5964 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5968 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5969 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5970 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5971 pEnumValues += cbValueNameLen;
5973 /* return # of *bytes* (including trailing \0), not # of chars */
5974 ppev[dwIndex].cbValueName = cbValueNameLen;
5976 ppev[dwIndex].dwType = dwType;
5978 memcpy (pEnumValues, lpValue, cbValueLen);
5979 ppev[dwIndex].pData = pEnumValues;
5980 pEnumValues += cbValueLen;
5982 ppev[dwIndex].cbData = cbValueLen;
5984 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5985 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5988 if (HeapFree (hHeap, 0, lpValue) == 0)
5990 ret = GetLastError ();
5991 ERR ("HeapFree failed with code %i\n", ret);
5992 if (HeapFree (hHeap, 0, lpValueName) == 0)
5993 WARN ("HeapFree failed with code %i\n", GetLastError ());
5994 r = RegCloseKey (hkSubKey);
5995 if (r != ERROR_SUCCESS)
5996 WARN ("RegCloseKey returned %i\n", r);
6000 if (HeapFree (hHeap, 0, lpValueName) == 0)
6002 ret = GetLastError ();
6003 ERR ("HeapFree failed with code %i\n", ret);
6004 r = RegCloseKey (hkSubKey);
6005 if (r != ERROR_SUCCESS)
6006 WARN ("RegCloseKey returned %i\n", r);
6010 ret = RegCloseKey (hkSubKey);
6011 if (ret != ERROR_SUCCESS)
6013 ERR ("RegCloseKey returned %i\n", ret);
6017 return ERROR_SUCCESS;
6020 /*******************************************************************************
6021 * EnumPrinterDataExA [WINSPOOL.@]
6023 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6024 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6025 * what Windows 2000 SP1 does.
6028 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6029 LPBYTE pEnumValues, DWORD cbEnumValues,
6030 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6034 DWORD ret, dwIndex, dwBufSize;
6038 TRACE ("%p %s\n", hPrinter, pKeyName);
6040 if (pKeyName == NULL || *pKeyName == 0)
6041 return ERROR_INVALID_PARAMETER;
6043 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6046 ret = GetLastError ();
6047 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6051 hHeap = GetProcessHeap ();
6054 ERR ("GetProcessHeap failed\n");
6055 return ERROR_OUTOFMEMORY;
6058 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6059 if (pKeyNameW == NULL)
6061 ERR ("Failed to allocate %i bytes from process heap\n",
6062 (LONG)(len * sizeof (WCHAR)));
6063 return ERROR_OUTOFMEMORY;
6066 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6068 ret = GetLastError ();
6069 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6070 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6071 WARN ("HeapFree failed with code %i\n", GetLastError ());
6075 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6076 pcbEnumValues, pnEnumValues);
6077 if (ret != ERROR_SUCCESS)
6079 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6080 WARN ("HeapFree failed with code %i\n", GetLastError ());
6081 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6085 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6087 ret = GetLastError ();
6088 ERR ("HeapFree failed with code %i\n", ret);
6092 if (*pnEnumValues == 0) /* empty key */
6093 return ERROR_SUCCESS;
6096 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6098 PPRINTER_ENUM_VALUESW ppev =
6099 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6101 if (dwBufSize < ppev->cbValueName)
6102 dwBufSize = ppev->cbValueName;
6104 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6105 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6106 dwBufSize = ppev->cbData;
6109 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6111 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6112 if (pBuffer == NULL)
6114 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6115 return ERROR_OUTOFMEMORY;
6118 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6120 PPRINTER_ENUM_VALUESW ppev =
6121 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6123 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6124 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6128 ret = GetLastError ();
6129 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6130 if (HeapFree (hHeap, 0, pBuffer) == 0)
6131 WARN ("HeapFree failed with code %i\n", GetLastError ());
6135 memcpy (ppev->pValueName, pBuffer, len);
6137 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6139 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6140 ppev->dwType != REG_MULTI_SZ)
6143 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6144 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6147 ret = GetLastError ();
6148 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6149 if (HeapFree (hHeap, 0, pBuffer) == 0)
6150 WARN ("HeapFree failed with code %i\n", GetLastError ());
6154 memcpy (ppev->pData, pBuffer, len);
6156 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6157 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6160 if (HeapFree (hHeap, 0, pBuffer) == 0)
6162 ret = GetLastError ();
6163 ERR ("HeapFree failed with code %i\n", ret);
6167 return ERROR_SUCCESS;
6170 /******************************************************************************
6171 * AbortPrinter (WINSPOOL.@)
6173 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6175 FIXME("(%p), stub!\n", hPrinter);
6179 /******************************************************************************
6180 * AddPortA (WINSPOOL.@)
6185 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6187 LPWSTR nameW = NULL;
6188 LPWSTR monitorW = NULL;
6192 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6195 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6196 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6197 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6201 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6202 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6203 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6205 res = AddPortW(nameW, hWnd, monitorW);
6206 HeapFree(GetProcessHeap(), 0, nameW);
6207 HeapFree(GetProcessHeap(), 0, monitorW);
6211 /******************************************************************************
6212 * AddPortW (WINSPOOL.@)
6214 * Add a Port for a specific Monitor
6217 * pName [I] Servername or NULL (local Computer)
6218 * hWnd [I] Handle to parent Window for the Dialog-Box
6219 * pMonitorName [I] Name of the Monitor that manage the Port
6226 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6228 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6230 if ((backend == NULL) && !load_backend()) return FALSE;
6232 if (!pMonitorName) {
6233 SetLastError(RPC_X_NULL_REF_POINTER);
6237 return backend->fpAddPort(pName, hWnd, pMonitorName);
6240 /******************************************************************************
6241 * AddPortExA (WINSPOOL.@)
6246 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6249 PORT_INFO_2A * pi2A;
6250 LPWSTR nameW = NULL;
6251 LPWSTR monitorW = NULL;
6255 pi2A = (PORT_INFO_2A *) pBuffer;
6257 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6258 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6260 if ((level < 1) || (level > 2)) {
6261 SetLastError(ERROR_INVALID_LEVEL);
6266 SetLastError(ERROR_INVALID_PARAMETER);
6271 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6272 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6273 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6277 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6278 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6279 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6282 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6284 if (pi2A->pPortName) {
6285 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6286 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6287 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6291 if (pi2A->pMonitorName) {
6292 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6293 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6294 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6297 if (pi2A->pDescription) {
6298 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6299 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6300 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6302 pi2W.fPortType = pi2A->fPortType;
6303 pi2W.Reserved = pi2A->Reserved;
6306 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6308 HeapFree(GetProcessHeap(), 0, nameW);
6309 HeapFree(GetProcessHeap(), 0, monitorW);
6310 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6311 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6312 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6317 /******************************************************************************
6318 * AddPortExW (WINSPOOL.@)
6320 * Add a Port for a specific Monitor, without presenting a user interface
6323 * pName [I] Servername or NULL (local Computer)
6324 * level [I] Structure-Level (1 or 2) for pBuffer
6325 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6326 * pMonitorName [I] Name of the Monitor that manage the Port
6333 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6337 pi2 = (PORT_INFO_2W *) pBuffer;
6339 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6340 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6341 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6342 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6344 if ((backend == NULL) && !load_backend()) return FALSE;
6346 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6347 SetLastError(ERROR_INVALID_PARAMETER);
6351 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6354 /******************************************************************************
6355 * AddPrinterConnectionA (WINSPOOL.@)
6357 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6359 FIXME("%s\n", debugstr_a(pName));
6363 /******************************************************************************
6364 * AddPrinterConnectionW (WINSPOOL.@)
6366 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6368 FIXME("%s\n", debugstr_w(pName));
6372 /******************************************************************************
6373 * AddPrinterDriverExW (WINSPOOL.@)
6375 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6378 * pName [I] Servername or NULL (local Computer)
6379 * level [I] Level for the supplied DRIVER_INFO_*W struct
6380 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6381 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6388 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6390 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6392 if ((backend == NULL) && !load_backend()) return FALSE;
6394 if (level < 2 || level == 5 || level == 7 || level > 8) {
6395 SetLastError(ERROR_INVALID_LEVEL);
6400 SetLastError(ERROR_INVALID_PARAMETER);
6404 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6407 /******************************************************************************
6408 * AddPrinterDriverExA (WINSPOOL.@)
6410 * See AddPrinterDriverExW.
6413 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6415 DRIVER_INFO_8A *diA;
6417 LPWSTR nameW = NULL;
6422 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6424 diA = (DRIVER_INFO_8A *) pDriverInfo;
6425 ZeroMemory(&diW, sizeof(diW));
6427 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6428 SetLastError(ERROR_INVALID_LEVEL);
6433 SetLastError(ERROR_INVALID_PARAMETER);
6437 /* convert servername to unicode */
6439 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6440 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6441 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6445 diW.cVersion = diA->cVersion;
6448 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6449 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6450 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6453 if (diA->pEnvironment) {
6454 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6455 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6456 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6459 if (diA->pDriverPath) {
6460 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6461 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6462 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6465 if (diA->pDataFile) {
6466 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6467 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6468 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6471 if (diA->pConfigFile) {
6472 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6473 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6474 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6477 if ((Level > 2) && diA->pDependentFiles) {
6478 lenA = multi_sz_lenA(diA->pDependentFiles);
6479 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6480 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6481 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6484 if ((Level > 2) && diA->pMonitorName) {
6485 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6486 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6487 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6490 if ((Level > 3) && diA->pDefaultDataType) {
6491 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6492 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6493 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6496 if ((Level > 3) && diA->pszzPreviousNames) {
6497 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6498 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6499 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6500 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6503 if ((Level > 5) && diA->pszMfgName) {
6504 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6505 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6506 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6509 if ((Level > 5) && diA->pszOEMUrl) {
6510 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6511 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6512 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6515 if ((Level > 5) && diA->pszHardwareID) {
6516 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6517 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6518 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6521 if ((Level > 5) && diA->pszProvider) {
6522 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6523 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6524 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6528 FIXME("level %u is incomplete\n", Level);
6531 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6532 TRACE("got %u with %u\n", res, GetLastError());
6533 HeapFree(GetProcessHeap(), 0, nameW);
6534 HeapFree(GetProcessHeap(), 0, diW.pName);
6535 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6536 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6537 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6538 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6539 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6540 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6541 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6542 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6543 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6544 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6545 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6546 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6548 TRACE("=> %u with %u\n", res, GetLastError());
6552 /******************************************************************************
6553 * ConfigurePortA (WINSPOOL.@)
6555 * See ConfigurePortW.
6558 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6560 LPWSTR nameW = NULL;
6561 LPWSTR portW = NULL;
6565 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6567 /* convert servername to unicode */
6569 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6570 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6571 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6574 /* convert portname to unicode */
6576 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6577 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6578 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6581 res = ConfigurePortW(nameW, hWnd, portW);
6582 HeapFree(GetProcessHeap(), 0, nameW);
6583 HeapFree(GetProcessHeap(), 0, portW);
6587 /******************************************************************************
6588 * ConfigurePortW (WINSPOOL.@)
6590 * Display the Configuration-Dialog for a specific Port
6593 * pName [I] Servername or NULL (local Computer)
6594 * hWnd [I] Handle to parent Window for the Dialog-Box
6595 * pPortName [I] Name of the Port, that should be configured
6602 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6605 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6607 if ((backend == NULL) && !load_backend()) return FALSE;
6610 SetLastError(RPC_X_NULL_REF_POINTER);
6614 return backend->fpConfigurePort(pName, hWnd, pPortName);
6617 /******************************************************************************
6618 * ConnectToPrinterDlg (WINSPOOL.@)
6620 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6622 FIXME("%p %x\n", hWnd, Flags);
6626 /******************************************************************************
6627 * DeletePrinterConnectionA (WINSPOOL.@)
6629 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6631 FIXME("%s\n", debugstr_a(pName));
6635 /******************************************************************************
6636 * DeletePrinterConnectionW (WINSPOOL.@)
6638 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6640 FIXME("%s\n", debugstr_w(pName));
6644 /******************************************************************************
6645 * DeletePrinterDriverExW (WINSPOOL.@)
6647 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6648 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6653 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6654 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6656 if(pName && pName[0])
6658 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6659 SetLastError(ERROR_INVALID_PARAMETER);
6665 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6666 SetLastError(ERROR_INVALID_PARAMETER);
6670 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6674 ERR("Can't open drivers key\n");
6678 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6681 RegCloseKey(hkey_drivers);
6686 /******************************************************************************
6687 * DeletePrinterDriverExA (WINSPOOL.@)
6689 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6690 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6692 UNICODE_STRING NameW, EnvW, DriverW;
6695 asciitounicode(&NameW, pName);
6696 asciitounicode(&EnvW, pEnvironment);
6697 asciitounicode(&DriverW, pDriverName);
6699 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6701 RtlFreeUnicodeString(&DriverW);
6702 RtlFreeUnicodeString(&EnvW);
6703 RtlFreeUnicodeString(&NameW);
6708 /******************************************************************************
6709 * DeletePrinterDataExW (WINSPOOL.@)
6711 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6714 FIXME("%p %s %s\n", hPrinter,
6715 debugstr_w(pKeyName), debugstr_w(pValueName));
6716 return ERROR_INVALID_PARAMETER;
6719 /******************************************************************************
6720 * DeletePrinterDataExA (WINSPOOL.@)
6722 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6725 FIXME("%p %s %s\n", hPrinter,
6726 debugstr_a(pKeyName), debugstr_a(pValueName));
6727 return ERROR_INVALID_PARAMETER;
6730 /******************************************************************************
6731 * DeletePrintProcessorA (WINSPOOL.@)
6733 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6735 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6736 debugstr_a(pPrintProcessorName));
6740 /******************************************************************************
6741 * DeletePrintProcessorW (WINSPOOL.@)
6743 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6745 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6746 debugstr_w(pPrintProcessorName));
6750 /******************************************************************************
6751 * DeletePrintProvidorA (WINSPOOL.@)
6753 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6755 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6756 debugstr_a(pPrintProviderName));
6760 /******************************************************************************
6761 * DeletePrintProvidorW (WINSPOOL.@)
6763 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6765 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6766 debugstr_w(pPrintProviderName));
6770 /******************************************************************************
6771 * EnumFormsA (WINSPOOL.@)
6773 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6774 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6776 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6777 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6781 /******************************************************************************
6782 * EnumFormsW (WINSPOOL.@)
6784 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6785 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6787 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6788 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6792 /*****************************************************************************
6793 * EnumMonitorsA [WINSPOOL.@]
6795 * See EnumMonitorsW.
6798 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6799 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6802 LPBYTE bufferW = NULL;
6803 LPWSTR nameW = NULL;
6805 DWORD numentries = 0;
6808 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6809 cbBuf, pcbNeeded, pcReturned);
6811 /* convert servername to unicode */
6813 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6814 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6815 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6817 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6818 needed = cbBuf * sizeof(WCHAR);
6819 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6820 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6822 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6823 if (pcbNeeded) needed = *pcbNeeded;
6824 /* HeapReAlloc return NULL, when bufferW was NULL */
6825 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6826 HeapAlloc(GetProcessHeap(), 0, needed);
6828 /* Try again with the large Buffer */
6829 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6831 numentries = pcReturned ? *pcReturned : 0;
6834 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6835 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6838 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6839 DWORD entrysize = 0;
6842 LPMONITOR_INFO_2W mi2w;
6843 LPMONITOR_INFO_2A mi2a;
6845 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6846 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6848 /* First pass: calculate the size for all Entries */
6849 mi2w = (LPMONITOR_INFO_2W) bufferW;
6850 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6852 while (index < numentries) {
6854 needed += entrysize; /* MONITOR_INFO_?A */
6855 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6857 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6858 NULL, 0, NULL, NULL);
6860 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6861 NULL, 0, NULL, NULL);
6862 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6863 NULL, 0, NULL, NULL);
6865 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6866 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6867 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6870 /* check for errors and quit on failure */
6871 if (cbBuf < needed) {
6872 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6876 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6877 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6878 cbBuf -= len ; /* free Bytes in the user-Buffer */
6879 mi2w = (LPMONITOR_INFO_2W) bufferW;
6880 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6882 /* Second Pass: Fill the User Buffer (if we have one) */
6883 while ((index < numentries) && pMonitors) {
6885 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6887 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6888 ptr, cbBuf , NULL, NULL);
6892 mi2a->pEnvironment = ptr;
6893 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6894 ptr, cbBuf, NULL, NULL);
6898 mi2a->pDLLName = ptr;
6899 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6900 ptr, cbBuf, NULL, NULL);
6904 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6905 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6906 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6910 if (pcbNeeded) *pcbNeeded = needed;
6911 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6913 HeapFree(GetProcessHeap(), 0, nameW);
6914 HeapFree(GetProcessHeap(), 0, bufferW);
6916 TRACE("returning %d with %d (%d byte for %d entries)\n",
6917 (res), GetLastError(), needed, numentries);
6923 /*****************************************************************************
6924 * EnumMonitorsW [WINSPOOL.@]
6926 * Enumerate available Port-Monitors
6929 * pName [I] Servername or NULL (local Computer)
6930 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6931 * pMonitors [O] PTR to Buffer that receives the Result
6932 * cbBuf [I] Size of Buffer at pMonitors
6933 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6934 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6938 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6941 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6942 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6945 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6946 cbBuf, pcbNeeded, pcReturned);
6948 if ((backend == NULL) && !load_backend()) return FALSE;
6950 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6951 SetLastError(RPC_X_NULL_REF_POINTER);
6955 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6958 /******************************************************************************
6959 * SpoolerInit (WINSPOOL.@)
6961 * Initialize the Spooler
6968 * The function fails on windows, when the spooler service is not running
6971 BOOL WINAPI SpoolerInit(void)
6974 if ((backend == NULL) && !load_backend()) return FALSE;
6978 /******************************************************************************
6979 * XcvDataW (WINSPOOL.@)
6981 * Execute commands in the Printmonitor DLL
6984 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6985 * pszDataName [i] Name of the command to execute
6986 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6987 * cbInputData [i] Size in Bytes of Buffer at pInputData
6988 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6989 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6990 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6991 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6998 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6999 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7001 * Minimal List of commands, that a Printmonitor DLL should support:
7003 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7004 *| "AddPort" : Add a Port
7005 *| "DeletePort": Delete a Port
7007 * Many Printmonitors support additional commands. Examples for localspl.dll:
7008 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7009 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7012 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7013 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7014 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7016 opened_printer_t *printer;
7018 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7019 pInputData, cbInputData, pOutputData,
7020 cbOutputData, pcbOutputNeeded, pdwStatus);
7022 if ((backend == NULL) && !load_backend()) return FALSE;
7024 printer = get_opened_printer(hXcv);
7025 if (!printer || (!printer->backend_printer)) {
7026 SetLastError(ERROR_INVALID_HANDLE);
7030 if (!pcbOutputNeeded) {
7031 SetLastError(ERROR_INVALID_PARAMETER);
7035 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7036 SetLastError(RPC_X_NULL_REF_POINTER);
7040 *pcbOutputNeeded = 0;
7042 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7043 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7047 /*****************************************************************************
7048 * EnumPrinterDataA [WINSPOOL.@]
7051 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7052 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7053 DWORD cbData, LPDWORD pcbData )
7055 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7056 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7057 return ERROR_NO_MORE_ITEMS;
7060 /*****************************************************************************
7061 * EnumPrinterDataW [WINSPOOL.@]
7064 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7065 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7066 DWORD cbData, LPDWORD pcbData )
7068 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7069 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7070 return ERROR_NO_MORE_ITEMS;
7073 /*****************************************************************************
7074 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7077 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7078 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7079 LPDWORD pcbNeeded, LPDWORD pcReturned)
7081 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7082 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7083 pcbNeeded, pcReturned);
7087 /*****************************************************************************
7088 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7091 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7092 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7093 LPDWORD pcbNeeded, LPDWORD pcReturned)
7095 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7096 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7097 pcbNeeded, pcReturned);
7101 /*****************************************************************************
7102 * EnumPrintProcessorsA [WINSPOOL.@]
7104 * See EnumPrintProcessorsW.
7107 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7108 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7111 LPBYTE bufferW = NULL;
7112 LPWSTR nameW = NULL;
7115 DWORD numentries = 0;
7118 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7119 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7121 /* convert names to unicode */
7123 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7124 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7125 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7128 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7129 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7130 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7133 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7134 needed = cbBuf * sizeof(WCHAR);
7135 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7136 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7138 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7139 if (pcbNeeded) needed = *pcbNeeded;
7140 /* HeapReAlloc return NULL, when bufferW was NULL */
7141 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7142 HeapAlloc(GetProcessHeap(), 0, needed);
7144 /* Try again with the large Buffer */
7145 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7147 numentries = pcReturned ? *pcReturned : 0;
7151 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7154 PPRINTPROCESSOR_INFO_1W ppiw;
7155 PPRINTPROCESSOR_INFO_1A ppia;
7157 /* First pass: calculate the size for all Entries */
7158 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7159 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7161 while (index < numentries) {
7163 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7164 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7166 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7167 NULL, 0, NULL, NULL);
7169 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7170 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7173 /* check for errors and quit on failure */
7174 if (cbBuf < needed) {
7175 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7180 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7181 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7182 cbBuf -= len ; /* free Bytes in the user-Buffer */
7183 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7184 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7186 /* Second Pass: Fill the User Buffer (if we have one) */
7187 while ((index < numentries) && pPPInfo) {
7189 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7191 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7192 ptr, cbBuf , NULL, NULL);
7196 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7197 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7202 if (pcbNeeded) *pcbNeeded = needed;
7203 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7205 HeapFree(GetProcessHeap(), 0, nameW);
7206 HeapFree(GetProcessHeap(), 0, envW);
7207 HeapFree(GetProcessHeap(), 0, bufferW);
7209 TRACE("returning %d with %d (%d byte for %d entries)\n",
7210 (res), GetLastError(), needed, numentries);
7215 /*****************************************************************************
7216 * EnumPrintProcessorsW [WINSPOOL.@]
7218 * Enumerate available Print Processors
7221 * pName [I] Servername or NULL (local Computer)
7222 * pEnvironment [I] Printing-Environment or NULL (Default)
7223 * Level [I] Structure-Level (Only 1 is allowed)
7224 * pPPInfo [O] PTR to Buffer that receives the Result
7225 * cbBuf [I] Size of Buffer at pPPInfo
7226 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7227 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7231 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7234 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7235 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7238 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7239 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7241 if ((backend == NULL) && !load_backend()) return FALSE;
7243 if (!pcbNeeded || !pcReturned) {
7244 SetLastError(RPC_X_NULL_REF_POINTER);
7248 if (!pPPInfo && (cbBuf > 0)) {
7249 SetLastError(ERROR_INVALID_USER_BUFFER);
7253 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7254 cbBuf, pcbNeeded, pcReturned);
7257 /*****************************************************************************
7258 * ExtDeviceMode [WINSPOOL.@]
7261 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7262 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7265 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7266 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7267 debugstr_a(pProfile), fMode);
7271 /*****************************************************************************
7272 * FindClosePrinterChangeNotification [WINSPOOL.@]
7275 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7277 FIXME("Stub: %p\n", hChange);
7281 /*****************************************************************************
7282 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7285 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7286 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7288 FIXME("Stub: %p %x %x %p\n",
7289 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7290 return INVALID_HANDLE_VALUE;
7293 /*****************************************************************************
7294 * FindNextPrinterChangeNotification [WINSPOOL.@]
7297 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7298 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7300 FIXME("Stub: %p %p %p %p\n",
7301 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7305 /*****************************************************************************
7306 * FreePrinterNotifyInfo [WINSPOOL.@]
7309 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7311 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7315 /*****************************************************************************
7318 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7319 * ansi depending on the unicode parameter.
7321 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7331 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7334 memcpy(ptr, str, *size);
7341 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7344 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7351 /*****************************************************************************
7354 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7355 LPDWORD pcbNeeded, BOOL unicode)
7357 DWORD size, left = cbBuf;
7358 BOOL space = (cbBuf > 0);
7365 ji1->JobId = job->job_id;
7368 string_to_buf(job->document_title, ptr, left, &size, unicode);
7369 if(space && size <= left)
7371 ji1->pDocument = (LPWSTR)ptr;
7379 if (job->printer_name)
7381 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7382 if(space && size <= left)
7384 ji1->pPrinterName = (LPWSTR)ptr;
7396 /*****************************************************************************
7399 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7400 LPDWORD pcbNeeded, BOOL unicode)
7402 DWORD size, left = cbBuf;
7404 BOOL space = (cbBuf > 0);
7406 LPDEVMODEA dmA = NULL;
7413 ji2->JobId = job->job_id;
7416 string_to_buf(job->document_title, ptr, left, &size, unicode);
7417 if(space && size <= left)
7419 ji2->pDocument = (LPWSTR)ptr;
7427 if (job->printer_name)
7429 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7430 if(space && size <= left)
7432 ji2->pPrinterName = (LPWSTR)ptr;
7445 dmA = DEVMODEdupWtoA(job->devmode);
7446 devmode = (LPDEVMODEW) dmA;
7447 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7451 devmode = job->devmode;
7452 size = devmode->dmSize + devmode->dmDriverExtra;
7456 FIXME("Can't convert DEVMODE W to A\n");
7459 /* align DEVMODE to a DWORD boundary */
7460 shift = (4 - (*pcbNeeded & 3)) & 3;
7466 memcpy(ptr, devmode, size-shift);
7467 ji2->pDevMode = (LPDEVMODEW)ptr;
7468 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7481 /*****************************************************************************
7484 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7485 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7488 DWORD needed = 0, size;
7492 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7494 EnterCriticalSection(&printer_handles_cs);
7495 job = get_job(hPrinter, JobId);
7502 size = sizeof(JOB_INFO_1W);
7507 memset(pJob, 0, size);
7511 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7516 size = sizeof(JOB_INFO_2W);
7521 memset(pJob, 0, size);
7525 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7530 size = sizeof(JOB_INFO_3);
7534 memset(pJob, 0, size);
7543 SetLastError(ERROR_INVALID_LEVEL);
7547 *pcbNeeded = needed;
7549 LeaveCriticalSection(&printer_handles_cs);
7553 /*****************************************************************************
7554 * GetJobA [WINSPOOL.@]
7557 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7558 DWORD cbBuf, LPDWORD pcbNeeded)
7560 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7563 /*****************************************************************************
7564 * GetJobW [WINSPOOL.@]
7567 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7568 DWORD cbBuf, LPDWORD pcbNeeded)
7570 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7573 /*****************************************************************************
7576 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7579 char *unixname, *cmdA;
7581 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7587 if(!(unixname = wine_get_unix_file_name(filename)))
7590 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7591 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7592 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7594 TRACE("printing with: %s\n", cmdA);
7596 if((file_fd = open(unixname, O_RDONLY)) == -1)
7601 ERR("pipe() failed!\n");
7605 if ((pid = fork()) == 0)
7611 /* reset signals that we previously set to SIG_IGN */
7612 signal(SIGPIPE, SIG_DFL);
7614 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7619 ERR("fork() failed!\n");
7623 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7624 write(fds[1], buf, no_read);
7631 wret = waitpid(pid, &status, 0);
7632 } while (wret < 0 && errno == EINTR);
7635 ERR("waitpid() failed!\n");
7638 if (!WIFEXITED(status) || WEXITSTATUS(status))
7640 ERR("child process failed! %d\n", status);
7647 if(file_fd != -1) close(file_fd);
7648 if(fds[0] != -1) close(fds[0]);
7649 if(fds[1] != -1) close(fds[1]);
7651 HeapFree(GetProcessHeap(), 0, cmdA);
7652 HeapFree(GetProcessHeap(), 0, unixname);
7659 /*****************************************************************************
7662 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7665 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7668 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7669 sprintfW(cmd, fmtW, printer_name);
7671 r = schedule_pipe(cmd, filename);
7673 HeapFree(GetProcessHeap(), 0, cmd);
7677 #ifdef SONAME_LIBCUPS
7678 /*****************************************************************************
7679 * get_cups_jobs_ticket_options
7681 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7682 * The CUPS scheduler only looks for these in Print-File requests, and since
7683 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7686 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7688 FILE *fp = fopen( file, "r" );
7689 char buf[257]; /* DSC max of 256 + '\0' */
7690 const char *ps_adobe = "%!PS-Adobe-";
7691 const char *cups_job = "%cupsJobTicket:";
7693 if (!fp) return num_options;
7694 if (!fgets( buf, sizeof(buf), fp )) goto end;
7695 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7696 while (fgets( buf, sizeof(buf), fp ))
7698 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7699 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7708 /*****************************************************************************
7711 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7713 #ifdef SONAME_LIBCUPS
7716 char *unixname, *queue, *unix_doc_title;
7719 int num_options = 0, i;
7720 cups_option_t *options = NULL;
7722 if(!(unixname = wine_get_unix_file_name(filename)))
7725 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7726 queue = HeapAlloc(GetProcessHeap(), 0, len);
7727 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7729 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7730 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7731 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7733 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7735 TRACE( "printing via cups with options:\n" );
7736 for (i = 0; i < num_options; i++)
7737 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7739 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7741 pcupsFreeOptions( num_options, options );
7743 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7744 HeapFree(GetProcessHeap(), 0, queue);
7745 HeapFree(GetProcessHeap(), 0, unixname);
7751 return schedule_lpr(printer_name, filename);
7755 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7762 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7766 if(HIWORD(wparam) == BN_CLICKED)
7768 if(LOWORD(wparam) == IDOK)
7771 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7774 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7775 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7777 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7779 WCHAR caption[200], message[200];
7782 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7783 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7784 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7785 if(mb_ret == IDCANCEL)
7787 HeapFree(GetProcessHeap(), 0, filename);
7791 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7792 if(hf == INVALID_HANDLE_VALUE)
7794 WCHAR caption[200], message[200];
7796 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7797 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7798 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7799 HeapFree(GetProcessHeap(), 0, filename);
7803 DeleteFileW(filename);
7804 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7806 EndDialog(hwnd, IDOK);
7809 if(LOWORD(wparam) == IDCANCEL)
7811 EndDialog(hwnd, IDCANCEL);
7820 /*****************************************************************************
7823 static BOOL get_filename(LPWSTR *filename)
7825 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7826 file_dlg_proc, (LPARAM)filename) == IDOK;
7829 /*****************************************************************************
7832 static BOOL schedule_file(LPCWSTR filename)
7834 LPWSTR output = NULL;
7836 if(get_filename(&output))
7839 TRACE("copy to %s\n", debugstr_w(output));
7840 r = CopyFileW(filename, output, FALSE);
7841 HeapFree(GetProcessHeap(), 0, output);
7847 /*****************************************************************************
7850 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7852 int in_fd, out_fd, no_read;
7855 char *unixname, *outputA;
7858 if(!(unixname = wine_get_unix_file_name(filename)))
7861 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7862 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7863 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7865 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7866 in_fd = open(unixname, O_RDONLY);
7867 if(out_fd == -1 || in_fd == -1)
7870 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7871 write(out_fd, buf, no_read);
7875 if(in_fd != -1) close(in_fd);
7876 if(out_fd != -1) close(out_fd);
7877 HeapFree(GetProcessHeap(), 0, outputA);
7878 HeapFree(GetProcessHeap(), 0, unixname);
7882 /*****************************************************************************
7883 * ScheduleJob [WINSPOOL.@]
7886 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7888 opened_printer_t *printer;
7890 struct list *cursor, *cursor2;
7892 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7893 EnterCriticalSection(&printer_handles_cs);
7894 printer = get_opened_printer(hPrinter);
7898 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7900 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7903 if(job->job_id != dwJobID) continue;
7905 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7906 if(hf != INVALID_HANDLE_VALUE)
7908 PRINTER_INFO_5W *pi5 = NULL;
7909 LPWSTR portname = job->portname;
7913 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7914 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7918 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7919 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7920 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7921 portname = pi5->pPortName;
7923 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7924 debugstr_w(portname));
7928 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7929 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7931 DWORD type, count = sizeof(output);
7932 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7935 if(output[0] == '|')
7937 ret = schedule_pipe(output + 1, job->filename);
7941 ret = schedule_unixfile(output, job->filename);
7943 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7945 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7947 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7949 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7951 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7953 ret = schedule_file(job->filename);
7957 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7959 HeapFree(GetProcessHeap(), 0, pi5);
7961 DeleteFileW(job->filename);
7963 list_remove(cursor);
7964 HeapFree(GetProcessHeap(), 0, job->document_title);
7965 HeapFree(GetProcessHeap(), 0, job->printer_name);
7966 HeapFree(GetProcessHeap(), 0, job->portname);
7967 HeapFree(GetProcessHeap(), 0, job->filename);
7968 HeapFree(GetProcessHeap(), 0, job->devmode);
7969 HeapFree(GetProcessHeap(), 0, job);
7973 LeaveCriticalSection(&printer_handles_cs);
7977 /*****************************************************************************
7978 * StartDocDlgA [WINSPOOL.@]
7980 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7982 UNICODE_STRING usBuffer;
7985 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7988 docW.cbSize = sizeof(docW);
7989 if (doc->lpszDocName)
7991 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7992 if (!(docW.lpszDocName = docnameW)) return NULL;
7994 if (doc->lpszOutput)
7996 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7997 if (!(docW.lpszOutput = outputW)) return NULL;
7999 if (doc->lpszDatatype)
8001 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8002 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8004 docW.fwType = doc->fwType;
8006 retW = StartDocDlgW(hPrinter, &docW);
8010 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8011 ret = HeapAlloc(GetProcessHeap(), 0, len);
8012 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8013 HeapFree(GetProcessHeap(), 0, retW);
8016 HeapFree(GetProcessHeap(), 0, datatypeW);
8017 HeapFree(GetProcessHeap(), 0, outputW);
8018 HeapFree(GetProcessHeap(), 0, docnameW);
8023 /*****************************************************************************
8024 * StartDocDlgW [WINSPOOL.@]
8026 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8027 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8028 * port is "FILE:". Also returns the full path if passed a relative path.
8030 * The caller should free the returned string from the process heap.
8032 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8037 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8039 PRINTER_INFO_5W *pi5;
8040 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8041 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8043 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8044 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8045 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8047 HeapFree(GetProcessHeap(), 0, pi5);
8050 HeapFree(GetProcessHeap(), 0, pi5);
8053 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8057 if (get_filename(&name))
8059 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8061 HeapFree(GetProcessHeap(), 0, name);
8064 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8065 GetFullPathNameW(name, len, ret, NULL);
8066 HeapFree(GetProcessHeap(), 0, name);
8071 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8074 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8075 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8077 attr = GetFileAttributesW(ret);
8078 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8080 HeapFree(GetProcessHeap(), 0, ret);