winspool: Change get_dword_from_reg to accept a unicode value name.
[wine.git] / dlls / winspool.drv / info.c
blob481bad9f3b8b212b5a2080a27836346ab03bf6c4
1 /*
2 * WINSPOOL functions
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
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winuser.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "wingdi.h"
57 #include "winspool.h"
58 #include "winternl.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
63 #include "winnls.h"
65 #include "ddk/winsplp.h"
66 #include "wspool.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 /* ############################### */
83 typedef struct {
84 DWORD job_id;
85 HANDLE hf;
86 } started_doc_t;
88 typedef struct {
89 struct list jobs;
90 LONG ref;
91 } jobqueue_t;
93 typedef struct {
94 LPWSTR name;
95 LPWSTR printername;
96 HANDLE backend_printer;
97 jobqueue_t *queue;
98 started_doc_t *doc;
99 DEVMODEW *devmode;
100 } opened_printer_t;
102 typedef struct {
103 struct list entry;
104 DWORD job_id;
105 WCHAR *filename;
106 WCHAR *portname;
107 WCHAR *document_title;
108 WCHAR *printer_name;
109 LPDEVMODEW devmode;
110 } job_t;
113 typedef struct {
114 LPCWSTR envname;
115 LPCWSTR subdir;
116 DWORD driverversion;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
119 } printenv_t;
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,
129 LPDEVMODEA lpdm );
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
133 DWORD fwMode );
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 dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
199 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
200 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
201 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
202 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
203 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
204 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
205 static const WCHAR NameW[] = {'N','a','m','e',0};
206 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
207 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
208 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
209 static const WCHAR PortW[] = {'P','o','r','t',0};
210 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
211 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
212 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
213 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
214 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
215 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
216 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
217 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
218 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
219 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
221 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
222 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
223 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
224 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
225 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
226 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
227 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
228 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
229 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
230 static WCHAR rawW[] = {'R','A','W',0};
231 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
232 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
233 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
234 static const WCHAR commaW[] = {',',0};
235 static WCHAR emptyStringW[] = {0};
237 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
239 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
240 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
241 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
243 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
244 'D','o','c','u','m','e','n','t',0};
246 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
247 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
248 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
249 0, sizeof(DRIVER_INFO_8W)};
252 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
253 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
254 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
255 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
256 sizeof(PRINTER_INFO_9W)};
258 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
259 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
260 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
262 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
264 /******************************************************************
265 * validate the user-supplied printing-environment [internal]
267 * PARAMS
268 * env [I] PTR to Environment-String or NULL
270 * RETURNS
271 * Failure: NULL
272 * Success: PTR to printenv_t
274 * NOTES
275 * An empty string is handled the same way as NULL.
276 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
280 static const printenv_t * validate_envW(LPCWSTR env)
282 const printenv_t *result = NULL;
283 unsigned int i;
285 TRACE("testing %s\n", debugstr_w(env));
286 if (env && env[0])
288 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
290 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
292 result = all_printenv[i];
293 break;
297 if (result == NULL) {
298 FIXME("unsupported Environment: %s\n", debugstr_w(env));
299 SetLastError(ERROR_INVALID_ENVIRONMENT);
301 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
303 else
305 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
307 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
309 return result;
313 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
314 if passed a NULL string. This returns NULLs to the result.
316 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
318 if ( (src) )
320 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
321 return usBufferPtr->Buffer;
323 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
324 return NULL;
327 static LPWSTR strdupW(LPCWSTR p)
329 LPWSTR ret;
330 DWORD len;
332 if(!p) return NULL;
333 len = (strlenW(p) + 1) * sizeof(WCHAR);
334 ret = HeapAlloc(GetProcessHeap(), 0, len);
335 memcpy(ret, p, len);
336 return ret;
339 static LPSTR strdupWtoA( LPCWSTR str )
341 LPSTR ret;
342 INT len;
344 if (!str) return NULL;
345 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
346 ret = HeapAlloc( GetProcessHeap(), 0, len );
347 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
348 return ret;
351 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
353 DEVMODEW *ret;
355 if (!dm) return NULL;
356 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
357 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
358 return ret;
361 /***********************************************************
362 * DEVMODEdupWtoA
363 * Creates an ansi copy of supplied devmode
365 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
367 LPDEVMODEA dmA;
368 DWORD size;
370 if (!dmW) return NULL;
371 size = dmW->dmSize - CCHDEVICENAME -
372 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
374 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
375 if (!dmA) return NULL;
377 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
378 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
380 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
382 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
383 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
385 else
387 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
388 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
389 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
390 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
392 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
395 dmA->dmSize = size;
396 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
397 return dmA;
401 /******************************************************************
402 * verify, that the filename is a local file
405 static inline BOOL is_local_file(LPWSTR name)
407 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
410 /* ################################ */
412 static int multi_sz_lenA(const char *str)
414 const char *ptr = str;
415 if(!str) return 0;
418 ptr += lstrlenA(ptr) + 1;
419 } while(*ptr);
421 return ptr - str + 1;
424 static void
425 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
426 char qbuf[200];
428 /* If forcing, or no profile string entry for device yet, set the entry
430 * The always change entry if not WINEPS yet is discussable.
432 if (force ||
433 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
434 !strcmp(qbuf,"*") ||
435 !strstr(qbuf,"WINEPS.DRV")
437 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
438 HKEY hkey;
440 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
441 WriteProfileStringA("windows","device",buf);
442 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
443 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
444 RegCloseKey(hkey);
446 HeapFree(GetProcessHeap(),0,buf);
450 static BOOL add_printer_driver(WCHAR *name)
452 DRIVER_INFO_3W di3;
454 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
455 di3.cVersion = 3;
456 di3.pName = name;
457 di3.pEnvironment = envname_x86W;
458 di3.pDriverPath = driver_nt;
459 di3.pDataFile = generic_ppdW;
460 di3.pConfigFile = driver_nt;
461 di3.pDefaultDataType = rawW;
463 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
464 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
466 di3.cVersion = 0;
467 di3.pEnvironment = envname_win40W;
468 di3.pDriverPath = driver_9x;
469 di3.pConfigFile = driver_9x;
470 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
471 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
473 return TRUE;
476 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
477 return FALSE;
480 #ifdef SONAME_LIBCUPS
482 static void *cupshandle;
484 #define CUPS_FUNCS \
485 DO_FUNC(cupsFreeDests); \
486 DO_FUNC(cupsFreeOptions); \
487 DO_FUNC(cupsGetDests); \
488 DO_FUNC(cupsGetPPD); \
489 DO_FUNC(cupsParseOptions); \
490 DO_FUNC(cupsPrintFile);
492 #define DO_FUNC(f) static typeof(f) *p##f
493 CUPS_FUNCS;
494 #undef DO_FUNC
496 static BOOL CUPS_LoadPrinters(void)
498 int i, nrofdests;
499 BOOL hadprinter = FALSE, haddefault = FALSE;
500 cups_dest_t *dests;
501 PRINTER_INFO_2W pi2;
502 WCHAR *port;
503 HKEY hkeyPrinter, hkeyPrinters;
504 char loaderror[256];
505 WCHAR nameW[MAX_PATH];
506 HANDLE added_printer;
508 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
509 if (!cupshandle) {
510 TRACE("%s\n", loaderror);
511 return FALSE;
513 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
515 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
516 CUPS_FUNCS;
517 #undef DO_FUNC
519 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
520 ERROR_SUCCESS) {
521 ERR("Can't create Printers key\n");
522 return FALSE;
525 nrofdests = pcupsGetDests(&dests);
526 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
527 for (i=0;i<nrofdests;i++) {
528 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
530 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
531 lstrcpyW(port, CUPS_Port);
532 lstrcatW(port, nameW);
534 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
535 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
536 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
537 and continue */
538 TRACE("Printer already exists\n");
539 /* overwrite old LPR:* port */
540 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
541 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
542 RegCloseKey(hkeyPrinter);
543 } else {
544 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
545 ' ','u','s','i','n','g',' ','C','U','P','S',0};
547 add_printer_driver(nameW);
549 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
550 pi2.pPrinterName = nameW;
551 pi2.pDatatype = rawW;
552 pi2.pPrintProcessor = WinPrintW;
553 pi2.pDriverName = nameW;
554 pi2.pComment = comment_cups;
555 pi2.pLocation = emptyStringW;
556 pi2.pPortName = port;
557 pi2.pParameters = emptyStringW;
558 pi2.pShareName = emptyStringW;
559 pi2.pSepFile = emptyStringW;
561 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
562 if (added_printer) ClosePrinter( added_printer );
563 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
564 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
566 HeapFree(GetProcessHeap(),0,port);
568 hadprinter = TRUE;
569 if (dests[i].is_default) {
570 SetDefaultPrinterW(nameW);
571 haddefault = TRUE;
574 if (hadprinter && !haddefault) {
575 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
576 SetDefaultPrinterW(nameW);
578 pcupsFreeDests(nrofdests, dests);
579 RegCloseKey(hkeyPrinters);
580 return TRUE;
582 #endif
584 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
586 PRINTER_INFO_2A pinfo2a;
587 const char *r;
588 size_t name_len;
589 char *e,*s,*name,*prettyname,*devname;
590 BOOL ret = FALSE, set_default = FALSE;
591 char *port = NULL, *env_default;
592 HKEY hkeyPrinter, hkeyPrinters;
593 WCHAR devnameW[MAX_PATH];
594 HANDLE added_printer;
596 while (isspace(*pent)) pent++;
597 r = strchr(pent,':');
598 if (r)
599 name_len = r - pent;
600 else
601 name_len = strlen(pent);
602 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
603 memcpy(name, pent, name_len);
604 name[name_len] = '\0';
605 if (r)
606 pent = r;
607 else
608 pent = "";
610 TRACE("name=%s entry=%s\n",name, pent);
612 if(ispunct(*name)) { /* a tc entry, not a real printer */
613 TRACE("skipping tc entry\n");
614 goto end;
617 if(strstr(pent,":server")) { /* server only version so skip */
618 TRACE("skipping server entry\n");
619 goto end;
622 /* Determine whether this is a postscript printer. */
624 ret = TRUE;
625 env_default = getenv("PRINTER");
626 prettyname = name;
627 /* Get longest name, usually the one at the right for later display. */
628 while((s=strchr(prettyname,'|'))) {
629 *s = '\0';
630 e = s;
631 while(isspace(*--e)) *e = '\0';
632 TRACE("\t%s\n", debugstr_a(prettyname));
633 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
634 for(prettyname = s+1; isspace(*prettyname); prettyname++)
637 e = prettyname + strlen(prettyname);
638 while(isspace(*--e)) *e = '\0';
639 TRACE("\t%s\n", debugstr_a(prettyname));
640 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
642 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
643 * if it is too long, we use it as comment below. */
644 devname = prettyname;
645 if (strlen(devname)>=CCHDEVICENAME-1)
646 devname = name;
647 if (strlen(devname)>=CCHDEVICENAME-1) {
648 ret = FALSE;
649 goto end;
652 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
653 sprintf(port,"LPR:%s",name);
655 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
656 ERROR_SUCCESS) {
657 ERR("Can't create Printers key\n");
658 ret = FALSE;
659 goto end;
662 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
664 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
665 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
666 and continue */
667 TRACE("Printer already exists\n");
668 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
669 RegCloseKey(hkeyPrinter);
670 } else {
671 static CHAR data_type[] = "RAW",
672 print_proc[] = "WinPrint",
673 comment[] = "WINEPS Printer using LPR",
674 params[] = "<parameters?>",
675 share_name[] = "<share name?>",
676 sep_file[] = "<sep file?>";
678 add_printer_driver(devnameW);
680 memset(&pinfo2a,0,sizeof(pinfo2a));
681 pinfo2a.pPrinterName = devname;
682 pinfo2a.pDatatype = data_type;
683 pinfo2a.pPrintProcessor = print_proc;
684 pinfo2a.pDriverName = devname;
685 pinfo2a.pComment = comment;
686 pinfo2a.pLocation = prettyname;
687 pinfo2a.pPortName = port;
688 pinfo2a.pParameters = params;
689 pinfo2a.pShareName = share_name;
690 pinfo2a.pSepFile = sep_file;
692 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
693 if (added_printer) ClosePrinter( added_printer );
694 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
695 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
697 RegCloseKey(hkeyPrinters);
699 if (isfirst || set_default)
700 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
702 end:
703 HeapFree(GetProcessHeap(), 0, port);
704 HeapFree(GetProcessHeap(), 0, name);
705 return ret;
708 static BOOL
709 PRINTCAP_LoadPrinters(void) {
710 BOOL hadprinter = FALSE;
711 char buf[200];
712 FILE *f;
713 char *pent = NULL;
714 BOOL had_bash = FALSE;
716 f = fopen("/etc/printcap","r");
717 if (!f)
718 return FALSE;
720 while(fgets(buf,sizeof(buf),f)) {
721 char *start, *end;
723 end=strchr(buf,'\n');
724 if (end) *end='\0';
726 start = buf;
727 while(isspace(*start)) start++;
728 if(*start == '#' || *start == '\0')
729 continue;
731 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
732 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
733 HeapFree(GetProcessHeap(),0,pent);
734 pent = NULL;
737 if (end && *--end == '\\') {
738 *end = '\0';
739 had_bash = TRUE;
740 } else
741 had_bash = FALSE;
743 if (pent) {
744 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
745 strcat(pent,start);
746 } else {
747 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
748 strcpy(pent,start);
752 if(pent) {
753 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
754 HeapFree(GetProcessHeap(),0,pent);
756 fclose(f);
757 return hadprinter;
760 static inline DWORD set_reg_DWORD(HKEY hkey, const WCHAR *keyname, const DWORD value)
762 return RegSetValueExW(hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
765 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
767 if (value)
768 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
769 (lstrlenW(value) + 1) * sizeof(WCHAR));
770 else
771 return ERROR_FILE_NOT_FOUND;
774 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
776 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
777 DWORD ret = ERROR_FILE_NOT_FOUND;
779 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
780 and we support these drivers. NT writes DEVMODEW so somehow
781 we'll need to distinguish between these when we support NT
782 drivers */
784 if (dmA)
786 ret = RegSetValueExW( key, name, 0, REG_BINARY,
787 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
788 HeapFree( GetProcessHeap(), 0, dmA );
791 return ret;
794 /******************************************************************
795 * get_servername_from_name (internal)
797 * for an external server, a copy of the serverpart from the full name is returned
800 static LPWSTR get_servername_from_name(LPCWSTR name)
802 LPWSTR server;
803 LPWSTR ptr;
804 WCHAR buffer[MAX_PATH];
805 DWORD len;
807 if (name == NULL) return NULL;
808 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
810 server = strdupW(&name[2]); /* skip over both backslash */
811 if (server == NULL) return NULL;
813 /* strip '\' and the printername */
814 ptr = strchrW(server, '\\');
815 if (ptr) ptr[0] = '\0';
817 TRACE("found %s\n", debugstr_w(server));
819 len = sizeof(buffer)/sizeof(buffer[0]);
820 if (GetComputerNameW(buffer, &len)) {
821 if (lstrcmpW(buffer, server) == 0) {
822 /* The requested Servername is our computername */
823 HeapFree(GetProcessHeap(), 0, server);
824 return NULL;
827 return server;
830 /******************************************************************
831 * get_basename_from_name (internal)
833 * skip over the serverpart from the full name
836 static LPCWSTR get_basename_from_name(LPCWSTR name)
838 if (name == NULL) return NULL;
839 if ((name[0] == '\\') && (name[1] == '\\')) {
840 /* skip over the servername and search for the following '\' */
841 name = strchrW(&name[2], '\\');
842 if ((name) && (name[1])) {
843 /* found a separator ('\') followed by a name:
844 skip over the separator and return the rest */
845 name++;
847 else
849 /* no basename present (we found only a servername) */
850 return NULL;
853 return name;
856 static void free_printer_entry( opened_printer_t *printer )
858 /* the queue is shared, so don't free that here */
859 HeapFree( GetProcessHeap(), 0, printer->printername );
860 HeapFree( GetProcessHeap(), 0, printer->name );
861 HeapFree( GetProcessHeap(), 0, printer->devmode );
862 HeapFree( GetProcessHeap(), 0, printer );
865 /******************************************************************
866 * get_opened_printer_entry
867 * Get the first place empty in the opened printer table
869 * ToDo:
870 * - pDefault is ignored
872 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
874 UINT_PTR handle = nb_printer_handles, i;
875 jobqueue_t *queue = NULL;
876 opened_printer_t *printer = NULL;
877 LPWSTR servername;
878 LPCWSTR printername;
880 if ((backend == NULL) && !load_backend()) return NULL;
882 servername = get_servername_from_name(name);
883 if (servername) {
884 FIXME("server %s not supported\n", debugstr_w(servername));
885 HeapFree(GetProcessHeap(), 0, servername);
886 SetLastError(ERROR_INVALID_PRINTER_NAME);
887 return NULL;
890 printername = get_basename_from_name(name);
891 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
893 /* an empty printername is invalid */
894 if (printername && (!printername[0])) {
895 SetLastError(ERROR_INVALID_PARAMETER);
896 return NULL;
899 EnterCriticalSection(&printer_handles_cs);
901 for (i = 0; i < nb_printer_handles; i++)
903 if (!printer_handles[i])
905 if(handle == nb_printer_handles)
906 handle = i;
908 else
910 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
911 queue = printer_handles[i]->queue;
915 if (handle >= nb_printer_handles)
917 opened_printer_t **new_array;
918 if (printer_handles)
919 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
920 (nb_printer_handles + 16) * sizeof(*new_array) );
921 else
922 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
923 (nb_printer_handles + 16) * sizeof(*new_array) );
925 if (!new_array)
927 handle = 0;
928 goto end;
930 printer_handles = new_array;
931 nb_printer_handles += 16;
934 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
936 handle = 0;
937 goto end;
940 /* get a printer handle from the backend */
941 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
942 handle = 0;
943 goto end;
946 /* clone the base name. This is NULL for the printserver */
947 printer->printername = strdupW(printername);
949 /* clone the full name */
950 printer->name = strdupW(name);
951 if (name && (!printer->name)) {
952 handle = 0;
953 goto end;
956 if (pDefault && pDefault->pDevMode)
957 printer->devmode = dup_devmode( pDefault->pDevMode );
959 if(queue)
960 printer->queue = queue;
961 else
963 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
964 if (!printer->queue) {
965 handle = 0;
966 goto end;
968 list_init(&printer->queue->jobs);
969 printer->queue->ref = 0;
971 InterlockedIncrement(&printer->queue->ref);
973 printer_handles[handle] = printer;
974 handle++;
975 end:
976 LeaveCriticalSection(&printer_handles_cs);
977 if (!handle && printer) {
978 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
979 free_printer_entry( printer );
982 return (HANDLE)handle;
985 /******************************************************************
986 * get_opened_printer
987 * Get the pointer to the opened printer referred by the handle
989 static opened_printer_t *get_opened_printer(HANDLE hprn)
991 UINT_PTR idx = (UINT_PTR)hprn;
992 opened_printer_t *ret = NULL;
994 EnterCriticalSection(&printer_handles_cs);
996 if ((idx > 0) && (idx <= nb_printer_handles)) {
997 ret = printer_handles[idx - 1];
999 LeaveCriticalSection(&printer_handles_cs);
1000 return ret;
1003 /******************************************************************
1004 * get_opened_printer_name
1005 * Get the pointer to the opened printer name referred by the handle
1007 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1009 opened_printer_t *printer = get_opened_printer(hprn);
1010 if(!printer) return NULL;
1011 return printer->name;
1014 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1016 HKEY printers;
1017 DWORD err;
1019 *key = NULL;
1020 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1021 if (err) return err;
1023 err = RegOpenKeyW( printers, name, key );
1024 if (err) err = ERROR_INVALID_PRINTER_NAME;
1025 RegCloseKey( printers );
1026 return err;
1029 /******************************************************************
1030 * WINSPOOL_GetOpenedPrinterRegKey
1033 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1035 LPCWSTR name = get_opened_printer_name(hPrinter);
1037 if(!name) return ERROR_INVALID_HANDLE;
1038 return open_printer_reg_key( name, phkey );
1041 static void old_printer_check( BOOL delete_phase )
1043 PRINTER_INFO_5W* pi;
1044 DWORD needed, type, num, delete, i, size;
1045 const DWORD one = 1;
1046 HKEY key;
1047 HANDLE hprn;
1049 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1050 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1052 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1053 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1054 for (i = 0; i < num; i++)
1056 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1057 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1058 continue;
1060 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1062 if (!delete_phase)
1064 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1065 RegCloseKey( key );
1067 else
1069 delete = 0;
1070 size = sizeof( delete );
1071 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1072 RegCloseKey( key );
1073 if (delete)
1075 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1076 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1078 DeletePrinter( hprn );
1079 ClosePrinter( hprn );
1081 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1085 HeapFree(GetProcessHeap(), 0, pi);
1088 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1089 'M','U','T','E','X','_','_','\0'};
1091 void WINSPOOL_LoadSystemPrinters(void)
1093 HKEY hkey, hkeyPrinters;
1094 DWORD needed, num, i;
1095 WCHAR PrinterName[256];
1096 BOOL done = FALSE;
1097 HANDLE mutex;
1099 /* FIXME: The init code should be moved to spoolsv.exe */
1100 mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1101 if (!mutex)
1103 ERR( "Failed to create mutex\n" );
1104 return;
1106 if (GetLastError() == ERROR_ALREADY_EXISTS)
1108 WaitForSingleObject( mutex, INFINITE );
1109 ReleaseMutex( mutex );
1110 TRACE( "Init already done\n" );
1111 return;
1114 /* This ensures that all printer entries have a valid Name value. If causes
1115 problems later if they don't. If one is found to be missed we create one
1116 and set it equal to the name of the key */
1117 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1118 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1119 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1120 for(i = 0; i < num; i++) {
1121 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1122 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1123 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1124 set_reg_szW(hkey, NameW, PrinterName);
1126 RegCloseKey(hkey);
1131 RegCloseKey(hkeyPrinters);
1134 old_printer_check( FALSE );
1136 #ifdef SONAME_LIBCUPS
1137 done = CUPS_LoadPrinters();
1138 #endif
1140 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1141 PRINTCAP_LoadPrinters();
1143 old_printer_check( TRUE );
1145 ReleaseMutex( mutex );
1146 return;
1149 /******************************************************************
1150 * get_job
1152 * Get the pointer to the specified job.
1153 * Should hold the printer_handles_cs before calling.
1155 static job_t *get_job(HANDLE hprn, DWORD JobId)
1157 opened_printer_t *printer = get_opened_printer(hprn);
1158 job_t *job;
1160 if(!printer) return NULL;
1161 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1163 if(job->job_id == JobId)
1164 return job;
1166 return NULL;
1169 /***********************************************************
1170 * DEVMODEcpyAtoW
1172 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1174 BOOL Formname;
1175 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1176 DWORD size;
1178 Formname = (dmA->dmSize > off_formname);
1179 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1180 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1181 dmW->dmDeviceName, CCHDEVICENAME);
1182 if(!Formname) {
1183 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1184 dmA->dmSize - CCHDEVICENAME);
1185 } else {
1186 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1187 off_formname - CCHDEVICENAME);
1188 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1189 dmW->dmFormName, CCHFORMNAME);
1190 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1191 (off_formname + CCHFORMNAME));
1193 dmW->dmSize = size;
1194 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1195 dmA->dmDriverExtra);
1196 return dmW;
1199 /******************************************************************
1200 * convert_printerinfo_W_to_A [internal]
1203 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1204 DWORD level, DWORD outlen, DWORD numentries)
1206 DWORD id = 0;
1207 LPSTR ptr;
1208 INT len;
1210 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1212 len = pi_sizeof[level] * numentries;
1213 ptr = (LPSTR) out + len;
1214 outlen -= len;
1216 /* copy the numbers of all PRINTER_INFO_* first */
1217 memcpy(out, pPrintersW, len);
1219 while (id < numentries) {
1220 switch (level) {
1221 case 1:
1223 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1224 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1226 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1227 if (piW->pDescription) {
1228 piA->pDescription = ptr;
1229 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1230 ptr, outlen, NULL, NULL);
1231 ptr += len;
1232 outlen -= len;
1234 if (piW->pName) {
1235 piA->pName = ptr;
1236 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1237 ptr, outlen, NULL, NULL);
1238 ptr += len;
1239 outlen -= len;
1241 if (piW->pComment) {
1242 piA->pComment = ptr;
1243 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1244 ptr, outlen, NULL, NULL);
1245 ptr += len;
1246 outlen -= len;
1248 break;
1251 case 2:
1253 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1254 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1255 LPDEVMODEA dmA;
1257 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1258 if (piW->pServerName) {
1259 piA->pServerName = ptr;
1260 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1261 ptr, outlen, NULL, NULL);
1262 ptr += len;
1263 outlen -= len;
1265 if (piW->pPrinterName) {
1266 piA->pPrinterName = ptr;
1267 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1268 ptr, outlen, NULL, NULL);
1269 ptr += len;
1270 outlen -= len;
1272 if (piW->pShareName) {
1273 piA->pShareName = ptr;
1274 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1275 ptr, outlen, NULL, NULL);
1276 ptr += len;
1277 outlen -= len;
1279 if (piW->pPortName) {
1280 piA->pPortName = ptr;
1281 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1282 ptr, outlen, NULL, NULL);
1283 ptr += len;
1284 outlen -= len;
1286 if (piW->pDriverName) {
1287 piA->pDriverName = ptr;
1288 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1289 ptr, outlen, NULL, NULL);
1290 ptr += len;
1291 outlen -= len;
1293 if (piW->pComment) {
1294 piA->pComment = ptr;
1295 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1296 ptr, outlen, NULL, NULL);
1297 ptr += len;
1298 outlen -= len;
1300 if (piW->pLocation) {
1301 piA->pLocation = ptr;
1302 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1303 ptr, outlen, NULL, NULL);
1304 ptr += len;
1305 outlen -= len;
1308 dmA = DEVMODEdupWtoA(piW->pDevMode);
1309 if (dmA) {
1310 /* align DEVMODEA to a DWORD boundary */
1311 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1312 ptr += len;
1313 outlen -= len;
1315 piA->pDevMode = (LPDEVMODEA) ptr;
1316 len = dmA->dmSize + dmA->dmDriverExtra;
1317 memcpy(ptr, dmA, len);
1318 HeapFree(GetProcessHeap(), 0, dmA);
1320 ptr += len;
1321 outlen -= len;
1324 if (piW->pSepFile) {
1325 piA->pSepFile = ptr;
1326 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1327 ptr, outlen, NULL, NULL);
1328 ptr += len;
1329 outlen -= len;
1331 if (piW->pPrintProcessor) {
1332 piA->pPrintProcessor = ptr;
1333 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1334 ptr, outlen, NULL, NULL);
1335 ptr += len;
1336 outlen -= len;
1338 if (piW->pDatatype) {
1339 piA->pDatatype = ptr;
1340 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1341 ptr, outlen, NULL, NULL);
1342 ptr += len;
1343 outlen -= len;
1345 if (piW->pParameters) {
1346 piA->pParameters = ptr;
1347 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1348 ptr, outlen, NULL, NULL);
1349 ptr += len;
1350 outlen -= len;
1352 if (piW->pSecurityDescriptor) {
1353 piA->pSecurityDescriptor = NULL;
1354 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1356 break;
1359 case 4:
1361 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1362 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1364 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1366 if (piW->pPrinterName) {
1367 piA->pPrinterName = ptr;
1368 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1369 ptr, outlen, NULL, NULL);
1370 ptr += len;
1371 outlen -= len;
1373 if (piW->pServerName) {
1374 piA->pServerName = ptr;
1375 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1376 ptr, outlen, NULL, NULL);
1377 ptr += len;
1378 outlen -= len;
1380 break;
1383 case 5:
1385 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1386 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1388 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1390 if (piW->pPrinterName) {
1391 piA->pPrinterName = ptr;
1392 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1393 ptr, outlen, NULL, NULL);
1394 ptr += len;
1395 outlen -= len;
1397 if (piW->pPortName) {
1398 piA->pPortName = ptr;
1399 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1400 ptr, outlen, NULL, NULL);
1401 ptr += len;
1402 outlen -= len;
1404 break;
1407 case 6: /* 6A and 6W are the same structure */
1408 break;
1410 case 7:
1412 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1413 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1415 TRACE("(%u) #%u\n", level, id);
1416 if (piW->pszObjectGUID) {
1417 piA->pszObjectGUID = ptr;
1418 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1419 ptr, outlen, NULL, NULL);
1420 ptr += len;
1421 outlen -= len;
1423 break;
1426 case 8:
1427 case 9:
1429 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1430 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1431 LPDEVMODEA dmA;
1433 TRACE("(%u) #%u\n", level, id);
1434 dmA = DEVMODEdupWtoA(piW->pDevMode);
1435 if (dmA) {
1436 /* align DEVMODEA to a DWORD boundary */
1437 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1438 ptr += len;
1439 outlen -= len;
1441 piA->pDevMode = (LPDEVMODEA) ptr;
1442 len = dmA->dmSize + dmA->dmDriverExtra;
1443 memcpy(ptr, dmA, len);
1444 HeapFree(GetProcessHeap(), 0, dmA);
1446 ptr += len;
1447 outlen -= len;
1450 break;
1453 default:
1454 FIXME("for level %u\n", level);
1456 pPrintersW += pi_sizeof[level];
1457 out += pi_sizeof[level];
1458 id++;
1462 /******************************************************************
1463 * convert_driverinfo_W_to_A [internal]
1466 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1467 DWORD level, DWORD outlen, DWORD numentries)
1469 DWORD id = 0;
1470 LPSTR ptr;
1471 INT len;
1473 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1475 len = di_sizeof[level] * numentries;
1476 ptr = (LPSTR) out + len;
1477 outlen -= len;
1479 /* copy the numbers of all PRINTER_INFO_* first */
1480 memcpy(out, pDriversW, len);
1482 #define COPY_STRING(fld) \
1483 { if (diW->fld){ \
1484 diA->fld = ptr; \
1485 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1486 ptr += len; outlen -= len;\
1488 #define COPY_MULTIZ_STRING(fld) \
1489 { LPWSTR p = diW->fld; if (p){ \
1490 diA->fld = ptr; \
1491 do {\
1492 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1493 ptr += len; outlen -= len; p += len;\
1495 while(len > 1 && outlen > 0); \
1498 while (id < numentries)
1500 switch (level)
1502 case 1:
1504 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1505 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1507 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1509 COPY_STRING(pName);
1510 break;
1512 case 2:
1514 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1515 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1517 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1519 COPY_STRING(pName);
1520 COPY_STRING(pEnvironment);
1521 COPY_STRING(pDriverPath);
1522 COPY_STRING(pDataFile);
1523 COPY_STRING(pConfigFile);
1524 break;
1526 case 3:
1528 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1529 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1531 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1533 COPY_STRING(pName);
1534 COPY_STRING(pEnvironment);
1535 COPY_STRING(pDriverPath);
1536 COPY_STRING(pDataFile);
1537 COPY_STRING(pConfigFile);
1538 COPY_STRING(pHelpFile);
1539 COPY_MULTIZ_STRING(pDependentFiles);
1540 COPY_STRING(pMonitorName);
1541 COPY_STRING(pDefaultDataType);
1542 break;
1544 case 4:
1546 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1547 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1549 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1551 COPY_STRING(pName);
1552 COPY_STRING(pEnvironment);
1553 COPY_STRING(pDriverPath);
1554 COPY_STRING(pDataFile);
1555 COPY_STRING(pConfigFile);
1556 COPY_STRING(pHelpFile);
1557 COPY_MULTIZ_STRING(pDependentFiles);
1558 COPY_STRING(pMonitorName);
1559 COPY_STRING(pDefaultDataType);
1560 COPY_MULTIZ_STRING(pszzPreviousNames);
1561 break;
1563 case 5:
1565 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1566 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1568 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1570 COPY_STRING(pName);
1571 COPY_STRING(pEnvironment);
1572 COPY_STRING(pDriverPath);
1573 COPY_STRING(pDataFile);
1574 COPY_STRING(pConfigFile);
1575 break;
1577 case 6:
1579 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1580 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1582 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1584 COPY_STRING(pName);
1585 COPY_STRING(pEnvironment);
1586 COPY_STRING(pDriverPath);
1587 COPY_STRING(pDataFile);
1588 COPY_STRING(pConfigFile);
1589 COPY_STRING(pHelpFile);
1590 COPY_MULTIZ_STRING(pDependentFiles);
1591 COPY_STRING(pMonitorName);
1592 COPY_STRING(pDefaultDataType);
1593 COPY_MULTIZ_STRING(pszzPreviousNames);
1594 COPY_STRING(pszMfgName);
1595 COPY_STRING(pszOEMUrl);
1596 COPY_STRING(pszHardwareID);
1597 COPY_STRING(pszProvider);
1598 break;
1600 case 8:
1602 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1603 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1605 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1607 COPY_STRING(pName);
1608 COPY_STRING(pEnvironment);
1609 COPY_STRING(pDriverPath);
1610 COPY_STRING(pDataFile);
1611 COPY_STRING(pConfigFile);
1612 COPY_STRING(pHelpFile);
1613 COPY_MULTIZ_STRING(pDependentFiles);
1614 COPY_STRING(pMonitorName);
1615 COPY_STRING(pDefaultDataType);
1616 COPY_MULTIZ_STRING(pszzPreviousNames);
1617 COPY_STRING(pszMfgName);
1618 COPY_STRING(pszOEMUrl);
1619 COPY_STRING(pszHardwareID);
1620 COPY_STRING(pszProvider);
1621 COPY_STRING(pszPrintProcessor);
1622 COPY_STRING(pszVendorSetup);
1623 COPY_MULTIZ_STRING(pszzColorProfiles);
1624 COPY_STRING(pszInfPath);
1625 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1626 break;
1630 default:
1631 FIXME("for level %u\n", level);
1634 pDriversW += di_sizeof[level];
1635 out += di_sizeof[level];
1636 id++;
1639 #undef COPY_STRING
1640 #undef COPY_MULTIZ_STRING
1644 /***********************************************************
1645 * printer_info_AtoW
1647 static void *printer_info_AtoW( const void *data, DWORD level )
1649 void *ret;
1650 UNICODE_STRING usBuffer;
1652 if (!data) return NULL;
1654 if (level < 1 || level > 9) return NULL;
1656 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1657 if (!ret) return NULL;
1659 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1661 switch (level)
1663 case 2:
1665 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1666 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1668 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1669 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1670 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1671 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1672 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1673 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1674 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1675 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1676 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1677 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1678 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1679 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1680 break;
1683 case 8:
1684 case 9:
1686 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1687 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1689 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1690 break;
1693 default:
1694 FIXME( "Unhandled level %d\n", level );
1695 HeapFree( GetProcessHeap(), 0, ret );
1696 return NULL;
1699 return ret;
1702 /***********************************************************
1703 * free_printer_info
1705 static void free_printer_info( void *data, DWORD level )
1707 if (!data) return;
1709 switch (level)
1711 case 2:
1713 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1715 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1716 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1717 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1718 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1719 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1720 HeapFree( GetProcessHeap(), 0, piW->pComment );
1721 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1722 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1723 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1724 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1725 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1726 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1727 break;
1730 case 8:
1731 case 9:
1733 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1735 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1736 break;
1739 default:
1740 FIXME( "Unhandled level %d\n", level );
1743 HeapFree( GetProcessHeap(), 0, data );
1744 return;
1747 /******************************************************************
1748 * DeviceCapabilities [WINSPOOL.@]
1749 * DeviceCapabilitiesA [WINSPOOL.@]
1752 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1753 LPSTR pOutput, LPDEVMODEA lpdm)
1755 INT ret;
1757 if (!GDI_CallDeviceCapabilities16)
1759 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1760 (LPCSTR)104 );
1761 if (!GDI_CallDeviceCapabilities16) return -1;
1763 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1765 /* If DC_PAPERSIZE map POINT16s to POINTs */
1766 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1767 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1768 POINT *pt = (POINT *)pOutput;
1769 INT i;
1770 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1771 for(i = 0; i < ret; i++, pt++)
1773 pt->x = tmp[i].x;
1774 pt->y = tmp[i].y;
1776 HeapFree( GetProcessHeap(), 0, tmp );
1778 return ret;
1782 /*****************************************************************************
1783 * DeviceCapabilitiesW [WINSPOOL.@]
1785 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1788 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1789 WORD fwCapability, LPWSTR pOutput,
1790 const DEVMODEW *pDevMode)
1792 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1793 LPSTR pDeviceA = strdupWtoA(pDevice);
1794 LPSTR pPortA = strdupWtoA(pPort);
1795 INT ret;
1797 if(pOutput && (fwCapability == DC_BINNAMES ||
1798 fwCapability == DC_FILEDEPENDENCIES ||
1799 fwCapability == DC_PAPERNAMES)) {
1800 /* These need A -> W translation */
1801 INT size = 0, i;
1802 LPSTR pOutputA;
1803 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1804 dmA);
1805 if(ret == -1)
1806 return ret;
1807 switch(fwCapability) {
1808 case DC_BINNAMES:
1809 size = 24;
1810 break;
1811 case DC_PAPERNAMES:
1812 case DC_FILEDEPENDENCIES:
1813 size = 64;
1814 break;
1816 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1817 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1818 dmA);
1819 for(i = 0; i < ret; i++)
1820 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1821 pOutput + (i * size), size);
1822 HeapFree(GetProcessHeap(), 0, pOutputA);
1823 } else {
1824 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1825 (LPSTR)pOutput, dmA);
1827 HeapFree(GetProcessHeap(),0,pPortA);
1828 HeapFree(GetProcessHeap(),0,pDeviceA);
1829 HeapFree(GetProcessHeap(),0,dmA);
1830 return ret;
1833 /******************************************************************
1834 * DocumentPropertiesA [WINSPOOL.@]
1836 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1838 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1839 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1840 LPDEVMODEA pDevModeInput,DWORD fMode )
1842 LPSTR lpName = pDeviceName;
1843 static CHAR port[] = "LPT1:";
1844 LONG ret;
1846 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1847 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1850 if(!pDeviceName) {
1851 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1852 if(!lpNameW) {
1853 ERR("no name from hPrinter?\n");
1854 SetLastError(ERROR_INVALID_HANDLE);
1855 return -1;
1857 lpName = strdupWtoA(lpNameW);
1860 if (!GDI_CallExtDeviceMode16)
1862 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1863 (LPCSTR)102 );
1864 if (!GDI_CallExtDeviceMode16) {
1865 ERR("No CallExtDeviceMode16?\n");
1866 return -1;
1869 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1870 pDevModeInput, NULL, fMode);
1872 if(!pDeviceName)
1873 HeapFree(GetProcessHeap(),0,lpName);
1874 return ret;
1878 /*****************************************************************************
1879 * DocumentPropertiesW (WINSPOOL.@)
1881 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1883 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1884 LPWSTR pDeviceName,
1885 LPDEVMODEW pDevModeOutput,
1886 LPDEVMODEW pDevModeInput, DWORD fMode)
1889 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1890 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1891 LPDEVMODEA pDevModeOutputA = NULL;
1892 LONG ret;
1894 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1895 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1896 fMode);
1897 if(pDevModeOutput) {
1898 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1899 if(ret < 0) return ret;
1900 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1902 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1903 pDevModeInputA, fMode);
1904 if(pDevModeOutput) {
1905 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1906 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1908 if(fMode == 0 && ret > 0)
1909 ret += (CCHDEVICENAME + CCHFORMNAME);
1910 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1911 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1912 return ret;
1915 /*****************************************************************************
1916 * IsValidDevmodeA [WINSPOOL.@]
1918 * Validate a DEVMODE structure and fix errors if possible.
1921 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1923 FIXME("(%p,%ld): stub\n", pDevMode, size);
1925 if(!pDevMode)
1926 return FALSE;
1928 return TRUE;
1931 /*****************************************************************************
1932 * IsValidDevmodeW [WINSPOOL.@]
1934 * Validate a DEVMODE structure and fix errors if possible.
1937 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1939 FIXME("(%p,%ld): stub\n", pDevMode, size);
1941 if(!pDevMode)
1942 return FALSE;
1944 return TRUE;
1947 /******************************************************************
1948 * OpenPrinterA [WINSPOOL.@]
1950 * See OpenPrinterW.
1953 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1954 LPPRINTER_DEFAULTSA pDefault)
1956 UNICODE_STRING lpPrinterNameW;
1957 UNICODE_STRING usBuffer;
1958 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1959 PWSTR pwstrPrinterNameW;
1960 BOOL ret;
1962 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1964 if(pDefault) {
1965 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1966 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1967 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1968 pDefaultW = &DefaultW;
1970 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1971 if(pDefault) {
1972 RtlFreeUnicodeString(&usBuffer);
1973 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1975 RtlFreeUnicodeString(&lpPrinterNameW);
1976 return ret;
1979 /******************************************************************
1980 * OpenPrinterW [WINSPOOL.@]
1982 * Open a Printer / Printserver or a Printer-Object
1984 * PARAMS
1985 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1986 * phPrinter [O] The resulting Handle is stored here
1987 * pDefault [I] PTR to Default Printer Settings or NULL
1989 * RETURNS
1990 * Success: TRUE
1991 * Failure: FALSE
1993 * NOTES
1994 * lpPrinterName is one of:
1995 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1996 *| Printer: "PrinterName"
1997 *| Printer-Object: "PrinterName,Job xxx"
1998 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1999 *| XcvPort: "Servername,XcvPort PortName"
2001 * BUGS
2002 *| Printer-Object not supported
2003 *| pDefaults is ignored
2006 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2009 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2011 if(!phPrinter) {
2012 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2013 SetLastError(ERROR_INVALID_PARAMETER);
2014 return FALSE;
2017 /* Get the unique handle of the printer or Printserver */
2018 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2019 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2020 return (*phPrinter != 0);
2023 /******************************************************************
2024 * AddMonitorA [WINSPOOL.@]
2026 * See AddMonitorW.
2029 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2031 LPWSTR nameW = NULL;
2032 INT len;
2033 BOOL res;
2034 LPMONITOR_INFO_2A mi2a;
2035 MONITOR_INFO_2W mi2w;
2037 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2038 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2039 debugstr_a(mi2a ? mi2a->pName : NULL),
2040 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2041 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2043 if (Level != 2) {
2044 SetLastError(ERROR_INVALID_LEVEL);
2045 return FALSE;
2048 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2049 if (mi2a == NULL) {
2050 return FALSE;
2053 if (pName) {
2054 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2055 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2056 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2059 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2060 if (mi2a->pName) {
2061 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2062 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2063 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2065 if (mi2a->pEnvironment) {
2066 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2067 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2068 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2070 if (mi2a->pDLLName) {
2071 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2072 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2073 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2076 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2078 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2079 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2080 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2082 HeapFree(GetProcessHeap(), 0, nameW);
2083 return (res);
2086 /******************************************************************************
2087 * AddMonitorW [WINSPOOL.@]
2089 * Install a Printmonitor
2091 * PARAMS
2092 * pName [I] Servername or NULL (local Computer)
2093 * Level [I] Structure-Level (Must be 2)
2094 * pMonitors [I] PTR to MONITOR_INFO_2
2096 * RETURNS
2097 * Success: TRUE
2098 * Failure: FALSE
2100 * NOTES
2101 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2104 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2106 LPMONITOR_INFO_2W mi2w;
2108 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2109 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2110 debugstr_w(mi2w ? mi2w->pName : NULL),
2111 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2112 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2114 if ((backend == NULL) && !load_backend()) return FALSE;
2116 if (Level != 2) {
2117 SetLastError(ERROR_INVALID_LEVEL);
2118 return FALSE;
2121 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2122 if (mi2w == NULL) {
2123 return FALSE;
2126 return backend->fpAddMonitor(pName, Level, pMonitors);
2129 /******************************************************************
2130 * DeletePrinterDriverA [WINSPOOL.@]
2133 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2135 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2138 /******************************************************************
2139 * DeletePrinterDriverW [WINSPOOL.@]
2142 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2144 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2147 /******************************************************************
2148 * DeleteMonitorA [WINSPOOL.@]
2150 * See DeleteMonitorW.
2153 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2155 LPWSTR nameW = NULL;
2156 LPWSTR EnvironmentW = NULL;
2157 LPWSTR MonitorNameW = NULL;
2158 BOOL res;
2159 INT len;
2161 if (pName) {
2162 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2163 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2164 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2167 if (pEnvironment) {
2168 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2169 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2170 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2172 if (pMonitorName) {
2173 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2174 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2175 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2178 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2180 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2181 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2182 HeapFree(GetProcessHeap(), 0, nameW);
2183 return (res);
2186 /******************************************************************
2187 * DeleteMonitorW [WINSPOOL.@]
2189 * Delete a specific Printmonitor from a Printing-Environment
2191 * PARAMS
2192 * pName [I] Servername or NULL (local Computer)
2193 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2194 * pMonitorName [I] Name of the Monitor, that should be deleted
2196 * RETURNS
2197 * Success: TRUE
2198 * Failure: FALSE
2200 * NOTES
2201 * pEnvironment is ignored in Windows for the local Computer.
2204 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2207 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2208 debugstr_w(pMonitorName));
2210 if ((backend == NULL) && !load_backend()) return FALSE;
2212 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2216 /******************************************************************
2217 * DeletePortA [WINSPOOL.@]
2219 * See DeletePortW.
2222 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2224 LPWSTR nameW = NULL;
2225 LPWSTR portW = NULL;
2226 INT len;
2227 DWORD res;
2229 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2231 /* convert servername to unicode */
2232 if (pName) {
2233 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2234 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2235 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2238 /* convert portname to unicode */
2239 if (pPortName) {
2240 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2241 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2242 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2245 res = DeletePortW(nameW, hWnd, portW);
2246 HeapFree(GetProcessHeap(), 0, nameW);
2247 HeapFree(GetProcessHeap(), 0, portW);
2248 return res;
2251 /******************************************************************
2252 * DeletePortW [WINSPOOL.@]
2254 * Delete a specific Port
2256 * PARAMS
2257 * pName [I] Servername or NULL (local Computer)
2258 * hWnd [I] Handle to parent Window for the Dialog-Box
2259 * pPortName [I] Name of the Port, that should be deleted
2261 * RETURNS
2262 * Success: TRUE
2263 * Failure: FALSE
2266 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2268 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2270 if ((backend == NULL) && !load_backend()) return FALSE;
2272 if (!pPortName) {
2273 SetLastError(RPC_X_NULL_REF_POINTER);
2274 return FALSE;
2277 return backend->fpDeletePort(pName, hWnd, pPortName);
2280 /******************************************************************************
2281 * WritePrinter [WINSPOOL.@]
2283 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2285 opened_printer_t *printer;
2286 BOOL ret = FALSE;
2288 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2290 EnterCriticalSection(&printer_handles_cs);
2291 printer = get_opened_printer(hPrinter);
2292 if(!printer)
2294 SetLastError(ERROR_INVALID_HANDLE);
2295 goto end;
2298 if(!printer->doc)
2300 SetLastError(ERROR_SPL_NO_STARTDOC);
2301 goto end;
2304 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2305 end:
2306 LeaveCriticalSection(&printer_handles_cs);
2307 return ret;
2310 /*****************************************************************************
2311 * AddFormA [WINSPOOL.@]
2313 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2315 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2316 return 1;
2319 /*****************************************************************************
2320 * AddFormW [WINSPOOL.@]
2322 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2324 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2325 return 1;
2328 /*****************************************************************************
2329 * AddJobA [WINSPOOL.@]
2331 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2333 BOOL ret;
2334 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2335 DWORD needed;
2337 if(Level != 1) {
2338 SetLastError(ERROR_INVALID_LEVEL);
2339 return FALSE;
2342 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2344 if(ret) {
2345 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2346 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2347 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2348 if(*pcbNeeded > cbBuf) {
2349 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2350 ret = FALSE;
2351 } else {
2352 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2353 addjobA->JobId = addjobW->JobId;
2354 addjobA->Path = (char *)(addjobA + 1);
2355 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2358 return ret;
2361 /*****************************************************************************
2362 * AddJobW [WINSPOOL.@]
2364 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2366 opened_printer_t *printer;
2367 job_t *job;
2368 BOOL ret = FALSE;
2369 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2370 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2371 WCHAR path[MAX_PATH], filename[MAX_PATH];
2372 DWORD len;
2373 ADDJOB_INFO_1W *addjob;
2375 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2377 EnterCriticalSection(&printer_handles_cs);
2379 printer = get_opened_printer(hPrinter);
2381 if(!printer) {
2382 SetLastError(ERROR_INVALID_HANDLE);
2383 goto end;
2386 if(Level != 1) {
2387 SetLastError(ERROR_INVALID_LEVEL);
2388 goto end;
2391 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2392 if(!job)
2393 goto end;
2395 job->job_id = InterlockedIncrement(&next_job_id);
2397 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2398 if(path[len - 1] != '\\')
2399 path[len++] = '\\';
2400 memcpy(path + len, spool_path, sizeof(spool_path));
2401 sprintfW(filename, fmtW, path, job->job_id);
2403 len = strlenW(filename);
2404 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2405 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2406 job->portname = NULL;
2407 job->document_title = strdupW(default_doc_title);
2408 job->printer_name = strdupW(printer->name);
2409 job->devmode = dup_devmode( printer->devmode );
2410 list_add_tail(&printer->queue->jobs, &job->entry);
2412 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2413 if(*pcbNeeded <= cbBuf) {
2414 addjob = (ADDJOB_INFO_1W*)pData;
2415 addjob->JobId = job->job_id;
2416 addjob->Path = (WCHAR *)(addjob + 1);
2417 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2418 ret = TRUE;
2419 } else
2420 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2422 end:
2423 LeaveCriticalSection(&printer_handles_cs);
2424 return ret;
2427 /*****************************************************************************
2428 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2430 * Return the PATH for the Print-Processors
2432 * See GetPrintProcessorDirectoryW.
2436 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2437 DWORD level, LPBYTE Info,
2438 DWORD cbBuf, LPDWORD pcbNeeded)
2440 LPWSTR serverW = NULL;
2441 LPWSTR envW = NULL;
2442 BOOL ret;
2443 INT len;
2445 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2446 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2449 if (server) {
2450 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2451 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2452 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2455 if (env) {
2456 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2457 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2458 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2461 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2462 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2464 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2465 cbBuf, pcbNeeded);
2467 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2468 cbBuf, NULL, NULL) > 0;
2471 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2472 HeapFree(GetProcessHeap(), 0, envW);
2473 HeapFree(GetProcessHeap(), 0, serverW);
2474 return ret;
2477 /*****************************************************************************
2478 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2480 * Return the PATH for the Print-Processors
2482 * PARAMS
2483 * server [I] Servername (NT only) or NULL (local Computer)
2484 * env [I] Printing-Environment (see below) or NULL (Default)
2485 * level [I] Structure-Level (must be 1)
2486 * Info [O] PTR to Buffer that receives the Result
2487 * cbBuf [I] Size of Buffer at "Info"
2488 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2489 * required for the Buffer at "Info"
2491 * RETURNS
2492 * Success: TRUE and in pcbNeeded the Bytes used in Info
2493 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2494 * if cbBuf is too small
2496 * Native Values returned in Info on Success:
2497 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2498 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2499 *| win9x(Windows 4.0): "%winsysdir%"
2501 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2503 * BUGS
2504 * Only NULL or "" is supported for server
2507 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2508 DWORD level, LPBYTE Info,
2509 DWORD cbBuf, LPDWORD pcbNeeded)
2512 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2513 Info, cbBuf, pcbNeeded);
2515 if ((backend == NULL) && !load_backend()) return FALSE;
2517 if (level != 1) {
2518 /* (Level != 1) is ignored in win9x */
2519 SetLastError(ERROR_INVALID_LEVEL);
2520 return FALSE;
2523 if (pcbNeeded == NULL) {
2524 /* (pcbNeeded == NULL) is ignored in win9x */
2525 SetLastError(RPC_X_NULL_REF_POINTER);
2526 return FALSE;
2529 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2532 /*****************************************************************************
2533 * WINSPOOL_OpenDriverReg [internal]
2535 * opens the registry for the printer drivers depending on the given input
2536 * variable pEnvironment
2538 * RETURNS:
2539 * the opened hkey on success
2540 * NULL on error
2542 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2544 HKEY retval = NULL;
2545 LPWSTR buffer;
2546 const printenv_t * env;
2548 TRACE("(%s)\n", debugstr_w(pEnvironment));
2550 env = validate_envW(pEnvironment);
2551 if (!env) return NULL;
2553 buffer = HeapAlloc( GetProcessHeap(), 0,
2554 (strlenW(DriversW) + strlenW(env->envname) +
2555 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2556 if(buffer) {
2557 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2558 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2559 HeapFree(GetProcessHeap(), 0, buffer);
2561 return retval;
2564 /*****************************************************************************
2565 * set_devices_and_printerports [internal]
2567 * set the [Devices] and [PrinterPorts] entries for a printer.
2570 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2572 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2573 WCHAR *devline;
2574 HKEY hkey;
2576 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2578 /* FIXME: the driver must change to "winspool" */
2579 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2580 if (devline) {
2581 lstrcpyW(devline, driver_nt);
2582 lstrcatW(devline, commaW);
2583 lstrcatW(devline, pi->pPortName);
2585 TRACE("using %s\n", debugstr_w(devline));
2586 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2587 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2588 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2589 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2590 RegCloseKey(hkey);
2593 lstrcatW(devline, timeout_15_45);
2594 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2595 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2596 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2597 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2598 RegCloseKey(hkey);
2600 HeapFree(GetProcessHeap(), 0, devline);
2604 /*****************************************************************************
2605 * AddPrinterW [WINSPOOL.@]
2607 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2609 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2610 LPDEVMODEW dm;
2611 HANDLE retval;
2612 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2613 LONG size;
2615 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2617 if(pName != NULL) {
2618 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2619 SetLastError(ERROR_INVALID_PARAMETER);
2620 return 0;
2622 if(Level != 2) {
2623 ERR("Level = %d, unsupported!\n", Level);
2624 SetLastError(ERROR_INVALID_LEVEL);
2625 return 0;
2627 if(!pPrinter) {
2628 SetLastError(ERROR_INVALID_PARAMETER);
2629 return 0;
2631 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2632 ERROR_SUCCESS) {
2633 ERR("Can't create Printers key\n");
2634 return 0;
2636 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2637 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
2638 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2639 RegCloseKey(hkeyPrinter);
2640 RegCloseKey(hkeyPrinters);
2641 return 0;
2643 RegCloseKey(hkeyPrinter);
2645 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2646 if(!hkeyDrivers) {
2647 ERR("Can't create Drivers key\n");
2648 RegCloseKey(hkeyPrinters);
2649 return 0;
2651 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2652 ERROR_SUCCESS) {
2653 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2654 RegCloseKey(hkeyPrinters);
2655 RegCloseKey(hkeyDrivers);
2656 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2657 return 0;
2659 RegCloseKey(hkeyDriver);
2660 RegCloseKey(hkeyDrivers);
2662 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2663 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2664 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2665 RegCloseKey(hkeyPrinters);
2666 return 0;
2669 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2670 ERROR_SUCCESS) {
2671 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2672 SetLastError(ERROR_INVALID_PRINTER_NAME);
2673 RegCloseKey(hkeyPrinters);
2674 return 0;
2677 set_devices_and_printerports(pi);
2678 RegSetValueExW(hkeyPrinter, AttributesW, 0, REG_DWORD,
2679 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2680 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2682 /* See if we can load the driver. We may need the devmode structure anyway
2684 * FIXME:
2685 * Note that DocumentPropertiesW will briefly try to open the printer we
2686 * just create to find a DEVMODE struct (it will use the WINEPS default
2687 * one in case it is not there, so we are ok).
2689 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2691 if(size < 0) {
2692 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2693 size = sizeof(DEVMODEW);
2695 if(pi->pDevMode)
2696 dm = pi->pDevMode;
2697 else
2699 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2700 dm->dmSize = size;
2701 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2703 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2704 HeapFree( GetProcessHeap(), 0, dm );
2705 dm = NULL;
2707 else
2709 /* set devmode to printer name */
2710 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2714 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
2715 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2717 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2718 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2719 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2720 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2722 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2723 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2724 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2725 RegSetValueExW(hkeyPrinter, PriorityW, 0, REG_DWORD,
2726 (LPBYTE)&pi->Priority, sizeof(DWORD));
2727 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2728 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2729 RegSetValueExW(hkeyPrinter, StartTimeW, 0, REG_DWORD,
2730 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2731 RegSetValueExW(hkeyPrinter, StatusW, 0, REG_DWORD,
2732 (LPBYTE)&pi->Status, sizeof(DWORD));
2733 RegSetValueExW(hkeyPrinter, UntilTimeW, 0, REG_DWORD,
2734 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2736 RegCloseKey(hkeyPrinter);
2737 RegCloseKey(hkeyPrinters);
2738 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2739 ERR("OpenPrinter failing\n");
2740 return 0;
2742 return retval;
2745 /*****************************************************************************
2746 * AddPrinterA [WINSPOOL.@]
2748 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2750 UNICODE_STRING pNameW;
2751 PWSTR pwstrNameW;
2752 PRINTER_INFO_2W *piW;
2753 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2754 HANDLE ret;
2756 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2757 if(Level != 2) {
2758 ERR("Level = %d, unsupported!\n", Level);
2759 SetLastError(ERROR_INVALID_LEVEL);
2760 return 0;
2762 pwstrNameW = asciitounicode(&pNameW,pName);
2763 piW = printer_info_AtoW( piA, Level );
2765 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2767 free_printer_info( piW, Level );
2768 RtlFreeUnicodeString(&pNameW);
2769 return ret;
2773 /*****************************************************************************
2774 * ClosePrinter [WINSPOOL.@]
2776 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2778 UINT_PTR i = (UINT_PTR)hPrinter;
2779 opened_printer_t *printer = NULL;
2780 BOOL ret = FALSE;
2782 TRACE("(%p)\n", hPrinter);
2784 EnterCriticalSection(&printer_handles_cs);
2786 if ((i > 0) && (i <= nb_printer_handles))
2787 printer = printer_handles[i - 1];
2790 if(printer)
2792 struct list *cursor, *cursor2;
2794 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2796 if (printer->backend_printer) {
2797 backend->fpClosePrinter(printer->backend_printer);
2800 if(printer->doc)
2801 EndDocPrinter(hPrinter);
2803 if(InterlockedDecrement(&printer->queue->ref) == 0)
2805 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2807 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2808 ScheduleJob(hPrinter, job->job_id);
2810 HeapFree(GetProcessHeap(), 0, printer->queue);
2813 free_printer_entry( printer );
2814 printer_handles[i - 1] = NULL;
2815 ret = TRUE;
2817 LeaveCriticalSection(&printer_handles_cs);
2818 return ret;
2821 /*****************************************************************************
2822 * DeleteFormA [WINSPOOL.@]
2824 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2826 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2827 return 1;
2830 /*****************************************************************************
2831 * DeleteFormW [WINSPOOL.@]
2833 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2835 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2836 return 1;
2839 /*****************************************************************************
2840 * DeletePrinter [WINSPOOL.@]
2842 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2844 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2845 HKEY hkeyPrinters, hkey;
2846 WCHAR def[MAX_PATH];
2847 DWORD size = sizeof( def ) / sizeof( def[0] );
2849 if(!lpNameW) {
2850 SetLastError(ERROR_INVALID_HANDLE);
2851 return FALSE;
2853 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2854 RegDeleteTreeW(hkeyPrinters, lpNameW);
2855 RegCloseKey(hkeyPrinters);
2857 WriteProfileStringW(devicesW, lpNameW, NULL);
2858 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2860 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2861 RegDeleteValueW(hkey, lpNameW);
2862 RegCloseKey(hkey);
2865 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2866 RegDeleteValueW(hkey, lpNameW);
2867 RegCloseKey(hkey);
2870 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2872 WriteProfileStringW( windowsW, deviceW, NULL );
2873 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2875 RegDeleteValueW( hkey, deviceW );
2876 RegCloseKey( hkey );
2878 SetDefaultPrinterW( NULL );
2881 return TRUE;
2884 /*****************************************************************************
2885 * SetPrinterA [WINSPOOL.@]
2887 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2889 BYTE *dataW = data;
2890 BOOL ret;
2892 if (level != 0)
2894 dataW = printer_info_AtoW( data, level );
2895 if (!dataW) return FALSE;
2898 ret = SetPrinterW( printer, level, dataW, command );
2900 if (dataW != data) free_printer_info( dataW, level );
2902 return ret;
2905 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
2907 set_reg_szW( key, NameW, pi->pPrinterName );
2908 set_reg_szW( key, Share_NameW, pi->pShareName );
2909 set_reg_szW( key, PortW, pi->pPortName );
2910 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
2911 set_reg_szW( key, DescriptionW, pi->pComment );
2912 set_reg_szW( key, LocationW, pi->pLocation );
2914 if (pi->pDevMode)
2915 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2917 set_reg_szW( key, Separator_FileW, pi->pSepFile );
2918 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
2919 set_reg_szW( key, DatatypeW, pi->pDatatype );
2920 set_reg_szW( key, ParametersW, pi->pParameters );
2922 set_reg_DWORD( key, AttributesW, pi->Attributes );
2923 set_reg_DWORD( key, PriorityW, pi->Priority );
2924 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
2925 set_reg_DWORD( key, StartTimeW, pi->StartTime );
2926 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
2929 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2931 if (!pi->pDevMode) return FALSE;
2933 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2934 return TRUE;
2937 /******************************************************************************
2938 * SetPrinterW [WINSPOOL.@]
2940 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2942 HKEY key;
2943 BOOL ret = FALSE;
2945 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2947 if (command != 0) FIXME( "Ignoring command %d\n", command );
2949 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2950 return FALSE;
2952 switch (level)
2954 case 2:
2956 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
2957 set_printer_2( key, pi2 );
2958 ret = TRUE;
2959 break;
2962 case 9:
2964 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2965 ret = set_printer_9( key, pi );
2966 break;
2969 default:
2970 FIXME( "Unimplemented level %d\n", level );
2971 SetLastError( ERROR_INVALID_LEVEL );
2974 RegCloseKey( key );
2975 return ret;
2978 /*****************************************************************************
2979 * SetJobA [WINSPOOL.@]
2981 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2982 LPBYTE pJob, DWORD Command)
2984 BOOL ret;
2985 LPBYTE JobW;
2986 UNICODE_STRING usBuffer;
2988 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2990 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2991 are all ignored by SetJob, so we don't bother copying them */
2992 switch(Level)
2994 case 0:
2995 JobW = NULL;
2996 break;
2997 case 1:
2999 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3000 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3002 JobW = (LPBYTE)info1W;
3003 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3004 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3005 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3006 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3007 info1W->Status = info1A->Status;
3008 info1W->Priority = info1A->Priority;
3009 info1W->Position = info1A->Position;
3010 info1W->PagesPrinted = info1A->PagesPrinted;
3011 break;
3013 case 2:
3015 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3016 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3018 JobW = (LPBYTE)info2W;
3019 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3020 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3021 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3022 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3023 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3024 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3025 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3026 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3027 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3028 info2W->Status = info2A->Status;
3029 info2W->Priority = info2A->Priority;
3030 info2W->Position = info2A->Position;
3031 info2W->StartTime = info2A->StartTime;
3032 info2W->UntilTime = info2A->UntilTime;
3033 info2W->PagesPrinted = info2A->PagesPrinted;
3034 break;
3036 case 3:
3037 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3038 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3039 break;
3040 default:
3041 SetLastError(ERROR_INVALID_LEVEL);
3042 return FALSE;
3045 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3047 switch(Level)
3049 case 1:
3051 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3052 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3053 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3054 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3055 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3056 break;
3058 case 2:
3060 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3061 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3062 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3063 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3064 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3065 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3066 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3067 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3068 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3069 break;
3072 HeapFree(GetProcessHeap(), 0, JobW);
3074 return ret;
3077 /*****************************************************************************
3078 * SetJobW [WINSPOOL.@]
3080 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3081 LPBYTE pJob, DWORD Command)
3083 BOOL ret = FALSE;
3084 job_t *job;
3086 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3087 FIXME("Ignoring everything other than document title\n");
3089 EnterCriticalSection(&printer_handles_cs);
3090 job = get_job(hPrinter, JobId);
3091 if(!job)
3092 goto end;
3094 switch(Level)
3096 case 0:
3097 break;
3098 case 1:
3100 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3101 HeapFree(GetProcessHeap(), 0, job->document_title);
3102 job->document_title = strdupW(info1->pDocument);
3103 break;
3105 case 2:
3107 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3108 HeapFree(GetProcessHeap(), 0, job->document_title);
3109 job->document_title = strdupW(info2->pDocument);
3110 HeapFree(GetProcessHeap(), 0, job->devmode);
3111 job->devmode = dup_devmode( info2->pDevMode );
3112 break;
3114 case 3:
3115 break;
3116 default:
3117 SetLastError(ERROR_INVALID_LEVEL);
3118 goto end;
3120 ret = TRUE;
3121 end:
3122 LeaveCriticalSection(&printer_handles_cs);
3123 return ret;
3126 /*****************************************************************************
3127 * EndDocPrinter [WINSPOOL.@]
3129 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3131 opened_printer_t *printer;
3132 BOOL ret = FALSE;
3133 TRACE("(%p)\n", hPrinter);
3135 EnterCriticalSection(&printer_handles_cs);
3137 printer = get_opened_printer(hPrinter);
3138 if(!printer)
3140 SetLastError(ERROR_INVALID_HANDLE);
3141 goto end;
3144 if(!printer->doc)
3146 SetLastError(ERROR_SPL_NO_STARTDOC);
3147 goto end;
3150 CloseHandle(printer->doc->hf);
3151 ScheduleJob(hPrinter, printer->doc->job_id);
3152 HeapFree(GetProcessHeap(), 0, printer->doc);
3153 printer->doc = NULL;
3154 ret = TRUE;
3155 end:
3156 LeaveCriticalSection(&printer_handles_cs);
3157 return ret;
3160 /*****************************************************************************
3161 * EndPagePrinter [WINSPOOL.@]
3163 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3165 FIXME("(%p): stub\n", hPrinter);
3166 return TRUE;
3169 /*****************************************************************************
3170 * StartDocPrinterA [WINSPOOL.@]
3172 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3174 UNICODE_STRING usBuffer;
3175 DOC_INFO_2W doc2W;
3176 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3177 DWORD ret;
3179 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3180 or one (DOC_INFO_3) extra DWORDs */
3182 switch(Level) {
3183 case 2:
3184 doc2W.JobId = doc2->JobId;
3185 /* fall through */
3186 case 3:
3187 doc2W.dwMode = doc2->dwMode;
3188 /* fall through */
3189 case 1:
3190 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3191 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3192 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3193 break;
3195 default:
3196 SetLastError(ERROR_INVALID_LEVEL);
3197 return FALSE;
3200 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3202 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3203 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3204 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3206 return ret;
3209 /*****************************************************************************
3210 * StartDocPrinterW [WINSPOOL.@]
3212 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3214 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3215 opened_printer_t *printer;
3216 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3217 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3218 JOB_INFO_1W job_info;
3219 DWORD needed, ret = 0;
3220 HANDLE hf;
3221 WCHAR *filename;
3222 job_t *job;
3224 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3225 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3226 debugstr_w(doc->pDatatype));
3228 if(Level < 1 || Level > 3)
3230 SetLastError(ERROR_INVALID_LEVEL);
3231 return 0;
3234 EnterCriticalSection(&printer_handles_cs);
3235 printer = get_opened_printer(hPrinter);
3236 if(!printer)
3238 SetLastError(ERROR_INVALID_HANDLE);
3239 goto end;
3242 if(printer->doc)
3244 SetLastError(ERROR_INVALID_PRINTER_STATE);
3245 goto end;
3248 /* Even if we're printing to a file we still add a print job, we'll
3249 just ignore the spool file name */
3251 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3253 ERR("AddJob failed gle %u\n", GetLastError());
3254 goto end;
3257 /* use pOutputFile only, when it is a real filename */
3258 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3259 filename = doc->pOutputFile;
3260 else
3261 filename = addjob->Path;
3263 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3264 if(hf == INVALID_HANDLE_VALUE)
3265 goto end;
3267 memset(&job_info, 0, sizeof(job_info));
3268 job_info.pDocument = doc->pDocName;
3269 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3271 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3272 printer->doc->hf = hf;
3273 ret = printer->doc->job_id = addjob->JobId;
3274 job = get_job(hPrinter, ret);
3275 job->portname = strdupW(doc->pOutputFile);
3277 end:
3278 LeaveCriticalSection(&printer_handles_cs);
3280 return ret;
3283 /*****************************************************************************
3284 * StartPagePrinter [WINSPOOL.@]
3286 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3288 FIXME("(%p): stub\n", hPrinter);
3289 return TRUE;
3292 /*****************************************************************************
3293 * GetFormA [WINSPOOL.@]
3295 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3296 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3298 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3299 Level,pForm,cbBuf,pcbNeeded);
3300 return FALSE;
3303 /*****************************************************************************
3304 * GetFormW [WINSPOOL.@]
3306 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3307 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3309 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3310 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3311 return FALSE;
3314 /*****************************************************************************
3315 * SetFormA [WINSPOOL.@]
3317 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3318 LPBYTE pForm)
3320 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3321 return FALSE;
3324 /*****************************************************************************
3325 * SetFormW [WINSPOOL.@]
3327 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3328 LPBYTE pForm)
3330 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3331 return FALSE;
3334 /*****************************************************************************
3335 * ReadPrinter [WINSPOOL.@]
3337 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3338 LPDWORD pNoBytesRead)
3340 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3341 return FALSE;
3344 /*****************************************************************************
3345 * ResetPrinterA [WINSPOOL.@]
3347 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3349 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3350 return FALSE;
3353 /*****************************************************************************
3354 * ResetPrinterW [WINSPOOL.@]
3356 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3358 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3359 return FALSE;
3362 /*****************************************************************************
3363 * get_dword_from_reg
3365 * Return DWORD associated with name from hkey.
3367 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
3369 DWORD sz = sizeof(DWORD), type, value = 0;
3370 LONG ret;
3372 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
3374 if(ret != ERROR_SUCCESS) {
3375 WARN("Got ret = %d on name %s\n", ret, debugstr_w(name));
3376 return 0;
3378 if(type != REG_DWORD) {
3379 ERR("Got type %d\n", type);
3380 return 0;
3382 return value;
3385 /*****************************************************************************
3386 * get_filename_from_reg [internal]
3388 * Get ValueName from hkey storing result in out
3389 * when the Value in the registry has only a filename, use driverdir as prefix
3390 * outlen is space left in out
3391 * String is stored either as unicode or ascii
3395 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3396 LPBYTE out, DWORD outlen, LPDWORD needed)
3398 WCHAR filename[MAX_PATH];
3399 DWORD size;
3400 DWORD type;
3401 LONG ret;
3402 LPWSTR buffer = filename;
3403 LPWSTR ptr;
3405 *needed = 0;
3406 size = sizeof(filename);
3407 buffer[0] = '\0';
3408 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3409 if (ret == ERROR_MORE_DATA) {
3410 TRACE("need dynamic buffer: %u\n", size);
3411 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3412 if (!buffer) {
3413 /* No Memory is bad */
3414 return FALSE;
3416 buffer[0] = '\0';
3417 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3420 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3421 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3422 return FALSE;
3425 ptr = buffer;
3426 while (ptr) {
3427 /* do we have a full path ? */
3428 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3429 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3431 if (!ret) {
3432 /* we must build the full Path */
3433 *needed += dirlen;
3434 if ((out) && (outlen > dirlen)) {
3435 lstrcpyW((LPWSTR)out, driverdir);
3436 out += dirlen;
3437 outlen -= dirlen;
3439 else
3440 out = NULL;
3443 /* write the filename */
3444 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3445 if ((out) && (outlen >= size)) {
3446 lstrcpyW((LPWSTR)out, ptr);
3447 out += size;
3448 outlen -= size;
3450 else
3451 out = NULL;
3452 *needed += size;
3453 ptr += lstrlenW(ptr)+1;
3454 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3457 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3459 /* write the multisz-termination */
3460 if (type == REG_MULTI_SZ) {
3461 size = sizeof(WCHAR);
3463 *needed += size;
3464 if (out && (outlen >= size)) {
3465 memset (out, 0, size);
3468 return TRUE;
3471 /*****************************************************************************
3472 * WINSPOOL_GetStringFromReg
3474 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3475 * String is stored as unicode.
3477 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3478 DWORD buflen, DWORD *needed)
3480 DWORD sz = buflen, type;
3481 LONG ret;
3483 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3484 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3485 WARN("Got ret = %d\n", ret);
3486 *needed = 0;
3487 return FALSE;
3489 /* add space for terminating '\0' */
3490 sz += sizeof(WCHAR);
3491 *needed = sz;
3493 if (ptr)
3494 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3496 return TRUE;
3499 /*****************************************************************************
3500 * WINSPOOL_GetDefaultDevMode
3502 * Get a default DevMode values for wineps.
3503 * FIXME - use ppd.
3506 static void WINSPOOL_GetDefaultDevMode(
3507 LPBYTE ptr,
3508 DWORD buflen, DWORD *needed)
3510 DEVMODEW dm;
3511 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3513 /* fill default DEVMODE - should be read from ppd... */
3514 ZeroMemory( &dm, sizeof(dm) );
3515 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3516 dm.dmSpecVersion = DM_SPECVERSION;
3517 dm.dmDriverVersion = 1;
3518 dm.dmSize = sizeof(DEVMODEW);
3519 dm.dmDriverExtra = 0;
3520 dm.dmFields =
3521 DM_ORIENTATION | DM_PAPERSIZE |
3522 DM_PAPERLENGTH | DM_PAPERWIDTH |
3523 DM_SCALE |
3524 DM_COPIES |
3525 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3526 DM_YRESOLUTION | DM_TTOPTION;
3528 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3529 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3530 dm.u1.s1.dmPaperLength = 2970;
3531 dm.u1.s1.dmPaperWidth = 2100;
3533 dm.u1.s1.dmScale = 100;
3534 dm.u1.s1.dmCopies = 1;
3535 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3536 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3537 /* dm.dmColor */
3538 /* dm.dmDuplex */
3539 dm.dmYResolution = 300; /* 300dpi */
3540 dm.dmTTOption = DMTT_BITMAP;
3541 /* dm.dmCollate */
3542 /* dm.dmFormName */
3543 /* dm.dmLogPixels */
3544 /* dm.dmBitsPerPel */
3545 /* dm.dmPelsWidth */
3546 /* dm.dmPelsHeight */
3547 /* dm.u2.dmDisplayFlags */
3548 /* dm.dmDisplayFrequency */
3549 /* dm.dmICMMethod */
3550 /* dm.dmICMIntent */
3551 /* dm.dmMediaType */
3552 /* dm.dmDitherType */
3553 /* dm.dmReserved1 */
3554 /* dm.dmReserved2 */
3555 /* dm.dmPanningWidth */
3556 /* dm.dmPanningHeight */
3558 if(buflen >= sizeof(DEVMODEW))
3559 memcpy(ptr, &dm, sizeof(DEVMODEW));
3560 *needed = sizeof(DEVMODEW);
3563 /*****************************************************************************
3564 * WINSPOOL_GetDevModeFromReg
3566 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3567 * DevMode is stored either as unicode or ascii.
3569 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3570 LPBYTE ptr,
3571 DWORD buflen, DWORD *needed)
3573 DWORD sz = buflen, type;
3574 LONG ret;
3576 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3577 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3578 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3579 if (sz < sizeof(DEVMODEA))
3581 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3582 return FALSE;
3584 /* ensures that dmSize is not erratically bogus if registry is invalid */
3585 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3586 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3587 sz += (CCHDEVICENAME + CCHFORMNAME);
3588 if (ptr && (buflen >= sz)) {
3589 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3590 memcpy(ptr, dmW, sz);
3591 HeapFree(GetProcessHeap(),0,dmW);
3593 *needed = sz;
3594 return TRUE;
3597 /*********************************************************************
3598 * WINSPOOL_GetPrinter_1
3600 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3602 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3603 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3605 DWORD size, left = cbBuf;
3606 BOOL space = (cbBuf > 0);
3607 LPBYTE ptr = buf;
3609 *pcbNeeded = 0;
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3612 if(space && size <= left) {
3613 pi1->pName = (LPWSTR)ptr;
3614 ptr += size;
3615 left -= size;
3616 } else
3617 space = FALSE;
3618 *pcbNeeded += size;
3621 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3622 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3623 if(space && size <= left) {
3624 pi1->pDescription = (LPWSTR)ptr;
3625 ptr += size;
3626 left -= size;
3627 } else
3628 space = FALSE;
3629 *pcbNeeded += size;
3632 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3633 if(space && size <= left) {
3634 pi1->pComment = (LPWSTR)ptr;
3635 ptr += size;
3636 left -= size;
3637 } else
3638 space = FALSE;
3639 *pcbNeeded += size;
3642 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3644 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3645 memset(pi1, 0, sizeof(*pi1));
3647 return space;
3649 /*********************************************************************
3650 * WINSPOOL_GetPrinter_2
3652 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3654 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3655 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3657 DWORD size, left = cbBuf;
3658 BOOL space = (cbBuf > 0);
3659 LPBYTE ptr = buf;
3661 *pcbNeeded = 0;
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3664 if(space && size <= left) {
3665 pi2->pPrinterName = (LPWSTR)ptr;
3666 ptr += size;
3667 left -= size;
3668 } else
3669 space = FALSE;
3670 *pcbNeeded += size;
3672 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3673 if(space && size <= left) {
3674 pi2->pShareName = (LPWSTR)ptr;
3675 ptr += size;
3676 left -= size;
3677 } else
3678 space = FALSE;
3679 *pcbNeeded += size;
3681 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3682 if(space && size <= left) {
3683 pi2->pPortName = (LPWSTR)ptr;
3684 ptr += size;
3685 left -= size;
3686 } else
3687 space = FALSE;
3688 *pcbNeeded += size;
3690 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3691 if(space && size <= left) {
3692 pi2->pDriverName = (LPWSTR)ptr;
3693 ptr += size;
3694 left -= size;
3695 } else
3696 space = FALSE;
3697 *pcbNeeded += size;
3699 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3700 if(space && size <= left) {
3701 pi2->pComment = (LPWSTR)ptr;
3702 ptr += size;
3703 left -= size;
3704 } else
3705 space = FALSE;
3706 *pcbNeeded += size;
3708 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3709 if(space && size <= left) {
3710 pi2->pLocation = (LPWSTR)ptr;
3711 ptr += size;
3712 left -= size;
3713 } else
3714 space = FALSE;
3715 *pcbNeeded += size;
3717 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3718 if(space && size <= left) {
3719 pi2->pDevMode = (LPDEVMODEW)ptr;
3720 ptr += size;
3721 left -= size;
3722 } else
3723 space = FALSE;
3724 *pcbNeeded += size;
3726 else
3728 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3729 if(space && size <= left) {
3730 pi2->pDevMode = (LPDEVMODEW)ptr;
3731 ptr += size;
3732 left -= size;
3733 } else
3734 space = FALSE;
3735 *pcbNeeded += size;
3737 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3738 if(space && size <= left) {
3739 pi2->pSepFile = (LPWSTR)ptr;
3740 ptr += size;
3741 left -= size;
3742 } else
3743 space = FALSE;
3744 *pcbNeeded += size;
3746 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3747 if(space && size <= left) {
3748 pi2->pPrintProcessor = (LPWSTR)ptr;
3749 ptr += size;
3750 left -= size;
3751 } else
3752 space = FALSE;
3753 *pcbNeeded += size;
3755 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3756 if(space && size <= left) {
3757 pi2->pDatatype = (LPWSTR)ptr;
3758 ptr += size;
3759 left -= size;
3760 } else
3761 space = FALSE;
3762 *pcbNeeded += size;
3764 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3765 if(space && size <= left) {
3766 pi2->pParameters = (LPWSTR)ptr;
3767 ptr += size;
3768 left -= size;
3769 } else
3770 space = FALSE;
3771 *pcbNeeded += size;
3773 if(pi2) {
3774 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
3775 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
3776 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
3777 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
3778 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
3781 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3782 memset(pi2, 0, sizeof(*pi2));
3784 return space;
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);
3797 LPBYTE ptr = buf;
3799 *pcbNeeded = 0;
3801 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3802 if(space && size <= left) {
3803 pi4->pPrinterName = (LPWSTR)ptr;
3804 ptr += size;
3805 left -= size;
3806 } else
3807 space = FALSE;
3808 *pcbNeeded += size;
3810 if(pi4) {
3811 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
3814 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3815 memset(pi4, 0, sizeof(*pi4));
3817 return space;
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);
3830 LPBYTE ptr = buf;
3832 *pcbNeeded = 0;
3834 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3835 if(space && size <= left) {
3836 pi5->pPrinterName = (LPWSTR)ptr;
3837 ptr += size;
3838 left -= size;
3839 } else
3840 space = FALSE;
3841 *pcbNeeded += size;
3843 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3844 if(space && size <= left) {
3845 pi5->pPortName = (LPWSTR)ptr;
3846 ptr += size;
3847 left -= size;
3848 } else
3849 space = FALSE;
3850 *pcbNeeded += size;
3852 if(pi5) {
3853 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
3854 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
3855 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
3858 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3859 memset(pi5, 0, sizeof(*pi5));
3861 return space;
3864 /*********************************************************************
3865 * WINSPOOL_GetPrinter_7
3867 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3869 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3870 DWORD cbBuf, LPDWORD pcbNeeded)
3872 DWORD size, left = cbBuf;
3873 BOOL space = (cbBuf > 0);
3874 LPBYTE ptr = buf;
3876 *pcbNeeded = 0;
3878 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3880 ptr = NULL;
3881 size = sizeof(pi7->pszObjectGUID);
3883 if (space && size <= left) {
3884 pi7->pszObjectGUID = (LPWSTR)ptr;
3885 ptr += size;
3886 left -= size;
3887 } else
3888 space = FALSE;
3889 *pcbNeeded += size;
3890 if (pi7) {
3891 /* We do not have a Directory Service */
3892 pi7->dwAction = DSPRINT_UNPUBLISH;
3895 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3896 memset(pi7, 0, sizeof(*pi7));
3898 return space;
3901 /*********************************************************************
3902 * WINSPOOL_GetPrinter_9
3904 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3906 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3907 DWORD cbBuf, LPDWORD pcbNeeded)
3909 DWORD size;
3910 BOOL space = (cbBuf > 0);
3912 *pcbNeeded = 0;
3914 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3915 if(space && size <= cbBuf) {
3916 pi9->pDevMode = (LPDEVMODEW)buf;
3917 } else
3918 space = FALSE;
3919 *pcbNeeded += size;
3921 else
3923 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3924 if(space && size <= cbBuf) {
3925 pi9->pDevMode = (LPDEVMODEW)buf;
3926 } else
3927 space = FALSE;
3928 *pcbNeeded += size;
3931 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3932 memset(pi9, 0, sizeof(*pi9));
3934 return space;
3937 /*****************************************************************************
3938 * GetPrinterW [WINSPOOL.@]
3940 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3941 DWORD cbBuf, LPDWORD pcbNeeded)
3943 DWORD size, needed = 0, err;
3944 LPBYTE ptr = NULL;
3945 HKEY hkeyPrinter;
3946 BOOL ret;
3948 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3950 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3951 if (err)
3953 SetLastError( err );
3954 return FALSE;
3957 switch(Level) {
3958 case 2:
3960 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3962 size = sizeof(PRINTER_INFO_2W);
3963 if(size <= cbBuf) {
3964 ptr = pPrinter + size;
3965 cbBuf -= size;
3966 memset(pPrinter, 0, size);
3967 } else {
3968 pi2 = NULL;
3969 cbBuf = 0;
3971 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3972 needed += size;
3973 break;
3976 case 4:
3978 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3980 size = sizeof(PRINTER_INFO_4W);
3981 if(size <= cbBuf) {
3982 ptr = pPrinter + size;
3983 cbBuf -= size;
3984 memset(pPrinter, 0, size);
3985 } else {
3986 pi4 = NULL;
3987 cbBuf = 0;
3989 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3990 needed += size;
3991 break;
3995 case 5:
3997 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3999 size = sizeof(PRINTER_INFO_5W);
4000 if(size <= cbBuf) {
4001 ptr = pPrinter + size;
4002 cbBuf -= size;
4003 memset(pPrinter, 0, size);
4004 } else {
4005 pi5 = NULL;
4006 cbBuf = 0;
4009 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4010 needed += size;
4011 break;
4015 case 6:
4017 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4019 size = sizeof(PRINTER_INFO_6);
4020 if (size <= cbBuf) {
4021 /* FIXME: We do not update the status yet */
4022 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4023 ret = TRUE;
4024 } else {
4025 ret = FALSE;
4028 needed += size;
4029 break;
4032 case 7:
4034 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4036 size = sizeof(PRINTER_INFO_7W);
4037 if (size <= cbBuf) {
4038 ptr = pPrinter + size;
4039 cbBuf -= size;
4040 memset(pPrinter, 0, size);
4041 } else {
4042 pi7 = NULL;
4043 cbBuf = 0;
4046 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4047 needed += size;
4048 break;
4052 case 8:
4053 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4054 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4055 /* fall through */
4056 case 9:
4058 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4060 size = sizeof(PRINTER_INFO_9W);
4061 if(size <= cbBuf) {
4062 ptr = pPrinter + size;
4063 cbBuf -= size;
4064 memset(pPrinter, 0, size);
4065 } else {
4066 pi9 = NULL;
4067 cbBuf = 0;
4070 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4071 needed += size;
4072 break;
4076 default:
4077 FIXME("Unimplemented level %d\n", Level);
4078 SetLastError(ERROR_INVALID_LEVEL);
4079 RegCloseKey(hkeyPrinter);
4080 return FALSE;
4083 RegCloseKey(hkeyPrinter);
4085 TRACE("returning %d needed = %d\n", ret, needed);
4086 if(pcbNeeded) *pcbNeeded = needed;
4087 if(!ret)
4088 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4089 return ret;
4092 /*****************************************************************************
4093 * GetPrinterA [WINSPOOL.@]
4095 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4096 DWORD cbBuf, LPDWORD pcbNeeded)
4098 BOOL ret;
4099 LPBYTE buf = NULL;
4101 if (cbBuf)
4102 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4104 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4105 if (ret)
4106 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4107 HeapFree(GetProcessHeap(), 0, buf);
4109 return ret;
4112 /*****************************************************************************
4113 * WINSPOOL_EnumPrintersW
4115 * Implementation of EnumPrintersW
4117 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4118 DWORD dwLevel, LPBYTE lpbPrinters,
4119 DWORD cbBuf, LPDWORD lpdwNeeded,
4120 LPDWORD lpdwReturned)
4123 HKEY hkeyPrinters, hkeyPrinter;
4124 WCHAR PrinterName[255];
4125 DWORD needed = 0, number = 0;
4126 DWORD used, i, left;
4127 PBYTE pi, buf;
4129 if(lpbPrinters)
4130 memset(lpbPrinters, 0, cbBuf);
4131 if(lpdwReturned)
4132 *lpdwReturned = 0;
4133 if(lpdwNeeded)
4134 *lpdwNeeded = 0;
4136 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4137 if(dwType == PRINTER_ENUM_DEFAULT)
4138 return TRUE;
4140 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4141 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4142 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4143 if (!dwType) {
4144 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4145 return TRUE;
4150 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4151 FIXME("dwType = %08x\n", dwType);
4152 SetLastError(ERROR_INVALID_FLAGS);
4153 return FALSE;
4156 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4157 ERROR_SUCCESS) {
4158 ERR("Can't create Printers key\n");
4159 return FALSE;
4162 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4163 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4164 RegCloseKey(hkeyPrinters);
4165 ERR("Can't query Printers key\n");
4166 return FALSE;
4168 TRACE("Found %d printers\n", number);
4170 switch(dwLevel) {
4171 case 1:
4172 used = number * sizeof(PRINTER_INFO_1W);
4173 break;
4174 case 2:
4175 used = number * sizeof(PRINTER_INFO_2W);
4176 break;
4177 case 4:
4178 used = number * sizeof(PRINTER_INFO_4W);
4179 break;
4180 case 5:
4181 used = number * sizeof(PRINTER_INFO_5W);
4182 break;
4184 default:
4185 SetLastError(ERROR_INVALID_LEVEL);
4186 RegCloseKey(hkeyPrinters);
4187 return FALSE;
4189 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4191 for(i = 0; i < number; i++) {
4192 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4193 ERROR_SUCCESS) {
4194 ERR("Can't enum key number %d\n", i);
4195 RegCloseKey(hkeyPrinters);
4196 return FALSE;
4198 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4199 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4200 ERROR_SUCCESS) {
4201 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4202 RegCloseKey(hkeyPrinters);
4203 return FALSE;
4206 if(cbBuf > used) {
4207 buf = lpbPrinters + used;
4208 left = cbBuf - used;
4209 } else {
4210 buf = NULL;
4211 left = 0;
4214 switch(dwLevel) {
4215 case 1:
4216 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4217 left, &needed);
4218 used += needed;
4219 if(pi) pi += sizeof(PRINTER_INFO_1W);
4220 break;
4221 case 2:
4222 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4223 left, &needed);
4224 used += needed;
4225 if(pi) pi += sizeof(PRINTER_INFO_2W);
4226 break;
4227 case 4:
4228 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4229 left, &needed);
4230 used += needed;
4231 if(pi) pi += sizeof(PRINTER_INFO_4W);
4232 break;
4233 case 5:
4234 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4235 left, &needed);
4236 used += needed;
4237 if(pi) pi += sizeof(PRINTER_INFO_5W);
4238 break;
4239 default:
4240 ERR("Shouldn't be here!\n");
4241 RegCloseKey(hkeyPrinter);
4242 RegCloseKey(hkeyPrinters);
4243 return FALSE;
4245 RegCloseKey(hkeyPrinter);
4247 RegCloseKey(hkeyPrinters);
4249 if(lpdwNeeded)
4250 *lpdwNeeded = used;
4252 if(used > cbBuf) {
4253 if(lpbPrinters)
4254 memset(lpbPrinters, 0, cbBuf);
4255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4256 return FALSE;
4258 if(lpdwReturned)
4259 *lpdwReturned = number;
4260 SetLastError(ERROR_SUCCESS);
4261 return TRUE;
4265 /******************************************************************
4266 * EnumPrintersW [WINSPOOL.@]
4268 * Enumerates the available printers, print servers and print
4269 * providers, depending on the specified flags, name and level.
4271 * RETURNS:
4273 * If level is set to 1:
4274 * Returns an array of PRINTER_INFO_1 data structures in the
4275 * lpbPrinters buffer.
4277 * If level is set to 2:
4278 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4279 * Returns an array of PRINTER_INFO_2 data structures in the
4280 * lpbPrinters buffer. Note that according to MSDN also an
4281 * OpenPrinter should be performed on every remote printer.
4283 * If level is set to 4 (officially WinNT only):
4284 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4285 * Fast: Only the registry is queried to retrieve printer names,
4286 * no connection to the driver is made.
4287 * Returns an array of PRINTER_INFO_4 data structures in the
4288 * lpbPrinters buffer.
4290 * If level is set to 5 (officially WinNT4/Win9x only):
4291 * Fast: Only the registry is queried to retrieve printer names,
4292 * no connection to the driver is made.
4293 * Returns an array of PRINTER_INFO_5 data structures in the
4294 * lpbPrinters buffer.
4296 * If level set to 3 or 6+:
4297 * returns zero (failure!)
4299 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4300 * for information.
4302 * BUGS:
4303 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4304 * - Only levels 2, 4 and 5 are implemented at the moment.
4305 * - 16-bit printer drivers are not enumerated.
4306 * - Returned amount of bytes used/needed does not match the real Windoze
4307 * implementation (as in this implementation, all strings are part
4308 * of the buffer, whereas Win32 keeps them somewhere else)
4309 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4311 * NOTE:
4312 * - In a regular Wine installation, no registry settings for printers
4313 * exist, which makes this function return an empty list.
4315 BOOL WINAPI EnumPrintersW(
4316 DWORD dwType, /* [in] Types of print objects to enumerate */
4317 LPWSTR lpszName, /* [in] name of objects to enumerate */
4318 DWORD dwLevel, /* [in] type of printer info structure */
4319 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4320 DWORD cbBuf, /* [in] max size of buffer in bytes */
4321 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4322 LPDWORD lpdwReturned /* [out] number of entries returned */
4325 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4326 lpdwNeeded, lpdwReturned);
4329 /******************************************************************
4330 * EnumPrintersA [WINSPOOL.@]
4332 * See EnumPrintersW
4335 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4336 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4338 BOOL ret;
4339 UNICODE_STRING pNameU;
4340 LPWSTR pNameW;
4341 LPBYTE pPrintersW;
4343 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4344 pPrinters, cbBuf, pcbNeeded, pcReturned);
4346 pNameW = asciitounicode(&pNameU, pName);
4348 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4349 MS Office need this */
4350 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4352 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4354 RtlFreeUnicodeString(&pNameU);
4355 if (ret) {
4356 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4358 HeapFree(GetProcessHeap(), 0, pPrintersW);
4359 return ret;
4362 /*****************************************************************************
4363 * WINSPOOL_GetDriverInfoFromReg [internal]
4365 * Enters the information from the registry into the DRIVER_INFO struct
4367 * RETURNS
4368 * zero if the printer driver does not exist in the registry
4369 * (only if Level > 1) otherwise nonzero
4371 static BOOL WINSPOOL_GetDriverInfoFromReg(
4372 HKEY hkeyDrivers,
4373 LPWSTR DriverName,
4374 const printenv_t * env,
4375 DWORD Level,
4376 LPBYTE ptr, /* DRIVER_INFO */
4377 LPBYTE pDriverStrings, /* strings buffer */
4378 DWORD cbBuf, /* size of string buffer */
4379 LPDWORD pcbNeeded) /* space needed for str. */
4381 DWORD size, tmp;
4382 HKEY hkeyDriver;
4383 WCHAR driverdir[MAX_PATH];
4384 DWORD dirlen;
4385 LPBYTE strPtr = pDriverStrings;
4386 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4388 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4389 debugstr_w(DriverName), env,
4390 Level, di, pDriverStrings, cbBuf);
4392 if (di) ZeroMemory(di, di_sizeof[Level]);
4394 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4395 if (*pcbNeeded <= cbBuf)
4396 strcpyW((LPWSTR)strPtr, DriverName);
4398 /* pName for level 1 has a different offset! */
4399 if (Level == 1) {
4400 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4401 return TRUE;
4404 /* .cVersion and .pName for level > 1 */
4405 if (di) {
4406 di->cVersion = env->driverversion;
4407 di->pName = (LPWSTR) strPtr;
4408 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4411 /* Reserve Space for the largest subdir and a Backslash*/
4412 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4413 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4414 /* Should never Fail */
4415 return FALSE;
4417 lstrcatW(driverdir, env->versionsubdir);
4418 lstrcatW(driverdir, backslashW);
4420 /* dirlen must not include the terminating zero */
4421 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4423 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4424 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4425 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4426 return FALSE;
4429 /* pEnvironment */
4430 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4432 *pcbNeeded += size;
4433 if (*pcbNeeded <= cbBuf) {
4434 lstrcpyW((LPWSTR)strPtr, env->envname);
4435 if (di) di->pEnvironment = (LPWSTR)strPtr;
4436 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4439 /* .pDriverPath is the Graphics rendering engine.
4440 The full Path is required to avoid a crash in some apps */
4441 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4442 *pcbNeeded += size;
4443 if (*pcbNeeded <= cbBuf)
4444 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4446 if (di) di->pDriverPath = (LPWSTR)strPtr;
4447 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4450 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4451 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4452 *pcbNeeded += size;
4453 if (*pcbNeeded <= cbBuf)
4454 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4456 if (di) di->pDataFile = (LPWSTR)strPtr;
4457 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4460 /* .pConfigFile is the Driver user Interface */
4461 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4462 *pcbNeeded += size;
4463 if (*pcbNeeded <= cbBuf)
4464 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4466 if (di) di->pConfigFile = (LPWSTR)strPtr;
4467 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4470 if (Level == 2 ) {
4471 RegCloseKey(hkeyDriver);
4472 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4473 return TRUE;
4476 if (Level == 5 ) {
4477 RegCloseKey(hkeyDriver);
4478 FIXME("level 5: incomplete\n");
4479 return TRUE;
4482 /* .pHelpFile */
4483 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4484 *pcbNeeded += size;
4485 if (*pcbNeeded <= cbBuf)
4486 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4488 if (di) di->pHelpFile = (LPWSTR)strPtr;
4489 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4492 /* .pDependentFiles */
4493 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4494 *pcbNeeded += size;
4495 if (*pcbNeeded <= cbBuf)
4496 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4498 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4499 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4501 else if (GetVersion() & 0x80000000) {
4502 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4503 size = 2 * sizeof(WCHAR);
4504 *pcbNeeded += size;
4505 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4507 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4508 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4511 /* .pMonitorName is the optional Language Monitor */
4512 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4513 *pcbNeeded += size;
4514 if (*pcbNeeded <= cbBuf)
4515 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4517 if (di) di->pMonitorName = (LPWSTR)strPtr;
4518 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4521 /* .pDefaultDataType */
4522 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4523 *pcbNeeded += size;
4524 if(*pcbNeeded <= cbBuf)
4525 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4527 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4528 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4531 if (Level == 3 ) {
4532 RegCloseKey(hkeyDriver);
4533 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4534 return TRUE;
4537 /* .pszzPreviousNames */
4538 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4539 *pcbNeeded += size;
4540 if(*pcbNeeded <= cbBuf)
4541 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4543 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4544 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4547 if (Level == 4 ) {
4548 RegCloseKey(hkeyDriver);
4549 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4550 return TRUE;
4553 /* support is missing, but not important enough for a FIXME */
4554 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4556 /* .pszMfgName */
4557 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4558 *pcbNeeded += size;
4559 if(*pcbNeeded <= cbBuf)
4560 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4562 if (di) di->pszMfgName = (LPWSTR)strPtr;
4563 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4566 /* .pszOEMUrl */
4567 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4568 *pcbNeeded += size;
4569 if(*pcbNeeded <= cbBuf)
4570 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4572 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4573 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4576 /* .pszHardwareID */
4577 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4578 *pcbNeeded += size;
4579 if(*pcbNeeded <= cbBuf)
4580 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4582 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4583 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4586 /* .pszProvider */
4587 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4588 *pcbNeeded += size;
4589 if(*pcbNeeded <= cbBuf)
4590 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4592 if (di) di->pszProvider = (LPWSTR)strPtr;
4593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4596 if (Level == 6 ) {
4597 RegCloseKey(hkeyDriver);
4598 return TRUE;
4601 /* support is missing, but not important enough for a FIXME */
4602 TRACE("level 8: incomplete\n");
4604 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4605 RegCloseKey(hkeyDriver);
4606 return TRUE;
4609 /*****************************************************************************
4610 * GetPrinterDriverW [WINSPOOL.@]
4612 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4613 DWORD Level, LPBYTE pDriverInfo,
4614 DWORD cbBuf, LPDWORD pcbNeeded)
4616 LPCWSTR name;
4617 WCHAR DriverName[100];
4618 DWORD ret, type, size, needed = 0;
4619 LPBYTE ptr = NULL;
4620 HKEY hkeyPrinter, hkeyDrivers;
4621 const printenv_t * env;
4623 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4624 Level,pDriverInfo,cbBuf, pcbNeeded);
4626 if (cbBuf > 0)
4627 ZeroMemory(pDriverInfo, cbBuf);
4629 if (!(name = get_opened_printer_name(hPrinter))) {
4630 SetLastError(ERROR_INVALID_HANDLE);
4631 return FALSE;
4634 if (Level < 1 || Level == 7 || Level > 8) {
4635 SetLastError(ERROR_INVALID_LEVEL);
4636 return FALSE;
4639 env = validate_envW(pEnvironment);
4640 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4642 ret = open_printer_reg_key( name, &hkeyPrinter );
4643 if (ret)
4645 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4646 SetLastError( ret );
4647 return FALSE;
4650 size = sizeof(DriverName);
4651 DriverName[0] = 0;
4652 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4653 (LPBYTE)DriverName, &size);
4654 RegCloseKey(hkeyPrinter);
4655 if(ret != ERROR_SUCCESS) {
4656 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4657 return FALSE;
4660 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4661 if(!hkeyDrivers) {
4662 ERR("Can't create Drivers key\n");
4663 return FALSE;
4666 size = di_sizeof[Level];
4667 if ((size <= cbBuf) && pDriverInfo)
4668 ptr = pDriverInfo + size;
4670 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4671 env, Level, pDriverInfo, ptr,
4672 (cbBuf < size) ? 0 : cbBuf - size,
4673 &needed)) {
4674 RegCloseKey(hkeyDrivers);
4675 return FALSE;
4678 RegCloseKey(hkeyDrivers);
4680 if(pcbNeeded) *pcbNeeded = size + needed;
4681 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4682 if(cbBuf >= size + needed) return TRUE;
4683 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4684 return FALSE;
4687 /*****************************************************************************
4688 * GetPrinterDriverA [WINSPOOL.@]
4690 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4691 DWORD Level, LPBYTE pDriverInfo,
4692 DWORD cbBuf, LPDWORD pcbNeeded)
4694 BOOL ret;
4695 UNICODE_STRING pEnvW;
4696 PWSTR pwstrEnvW;
4697 LPBYTE buf = NULL;
4699 if (cbBuf)
4701 ZeroMemory(pDriverInfo, cbBuf);
4702 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4705 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4706 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4707 cbBuf, pcbNeeded);
4708 if (ret)
4709 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4711 HeapFree(GetProcessHeap(), 0, buf);
4713 RtlFreeUnicodeString(&pEnvW);
4714 return ret;
4717 /*****************************************************************************
4718 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4720 * Return the PATH for the Printer-Drivers (UNICODE)
4722 * PARAMS
4723 * pName [I] Servername (NT only) or NULL (local Computer)
4724 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4725 * Level [I] Structure-Level (must be 1)
4726 * pDriverDirectory [O] PTR to Buffer that receives the Result
4727 * cbBuf [I] Size of Buffer at pDriverDirectory
4728 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4729 * required for pDriverDirectory
4731 * RETURNS
4732 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4733 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4734 * if cbBuf is too small
4736 * Native Values returned in pDriverDirectory on Success:
4737 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4738 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4739 *| win9x(Windows 4.0): "%winsysdir%"
4741 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4743 * FIXME
4744 *- Only NULL or "" is supported for pName
4747 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4748 DWORD Level, LPBYTE pDriverDirectory,
4749 DWORD cbBuf, LPDWORD pcbNeeded)
4751 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4752 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4754 if ((backend == NULL) && !load_backend()) return FALSE;
4756 if (Level != 1) {
4757 /* (Level != 1) is ignored in win9x */
4758 SetLastError(ERROR_INVALID_LEVEL);
4759 return FALSE;
4761 if (pcbNeeded == NULL) {
4762 /* (pcbNeeded == NULL) is ignored in win9x */
4763 SetLastError(RPC_X_NULL_REF_POINTER);
4764 return FALSE;
4767 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4768 pDriverDirectory, cbBuf, pcbNeeded);
4773 /*****************************************************************************
4774 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4776 * Return the PATH for the Printer-Drivers (ANSI)
4778 * See GetPrinterDriverDirectoryW.
4780 * NOTES
4781 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4784 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4785 DWORD Level, LPBYTE pDriverDirectory,
4786 DWORD cbBuf, LPDWORD pcbNeeded)
4788 UNICODE_STRING nameW, environmentW;
4789 BOOL ret;
4790 DWORD pcbNeededW;
4791 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4792 WCHAR *driverDirectoryW = NULL;
4794 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4795 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4797 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4799 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4800 else nameW.Buffer = NULL;
4801 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4802 else environmentW.Buffer = NULL;
4804 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4805 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4806 if (ret) {
4807 DWORD needed;
4808 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4809 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4810 if(pcbNeeded)
4811 *pcbNeeded = needed;
4812 ret = (needed <= cbBuf) ? TRUE : FALSE;
4813 } else
4814 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4816 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4818 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4819 RtlFreeUnicodeString(&environmentW);
4820 RtlFreeUnicodeString(&nameW);
4822 return ret;
4825 /*****************************************************************************
4826 * AddPrinterDriverA [WINSPOOL.@]
4828 * See AddPrinterDriverW.
4831 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4833 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4834 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4837 /******************************************************************************
4838 * AddPrinterDriverW (WINSPOOL.@)
4840 * Install a Printer Driver
4842 * PARAMS
4843 * pName [I] Servername or NULL (local Computer)
4844 * level [I] Level for the supplied DRIVER_INFO_*W struct
4845 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4847 * RESULTS
4848 * Success: TRUE
4849 * Failure: FALSE
4852 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4854 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4855 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4858 /*****************************************************************************
4859 * AddPrintProcessorA [WINSPOOL.@]
4861 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4862 LPSTR pPrintProcessorName)
4864 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4865 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4866 return FALSE;
4869 /*****************************************************************************
4870 * AddPrintProcessorW [WINSPOOL.@]
4872 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4873 LPWSTR pPrintProcessorName)
4875 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4876 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4877 return TRUE;
4880 /*****************************************************************************
4881 * AddPrintProvidorA [WINSPOOL.@]
4883 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4885 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4886 return FALSE;
4889 /*****************************************************************************
4890 * AddPrintProvidorW [WINSPOOL.@]
4892 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4894 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4895 return FALSE;
4898 /*****************************************************************************
4899 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4901 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4902 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4904 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4905 pDevModeOutput, pDevModeInput);
4906 return 0;
4909 /*****************************************************************************
4910 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4912 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4913 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4915 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4916 pDevModeOutput, pDevModeInput);
4917 return 0;
4920 /*****************************************************************************
4921 * PrinterProperties [WINSPOOL.@]
4923 * Displays a dialog to set the properties of the printer.
4925 * RETURNS
4926 * nonzero on success or zero on failure
4928 * BUGS
4929 * implemented as stub only
4931 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4932 HANDLE hPrinter /* [in] handle to printer object */
4934 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4935 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4936 return FALSE;
4939 /*****************************************************************************
4940 * EnumJobsA [WINSPOOL.@]
4943 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4944 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4945 LPDWORD pcReturned)
4947 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4948 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4950 if(pcbNeeded) *pcbNeeded = 0;
4951 if(pcReturned) *pcReturned = 0;
4952 return FALSE;
4956 /*****************************************************************************
4957 * EnumJobsW [WINSPOOL.@]
4960 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4961 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4962 LPDWORD pcReturned)
4964 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4965 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4967 if(pcbNeeded) *pcbNeeded = 0;
4968 if(pcReturned) *pcReturned = 0;
4969 return FALSE;
4972 /*****************************************************************************
4973 * WINSPOOL_EnumPrinterDrivers [internal]
4975 * Delivers information about all printer drivers installed on the
4976 * localhost or a given server
4978 * RETURNS
4979 * nonzero on success or zero on failure. If the buffer for the returned
4980 * information is too small the function will return an error
4982 * BUGS
4983 * - only implemented for localhost, foreign hosts will return an error
4985 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4986 DWORD Level, LPBYTE pDriverInfo,
4987 DWORD driver_index,
4988 DWORD cbBuf, LPDWORD pcbNeeded,
4989 LPDWORD pcFound, DWORD data_offset)
4991 { HKEY hkeyDrivers;
4992 DWORD i, size = 0;
4993 const printenv_t * env;
4995 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4996 debugstr_w(pName), debugstr_w(pEnvironment),
4997 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4999 env = validate_envW(pEnvironment);
5000 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5002 *pcFound = 0;
5004 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5005 if(!hkeyDrivers) {
5006 ERR("Can't open Drivers key\n");
5007 return FALSE;
5010 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5011 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5012 RegCloseKey(hkeyDrivers);
5013 ERR("Can't query Drivers key\n");
5014 return FALSE;
5016 TRACE("Found %d Drivers\n", *pcFound);
5018 /* get size of single struct
5019 * unicode and ascii structure have the same size
5021 size = di_sizeof[Level];
5023 if (data_offset == 0)
5024 data_offset = size * (*pcFound);
5025 *pcbNeeded = data_offset;
5027 for( i = 0; i < *pcFound; i++) {
5028 WCHAR DriverNameW[255];
5029 PBYTE table_ptr = NULL;
5030 PBYTE data_ptr = NULL;
5031 DWORD needed = 0;
5033 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5034 != ERROR_SUCCESS) {
5035 ERR("Can't enum key number %d\n", i);
5036 RegCloseKey(hkeyDrivers);
5037 return FALSE;
5040 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5041 table_ptr = pDriverInfo + (driver_index + i) * size;
5042 if (pDriverInfo && *pcbNeeded <= cbBuf)
5043 data_ptr = pDriverInfo + *pcbNeeded;
5045 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5046 env, Level, table_ptr, data_ptr,
5047 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5048 &needed)) {
5049 RegCloseKey(hkeyDrivers);
5050 return FALSE;
5053 *pcbNeeded += needed;
5056 RegCloseKey(hkeyDrivers);
5058 if(cbBuf < *pcbNeeded){
5059 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5060 return FALSE;
5063 return TRUE;
5066 /*****************************************************************************
5067 * EnumPrinterDriversW [WINSPOOL.@]
5069 * see function EnumPrinterDrivers for RETURNS, BUGS
5071 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5072 LPBYTE pDriverInfo, DWORD cbBuf,
5073 LPDWORD pcbNeeded, LPDWORD pcReturned)
5075 static const WCHAR allW[] = {'a','l','l',0};
5076 BOOL ret;
5077 DWORD found;
5079 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5081 SetLastError(RPC_X_NULL_REF_POINTER);
5082 return FALSE;
5085 /* check for local drivers */
5086 if((pName) && (pName[0])) {
5087 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5088 SetLastError(ERROR_ACCESS_DENIED);
5089 return FALSE;
5092 /* check input parameter */
5093 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5094 SetLastError(ERROR_INVALID_LEVEL);
5095 return FALSE;
5098 if(pDriverInfo && cbBuf > 0)
5099 memset( pDriverInfo, 0, cbBuf);
5101 /* Exception: pull all printers */
5102 if (pEnvironment && !strcmpW(pEnvironment, allW))
5104 DWORD i, needed, bufsize = cbBuf;
5105 DWORD total_needed = 0;
5106 DWORD total_found = 0;
5107 DWORD data_offset;
5109 /* Precompute the overall total; we need this to know
5110 where pointers end and data begins (i.e. data_offset) */
5111 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5113 needed = found = 0;
5114 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5115 NULL, 0, 0, &needed, &found, 0);
5116 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5117 total_needed += needed;
5118 total_found += found;
5121 data_offset = di_sizeof[Level] * total_found;
5123 *pcReturned = 0;
5124 *pcbNeeded = 0;
5125 total_found = 0;
5126 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5128 needed = found = 0;
5129 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5130 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5131 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5132 else if (ret)
5133 *pcReturned += found;
5134 *pcbNeeded = needed;
5135 data_offset = needed;
5136 total_found += found;
5138 return ret;
5141 /* Normal behavior */
5142 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5143 0, cbBuf, pcbNeeded, &found, 0);
5144 if (ret)
5145 *pcReturned = found;
5147 return ret;
5150 /*****************************************************************************
5151 * EnumPrinterDriversA [WINSPOOL.@]
5153 * see function EnumPrinterDrivers for RETURNS, BUGS
5155 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5156 LPBYTE pDriverInfo, DWORD cbBuf,
5157 LPDWORD pcbNeeded, LPDWORD pcReturned)
5159 BOOL ret;
5160 UNICODE_STRING pNameW, pEnvironmentW;
5161 PWSTR pwstrNameW, pwstrEnvironmentW;
5162 LPBYTE buf = NULL;
5164 if (cbBuf)
5165 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5167 pwstrNameW = asciitounicode(&pNameW, pName);
5168 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5170 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5171 buf, cbBuf, pcbNeeded, pcReturned);
5172 if (ret)
5173 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5175 HeapFree(GetProcessHeap(), 0, buf);
5177 RtlFreeUnicodeString(&pNameW);
5178 RtlFreeUnicodeString(&pEnvironmentW);
5180 return ret;
5183 /******************************************************************************
5184 * EnumPortsA (WINSPOOL.@)
5186 * See EnumPortsW.
5189 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5190 LPDWORD pcbNeeded, LPDWORD pcReturned)
5192 BOOL res;
5193 LPBYTE bufferW = NULL;
5194 LPWSTR nameW = NULL;
5195 DWORD needed = 0;
5196 DWORD numentries = 0;
5197 INT len;
5199 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5200 cbBuf, pcbNeeded, pcReturned);
5202 /* convert servername to unicode */
5203 if (pName) {
5204 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5205 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5206 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5208 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5209 needed = cbBuf * sizeof(WCHAR);
5210 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5211 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5213 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5214 if (pcbNeeded) needed = *pcbNeeded;
5215 /* HeapReAlloc return NULL, when bufferW was NULL */
5216 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5217 HeapAlloc(GetProcessHeap(), 0, needed);
5219 /* Try again with the large Buffer */
5220 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5222 needed = pcbNeeded ? *pcbNeeded : 0;
5223 numentries = pcReturned ? *pcReturned : 0;
5226 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5227 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5229 if (res) {
5230 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5231 DWORD entrysize = 0;
5232 DWORD index;
5233 LPSTR ptr;
5234 LPPORT_INFO_2W pi2w;
5235 LPPORT_INFO_2A pi2a;
5237 needed = 0;
5238 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5240 /* First pass: calculate the size for all Entries */
5241 pi2w = (LPPORT_INFO_2W) bufferW;
5242 pi2a = (LPPORT_INFO_2A) pPorts;
5243 index = 0;
5244 while (index < numentries) {
5245 index++;
5246 needed += entrysize; /* PORT_INFO_?A */
5247 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5249 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5250 NULL, 0, NULL, NULL);
5251 if (Level > 1) {
5252 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5253 NULL, 0, NULL, NULL);
5254 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5255 NULL, 0, NULL, NULL);
5257 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5258 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5259 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5262 /* check for errors and quit on failure */
5263 if (cbBuf < needed) {
5264 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5265 res = FALSE;
5266 goto cleanup;
5268 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5269 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5270 cbBuf -= len ; /* free Bytes in the user-Buffer */
5271 pi2w = (LPPORT_INFO_2W) bufferW;
5272 pi2a = (LPPORT_INFO_2A) pPorts;
5273 index = 0;
5274 /* Second Pass: Fill the User Buffer (if we have one) */
5275 while ((index < numentries) && pPorts) {
5276 index++;
5277 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5278 pi2a->pPortName = ptr;
5279 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5280 ptr, cbBuf , NULL, NULL);
5281 ptr += len;
5282 cbBuf -= len;
5283 if (Level > 1) {
5284 pi2a->pMonitorName = ptr;
5285 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5286 ptr, cbBuf, NULL, NULL);
5287 ptr += len;
5288 cbBuf -= len;
5290 pi2a->pDescription = ptr;
5291 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5292 ptr, cbBuf, NULL, NULL);
5293 ptr += len;
5294 cbBuf -= len;
5296 pi2a->fPortType = pi2w->fPortType;
5297 pi2a->Reserved = 0; /* documented: "must be zero" */
5300 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5301 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5302 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5306 cleanup:
5307 if (pcbNeeded) *pcbNeeded = needed;
5308 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5310 HeapFree(GetProcessHeap(), 0, nameW);
5311 HeapFree(GetProcessHeap(), 0, bufferW);
5313 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5314 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5316 return (res);
5320 /******************************************************************************
5321 * EnumPortsW (WINSPOOL.@)
5323 * Enumerate available Ports
5325 * PARAMS
5326 * pName [I] Servername or NULL (local Computer)
5327 * Level [I] Structure-Level (1 or 2)
5328 * pPorts [O] PTR to Buffer that receives the Result
5329 * cbBuf [I] Size of Buffer at pPorts
5330 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5331 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5333 * RETURNS
5334 * Success: TRUE
5335 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5338 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5341 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5342 cbBuf, pcbNeeded, pcReturned);
5344 if ((backend == NULL) && !load_backend()) return FALSE;
5346 /* Level is not checked in win9x */
5347 if (!Level || (Level > 2)) {
5348 WARN("level (%d) is ignored in win9x\n", Level);
5349 SetLastError(ERROR_INVALID_LEVEL);
5350 return FALSE;
5352 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5353 SetLastError(RPC_X_NULL_REF_POINTER);
5354 return FALSE;
5357 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5360 /******************************************************************************
5361 * GetDefaultPrinterW (WINSPOOL.@)
5363 * FIXME
5364 * This function must read the value from data 'device' of key
5365 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5367 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5369 BOOL retval = TRUE;
5370 DWORD insize, len;
5371 WCHAR *buffer, *ptr;
5373 if (!namesize)
5375 SetLastError(ERROR_INVALID_PARAMETER);
5376 return FALSE;
5379 /* make the buffer big enough for the stuff from the profile/registry,
5380 * the content must fit into the local buffer to compute the correct
5381 * size even if the extern buffer is too small or not given.
5382 * (20 for ,driver,port) */
5383 insize = *namesize;
5384 len = max(100, (insize + 20));
5385 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5387 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5389 SetLastError (ERROR_FILE_NOT_FOUND);
5390 retval = FALSE;
5391 goto end;
5393 TRACE("%s\n", debugstr_w(buffer));
5395 if ((ptr = strchrW(buffer, ',')) == NULL)
5397 SetLastError(ERROR_INVALID_NAME);
5398 retval = FALSE;
5399 goto end;
5402 *ptr = 0;
5403 *namesize = strlenW(buffer) + 1;
5404 if(!name || (*namesize > insize))
5406 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5407 retval = FALSE;
5408 goto end;
5410 strcpyW(name, buffer);
5412 end:
5413 HeapFree( GetProcessHeap(), 0, buffer);
5414 return retval;
5418 /******************************************************************************
5419 * GetDefaultPrinterA (WINSPOOL.@)
5421 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5423 BOOL retval = TRUE;
5424 DWORD insize = 0;
5425 WCHAR *bufferW = NULL;
5427 if (!namesize)
5429 SetLastError(ERROR_INVALID_PARAMETER);
5430 return FALSE;
5433 if(name && *namesize) {
5434 insize = *namesize;
5435 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5438 if(!GetDefaultPrinterW( bufferW, namesize)) {
5439 retval = FALSE;
5440 goto end;
5443 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5444 NULL, NULL);
5445 if (!*namesize)
5447 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5448 retval = FALSE;
5450 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5452 end:
5453 HeapFree( GetProcessHeap(), 0, bufferW);
5454 return retval;
5458 /******************************************************************************
5459 * SetDefaultPrinterW (WINSPOOL.204)
5461 * Set the Name of the Default Printer
5463 * PARAMS
5464 * pszPrinter [I] Name of the Printer or NULL
5466 * RETURNS
5467 * Success: True
5468 * Failure: FALSE
5470 * NOTES
5471 * When the Parameter is NULL or points to an Empty String and
5472 * a Default Printer was already present, then this Function changes nothing.
5473 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5474 * the First enumerated local Printer is used.
5477 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5479 WCHAR default_printer[MAX_PATH];
5480 LPWSTR buffer = NULL;
5481 HKEY hreg;
5482 DWORD size;
5483 DWORD namelen;
5484 LONG lres;
5486 TRACE("(%s)\n", debugstr_w(pszPrinter));
5487 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5489 default_printer[0] = '\0';
5490 size = sizeof(default_printer)/sizeof(WCHAR);
5492 /* if we have a default Printer, do nothing. */
5493 if (GetDefaultPrinterW(default_printer, &size))
5494 return TRUE;
5496 pszPrinter = NULL;
5497 /* we have no default Printer: search local Printers and use the first */
5498 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5500 default_printer[0] = '\0';
5501 size = sizeof(default_printer)/sizeof(WCHAR);
5502 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5504 pszPrinter = default_printer;
5505 TRACE("using %s\n", debugstr_w(pszPrinter));
5507 RegCloseKey(hreg);
5510 if (pszPrinter == NULL) {
5511 TRACE("no local printer found\n");
5512 SetLastError(ERROR_FILE_NOT_FOUND);
5513 return FALSE;
5517 /* "pszPrinter" is never empty or NULL here. */
5518 namelen = lstrlenW(pszPrinter);
5519 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5520 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5521 if (!buffer ||
5522 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5523 HeapFree(GetProcessHeap(), 0, buffer);
5524 SetLastError(ERROR_FILE_NOT_FOUND);
5525 return FALSE;
5528 /* read the devices entry for the printer (driver,port) to build the string for the
5529 default device entry (printer,driver,port) */
5530 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5531 buffer[namelen] = ',';
5532 namelen++; /* move index to the start of the driver */
5534 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5535 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5536 if (!lres) {
5537 TRACE("set device to %s\n", debugstr_w(buffer));
5539 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5540 TRACE("failed to set the device entry: %d\n", GetLastError());
5541 lres = ERROR_INVALID_PRINTER_NAME;
5544 /* remove the next section, when INIFileMapping is implemented */
5546 HKEY hdev;
5547 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5548 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5549 RegCloseKey(hdev);
5553 else
5555 if (lres != ERROR_FILE_NOT_FOUND)
5556 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5558 SetLastError(ERROR_INVALID_PRINTER_NAME);
5561 RegCloseKey(hreg);
5562 HeapFree(GetProcessHeap(), 0, buffer);
5563 return (lres == ERROR_SUCCESS);
5566 /******************************************************************************
5567 * SetDefaultPrinterA (WINSPOOL.202)
5569 * See SetDefaultPrinterW.
5572 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5574 LPWSTR bufferW = NULL;
5575 BOOL res;
5577 TRACE("(%s)\n", debugstr_a(pszPrinter));
5578 if(pszPrinter) {
5579 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5580 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5581 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5583 res = SetDefaultPrinterW(bufferW);
5584 HeapFree(GetProcessHeap(), 0, bufferW);
5585 return res;
5588 /******************************************************************************
5589 * SetPrinterDataExA (WINSPOOL.@)
5591 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5592 LPCSTR pValueName, DWORD Type,
5593 LPBYTE pData, DWORD cbData)
5595 HKEY hkeyPrinter, hkeySubkey;
5596 DWORD ret;
5598 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5599 debugstr_a(pValueName), Type, pData, cbData);
5601 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5602 != ERROR_SUCCESS)
5603 return ret;
5605 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5606 != ERROR_SUCCESS) {
5607 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5608 RegCloseKey(hkeyPrinter);
5609 return ret;
5611 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5612 RegCloseKey(hkeySubkey);
5613 RegCloseKey(hkeyPrinter);
5614 return ret;
5617 /******************************************************************************
5618 * SetPrinterDataExW (WINSPOOL.@)
5620 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5621 LPCWSTR pValueName, DWORD Type,
5622 LPBYTE pData, DWORD cbData)
5624 HKEY hkeyPrinter, hkeySubkey;
5625 DWORD ret;
5627 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5628 debugstr_w(pValueName), Type, pData, cbData);
5630 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5631 != ERROR_SUCCESS)
5632 return ret;
5634 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5635 != ERROR_SUCCESS) {
5636 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5637 RegCloseKey(hkeyPrinter);
5638 return ret;
5640 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5641 RegCloseKey(hkeySubkey);
5642 RegCloseKey(hkeyPrinter);
5643 return ret;
5646 /******************************************************************************
5647 * SetPrinterDataA (WINSPOOL.@)
5649 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5650 LPBYTE pData, DWORD cbData)
5652 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5653 pData, cbData);
5656 /******************************************************************************
5657 * SetPrinterDataW (WINSPOOL.@)
5659 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5660 LPBYTE pData, DWORD cbData)
5662 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5663 pData, cbData);
5666 /******************************************************************************
5667 * GetPrinterDataExA (WINSPOOL.@)
5669 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5670 LPCSTR pValueName, LPDWORD pType,
5671 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5673 opened_printer_t *printer;
5674 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5675 DWORD ret;
5677 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5678 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5680 printer = get_opened_printer(hPrinter);
5681 if(!printer) return ERROR_INVALID_HANDLE;
5683 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5684 if (ret) return ret;
5686 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5688 if (printer->name) {
5690 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5691 if (ret) {
5692 RegCloseKey(hkeyPrinters);
5693 return ret;
5695 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5696 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5697 RegCloseKey(hkeyPrinter);
5698 RegCloseKey(hkeyPrinters);
5699 return ret;
5702 *pcbNeeded = nSize;
5703 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5704 0, pType, pData, pcbNeeded);
5706 if (!ret && !pData) ret = ERROR_MORE_DATA;
5708 RegCloseKey(hkeySubkey);
5709 RegCloseKey(hkeyPrinter);
5710 RegCloseKey(hkeyPrinters);
5712 TRACE("--> %d\n", ret);
5713 return ret;
5716 /******************************************************************************
5717 * GetPrinterDataExW (WINSPOOL.@)
5719 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5720 LPCWSTR pValueName, LPDWORD pType,
5721 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5723 opened_printer_t *printer;
5724 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5725 DWORD ret;
5727 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5728 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5730 printer = get_opened_printer(hPrinter);
5731 if(!printer) return ERROR_INVALID_HANDLE;
5733 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5734 if (ret) return ret;
5736 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5738 if (printer->name) {
5740 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5741 if (ret) {
5742 RegCloseKey(hkeyPrinters);
5743 return ret;
5745 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5746 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5747 RegCloseKey(hkeyPrinter);
5748 RegCloseKey(hkeyPrinters);
5749 return ret;
5752 *pcbNeeded = nSize;
5753 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5754 0, pType, pData, pcbNeeded);
5756 if (!ret && !pData) ret = ERROR_MORE_DATA;
5758 RegCloseKey(hkeySubkey);
5759 RegCloseKey(hkeyPrinter);
5760 RegCloseKey(hkeyPrinters);
5762 TRACE("--> %d\n", ret);
5763 return ret;
5766 /******************************************************************************
5767 * GetPrinterDataA (WINSPOOL.@)
5769 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5770 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5772 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5773 pData, nSize, pcbNeeded);
5776 /******************************************************************************
5777 * GetPrinterDataW (WINSPOOL.@)
5779 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5780 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5782 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5783 pData, nSize, pcbNeeded);
5786 /*******************************************************************************
5787 * EnumPrinterDataExW [WINSPOOL.@]
5789 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5790 LPBYTE pEnumValues, DWORD cbEnumValues,
5791 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5793 HKEY hkPrinter, hkSubKey;
5794 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5795 cbValueNameLen, cbMaxValueLen, cbValueLen,
5796 cbBufSize, dwType;
5797 LPWSTR lpValueName;
5798 HANDLE hHeap;
5799 PBYTE lpValue;
5800 PPRINTER_ENUM_VALUESW ppev;
5802 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5804 if (pKeyName == NULL || *pKeyName == 0)
5805 return ERROR_INVALID_PARAMETER;
5807 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5808 if (ret != ERROR_SUCCESS)
5810 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5811 hPrinter, ret);
5812 return ret;
5815 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5816 if (ret != ERROR_SUCCESS)
5818 r = RegCloseKey (hkPrinter);
5819 if (r != ERROR_SUCCESS)
5820 WARN ("RegCloseKey returned %i\n", r);
5821 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5822 debugstr_w (pKeyName), ret);
5823 return ret;
5826 ret = RegCloseKey (hkPrinter);
5827 if (ret != ERROR_SUCCESS)
5829 ERR ("RegCloseKey returned %i\n", ret);
5830 r = RegCloseKey (hkSubKey);
5831 if (r != ERROR_SUCCESS)
5832 WARN ("RegCloseKey returned %i\n", r);
5833 return ret;
5836 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5837 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5838 if (ret != ERROR_SUCCESS)
5840 r = RegCloseKey (hkSubKey);
5841 if (r != ERROR_SUCCESS)
5842 WARN ("RegCloseKey returned %i\n", r);
5843 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5844 return ret;
5847 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5848 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5850 if (cValues == 0) /* empty key */
5852 r = RegCloseKey (hkSubKey);
5853 if (r != ERROR_SUCCESS)
5854 WARN ("RegCloseKey returned %i\n", r);
5855 *pcbEnumValues = *pnEnumValues = 0;
5856 return ERROR_SUCCESS;
5859 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5861 hHeap = GetProcessHeap ();
5862 if (hHeap == NULL)
5864 ERR ("GetProcessHeap failed\n");
5865 r = RegCloseKey (hkSubKey);
5866 if (r != ERROR_SUCCESS)
5867 WARN ("RegCloseKey returned %i\n", r);
5868 return ERROR_OUTOFMEMORY;
5871 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5872 if (lpValueName == NULL)
5874 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5875 r = RegCloseKey (hkSubKey);
5876 if (r != ERROR_SUCCESS)
5877 WARN ("RegCloseKey returned %i\n", r);
5878 return ERROR_OUTOFMEMORY;
5881 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5882 if (lpValue == NULL)
5884 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5885 if (HeapFree (hHeap, 0, lpValueName) == 0)
5886 WARN ("HeapFree failed with code %i\n", GetLastError ());
5887 r = RegCloseKey (hkSubKey);
5888 if (r != ERROR_SUCCESS)
5889 WARN ("RegCloseKey returned %i\n", r);
5890 return ERROR_OUTOFMEMORY;
5893 TRACE ("pass 1: calculating buffer required for all names and values\n");
5895 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5897 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5899 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5901 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5902 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5903 NULL, NULL, lpValue, &cbValueLen);
5904 if (ret != ERROR_SUCCESS)
5906 if (HeapFree (hHeap, 0, lpValue) == 0)
5907 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 if (HeapFree (hHeap, 0, lpValueName) == 0)
5909 WARN ("HeapFree failed with code %i\n", GetLastError ());
5910 r = RegCloseKey (hkSubKey);
5911 if (r != ERROR_SUCCESS)
5912 WARN ("RegCloseKey returned %i\n", r);
5913 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5914 return ret;
5917 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5918 debugstr_w (lpValueName), dwIndex,
5919 cbValueNameLen + 1, cbValueLen);
5921 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5922 cbBufSize += cbValueLen;
5925 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5927 *pcbEnumValues = cbBufSize;
5928 *pnEnumValues = cValues;
5930 if (cbEnumValues < cbBufSize) /* buffer too small */
5932 if (HeapFree (hHeap, 0, lpValue) == 0)
5933 WARN ("HeapFree failed with code %i\n", GetLastError ());
5934 if (HeapFree (hHeap, 0, lpValueName) == 0)
5935 WARN ("HeapFree failed with code %i\n", GetLastError ());
5936 r = RegCloseKey (hkSubKey);
5937 if (r != ERROR_SUCCESS)
5938 WARN ("RegCloseKey returned %i\n", r);
5939 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5940 return ERROR_MORE_DATA;
5943 TRACE ("pass 2: copying all names and values to buffer\n");
5945 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5946 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5948 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5950 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5951 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5952 NULL, &dwType, lpValue, &cbValueLen);
5953 if (ret != ERROR_SUCCESS)
5955 if (HeapFree (hHeap, 0, lpValue) == 0)
5956 WARN ("HeapFree failed with code %i\n", GetLastError ());
5957 if (HeapFree (hHeap, 0, lpValueName) == 0)
5958 WARN ("HeapFree failed with code %i\n", GetLastError ());
5959 r = RegCloseKey (hkSubKey);
5960 if (r != ERROR_SUCCESS)
5961 WARN ("RegCloseKey returned %i\n", r);
5962 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5963 return ret;
5966 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5967 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5968 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5969 pEnumValues += cbValueNameLen;
5971 /* return # of *bytes* (including trailing \0), not # of chars */
5972 ppev[dwIndex].cbValueName = cbValueNameLen;
5974 ppev[dwIndex].dwType = dwType;
5976 memcpy (pEnumValues, lpValue, cbValueLen);
5977 ppev[dwIndex].pData = pEnumValues;
5978 pEnumValues += cbValueLen;
5980 ppev[dwIndex].cbData = cbValueLen;
5982 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5983 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5986 if (HeapFree (hHeap, 0, lpValue) == 0)
5988 ret = GetLastError ();
5989 ERR ("HeapFree failed with code %i\n", ret);
5990 if (HeapFree (hHeap, 0, lpValueName) == 0)
5991 WARN ("HeapFree failed with code %i\n", GetLastError ());
5992 r = RegCloseKey (hkSubKey);
5993 if (r != ERROR_SUCCESS)
5994 WARN ("RegCloseKey returned %i\n", r);
5995 return ret;
5998 if (HeapFree (hHeap, 0, lpValueName) == 0)
6000 ret = GetLastError ();
6001 ERR ("HeapFree failed with code %i\n", ret);
6002 r = RegCloseKey (hkSubKey);
6003 if (r != ERROR_SUCCESS)
6004 WARN ("RegCloseKey returned %i\n", r);
6005 return ret;
6008 ret = RegCloseKey (hkSubKey);
6009 if (ret != ERROR_SUCCESS)
6011 ERR ("RegCloseKey returned %i\n", ret);
6012 return ret;
6015 return ERROR_SUCCESS;
6018 /*******************************************************************************
6019 * EnumPrinterDataExA [WINSPOOL.@]
6021 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6022 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6023 * what Windows 2000 SP1 does.
6026 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6027 LPBYTE pEnumValues, DWORD cbEnumValues,
6028 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6030 INT len;
6031 LPWSTR pKeyNameW;
6032 DWORD ret, dwIndex, dwBufSize;
6033 HANDLE hHeap;
6034 LPSTR pBuffer;
6036 TRACE ("%p %s\n", hPrinter, pKeyName);
6038 if (pKeyName == NULL || *pKeyName == 0)
6039 return ERROR_INVALID_PARAMETER;
6041 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6042 if (len == 0)
6044 ret = GetLastError ();
6045 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6046 return ret;
6049 hHeap = GetProcessHeap ();
6050 if (hHeap == NULL)
6052 ERR ("GetProcessHeap failed\n");
6053 return ERROR_OUTOFMEMORY;
6056 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6057 if (pKeyNameW == NULL)
6059 ERR ("Failed to allocate %i bytes from process heap\n",
6060 (LONG)(len * sizeof (WCHAR)));
6061 return ERROR_OUTOFMEMORY;
6064 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6066 ret = GetLastError ();
6067 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6068 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6069 WARN ("HeapFree failed with code %i\n", GetLastError ());
6070 return ret;
6073 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6074 pcbEnumValues, pnEnumValues);
6075 if (ret != ERROR_SUCCESS)
6077 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6078 WARN ("HeapFree failed with code %i\n", GetLastError ());
6079 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6080 return ret;
6083 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6085 ret = GetLastError ();
6086 ERR ("HeapFree failed with code %i\n", ret);
6087 return ret;
6090 if (*pnEnumValues == 0) /* empty key */
6091 return ERROR_SUCCESS;
6093 dwBufSize = 0;
6094 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6096 PPRINTER_ENUM_VALUESW ppev =
6097 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6099 if (dwBufSize < ppev->cbValueName)
6100 dwBufSize = ppev->cbValueName;
6102 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6103 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6104 dwBufSize = ppev->cbData;
6107 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6109 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6110 if (pBuffer == NULL)
6112 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6113 return ERROR_OUTOFMEMORY;
6116 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6118 PPRINTER_ENUM_VALUESW ppev =
6119 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6121 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6122 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6123 NULL);
6124 if (len == 0)
6126 ret = GetLastError ();
6127 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6128 if (HeapFree (hHeap, 0, pBuffer) == 0)
6129 WARN ("HeapFree failed with code %i\n", GetLastError ());
6130 return ret;
6133 memcpy (ppev->pValueName, pBuffer, len);
6135 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6137 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6138 ppev->dwType != REG_MULTI_SZ)
6139 continue;
6141 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6142 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6143 if (len == 0)
6145 ret = GetLastError ();
6146 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6147 if (HeapFree (hHeap, 0, pBuffer) == 0)
6148 WARN ("HeapFree failed with code %i\n", GetLastError ());
6149 return ret;
6152 memcpy (ppev->pData, pBuffer, len);
6154 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6155 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6158 if (HeapFree (hHeap, 0, pBuffer) == 0)
6160 ret = GetLastError ();
6161 ERR ("HeapFree failed with code %i\n", ret);
6162 return ret;
6165 return ERROR_SUCCESS;
6168 /******************************************************************************
6169 * AbortPrinter (WINSPOOL.@)
6171 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6173 FIXME("(%p), stub!\n", hPrinter);
6174 return TRUE;
6177 /******************************************************************************
6178 * AddPortA (WINSPOOL.@)
6180 * See AddPortW.
6183 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6185 LPWSTR nameW = NULL;
6186 LPWSTR monitorW = NULL;
6187 DWORD len;
6188 BOOL res;
6190 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6192 if (pName) {
6193 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6194 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6195 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6198 if (pMonitorName) {
6199 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6200 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6201 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6203 res = AddPortW(nameW, hWnd, monitorW);
6204 HeapFree(GetProcessHeap(), 0, nameW);
6205 HeapFree(GetProcessHeap(), 0, monitorW);
6206 return res;
6209 /******************************************************************************
6210 * AddPortW (WINSPOOL.@)
6212 * Add a Port for a specific Monitor
6214 * PARAMS
6215 * pName [I] Servername or NULL (local Computer)
6216 * hWnd [I] Handle to parent Window for the Dialog-Box
6217 * pMonitorName [I] Name of the Monitor that manage the Port
6219 * RETURNS
6220 * Success: TRUE
6221 * Failure: FALSE
6224 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6226 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6228 if ((backend == NULL) && !load_backend()) return FALSE;
6230 if (!pMonitorName) {
6231 SetLastError(RPC_X_NULL_REF_POINTER);
6232 return FALSE;
6235 return backend->fpAddPort(pName, hWnd, pMonitorName);
6238 /******************************************************************************
6239 * AddPortExA (WINSPOOL.@)
6241 * See AddPortExW.
6244 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6246 PORT_INFO_2W pi2W;
6247 PORT_INFO_2A * pi2A;
6248 LPWSTR nameW = NULL;
6249 LPWSTR monitorW = NULL;
6250 DWORD len;
6251 BOOL res;
6253 pi2A = (PORT_INFO_2A *) pBuffer;
6255 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6256 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6258 if ((level < 1) || (level > 2)) {
6259 SetLastError(ERROR_INVALID_LEVEL);
6260 return FALSE;
6263 if (!pi2A) {
6264 SetLastError(ERROR_INVALID_PARAMETER);
6265 return FALSE;
6268 if (pName) {
6269 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6270 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6271 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6274 if (pMonitorName) {
6275 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6276 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6277 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6280 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6282 if (pi2A->pPortName) {
6283 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6284 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6285 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6288 if (level > 1) {
6289 if (pi2A->pMonitorName) {
6290 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6291 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6292 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6295 if (pi2A->pDescription) {
6296 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6297 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6298 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6300 pi2W.fPortType = pi2A->fPortType;
6301 pi2W.Reserved = pi2A->Reserved;
6304 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6306 HeapFree(GetProcessHeap(), 0, nameW);
6307 HeapFree(GetProcessHeap(), 0, monitorW);
6308 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6309 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6310 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6311 return res;
6315 /******************************************************************************
6316 * AddPortExW (WINSPOOL.@)
6318 * Add a Port for a specific Monitor, without presenting a user interface
6320 * PARAMS
6321 * pName [I] Servername or NULL (local Computer)
6322 * level [I] Structure-Level (1 or 2) for pBuffer
6323 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6324 * pMonitorName [I] Name of the Monitor that manage the Port
6326 * RETURNS
6327 * Success: TRUE
6328 * Failure: FALSE
6331 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6333 PORT_INFO_2W * pi2;
6335 pi2 = (PORT_INFO_2W *) pBuffer;
6337 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6338 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6339 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6340 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6342 if ((backend == NULL) && !load_backend()) return FALSE;
6344 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6345 SetLastError(ERROR_INVALID_PARAMETER);
6346 return FALSE;
6349 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6352 /******************************************************************************
6353 * AddPrinterConnectionA (WINSPOOL.@)
6355 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6357 FIXME("%s\n", debugstr_a(pName));
6358 return FALSE;
6361 /******************************************************************************
6362 * AddPrinterConnectionW (WINSPOOL.@)
6364 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6366 FIXME("%s\n", debugstr_w(pName));
6367 return FALSE;
6370 /******************************************************************************
6371 * AddPrinterDriverExW (WINSPOOL.@)
6373 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6375 * PARAMS
6376 * pName [I] Servername or NULL (local Computer)
6377 * level [I] Level for the supplied DRIVER_INFO_*W struct
6378 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6379 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6381 * RESULTS
6382 * Success: TRUE
6383 * Failure: FALSE
6386 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6388 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6390 if ((backend == NULL) && !load_backend()) return FALSE;
6392 if (level < 2 || level == 5 || level == 7 || level > 8) {
6393 SetLastError(ERROR_INVALID_LEVEL);
6394 return FALSE;
6397 if (!pDriverInfo) {
6398 SetLastError(ERROR_INVALID_PARAMETER);
6399 return FALSE;
6402 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6405 /******************************************************************************
6406 * AddPrinterDriverExA (WINSPOOL.@)
6408 * See AddPrinterDriverExW.
6411 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6413 DRIVER_INFO_8A *diA;
6414 DRIVER_INFO_8W diW;
6415 LPWSTR nameW = NULL;
6416 DWORD lenA;
6417 DWORD len;
6418 DWORD res = FALSE;
6420 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6422 diA = (DRIVER_INFO_8A *) pDriverInfo;
6423 ZeroMemory(&diW, sizeof(diW));
6425 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6426 SetLastError(ERROR_INVALID_LEVEL);
6427 return FALSE;
6430 if (diA == NULL) {
6431 SetLastError(ERROR_INVALID_PARAMETER);
6432 return FALSE;
6435 /* convert servername to unicode */
6436 if (pName) {
6437 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6438 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6439 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6442 /* common fields */
6443 diW.cVersion = diA->cVersion;
6445 if (diA->pName) {
6446 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6447 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6448 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6451 if (diA->pEnvironment) {
6452 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6453 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6454 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6457 if (diA->pDriverPath) {
6458 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6459 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6460 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6463 if (diA->pDataFile) {
6464 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6465 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6466 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6469 if (diA->pConfigFile) {
6470 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6471 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6472 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6475 if ((Level > 2) && diA->pDependentFiles) {
6476 lenA = multi_sz_lenA(diA->pDependentFiles);
6477 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6478 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6479 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6482 if ((Level > 2) && diA->pMonitorName) {
6483 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6484 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6485 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6488 if ((Level > 3) && diA->pDefaultDataType) {
6489 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6490 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6491 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6494 if ((Level > 3) && diA->pszzPreviousNames) {
6495 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6496 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6497 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6498 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6501 if ((Level > 5) && diA->pszMfgName) {
6502 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6503 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6504 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6507 if ((Level > 5) && diA->pszOEMUrl) {
6508 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6509 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6510 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6513 if ((Level > 5) && diA->pszHardwareID) {
6514 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6515 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6516 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6519 if ((Level > 5) && diA->pszProvider) {
6520 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6521 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6522 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6525 if (Level > 7) {
6526 FIXME("level %u is incomplete\n", Level);
6529 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6530 TRACE("got %u with %u\n", res, GetLastError());
6531 HeapFree(GetProcessHeap(), 0, nameW);
6532 HeapFree(GetProcessHeap(), 0, diW.pName);
6533 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6534 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6535 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6536 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6537 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6538 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6539 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6540 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6541 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6542 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6543 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6544 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6546 TRACE("=> %u with %u\n", res, GetLastError());
6547 return res;
6550 /******************************************************************************
6551 * ConfigurePortA (WINSPOOL.@)
6553 * See ConfigurePortW.
6556 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6558 LPWSTR nameW = NULL;
6559 LPWSTR portW = NULL;
6560 INT len;
6561 DWORD res;
6563 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6565 /* convert servername to unicode */
6566 if (pName) {
6567 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6568 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6569 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6572 /* convert portname to unicode */
6573 if (pPortName) {
6574 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6575 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6576 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6579 res = ConfigurePortW(nameW, hWnd, portW);
6580 HeapFree(GetProcessHeap(), 0, nameW);
6581 HeapFree(GetProcessHeap(), 0, portW);
6582 return res;
6585 /******************************************************************************
6586 * ConfigurePortW (WINSPOOL.@)
6588 * Display the Configuration-Dialog for a specific Port
6590 * PARAMS
6591 * pName [I] Servername or NULL (local Computer)
6592 * hWnd [I] Handle to parent Window for the Dialog-Box
6593 * pPortName [I] Name of the Port, that should be configured
6595 * RETURNS
6596 * Success: TRUE
6597 * Failure: FALSE
6600 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6603 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6605 if ((backend == NULL) && !load_backend()) return FALSE;
6607 if (!pPortName) {
6608 SetLastError(RPC_X_NULL_REF_POINTER);
6609 return FALSE;
6612 return backend->fpConfigurePort(pName, hWnd, pPortName);
6615 /******************************************************************************
6616 * ConnectToPrinterDlg (WINSPOOL.@)
6618 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6620 FIXME("%p %x\n", hWnd, Flags);
6621 return NULL;
6624 /******************************************************************************
6625 * DeletePrinterConnectionA (WINSPOOL.@)
6627 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6629 FIXME("%s\n", debugstr_a(pName));
6630 return TRUE;
6633 /******************************************************************************
6634 * DeletePrinterConnectionW (WINSPOOL.@)
6636 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6638 FIXME("%s\n", debugstr_w(pName));
6639 return TRUE;
6642 /******************************************************************************
6643 * DeletePrinterDriverExW (WINSPOOL.@)
6645 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6646 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6648 HKEY hkey_drivers;
6649 BOOL ret = FALSE;
6651 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6652 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6654 if(pName && pName[0])
6656 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6657 SetLastError(ERROR_INVALID_PARAMETER);
6658 return FALSE;
6661 if(dwDeleteFlag)
6663 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6664 SetLastError(ERROR_INVALID_PARAMETER);
6665 return FALSE;
6668 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6670 if(!hkey_drivers)
6672 ERR("Can't open drivers key\n");
6673 return FALSE;
6676 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6677 ret = TRUE;
6679 RegCloseKey(hkey_drivers);
6681 return ret;
6684 /******************************************************************************
6685 * DeletePrinterDriverExA (WINSPOOL.@)
6687 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6688 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6690 UNICODE_STRING NameW, EnvW, DriverW;
6691 BOOL ret;
6693 asciitounicode(&NameW, pName);
6694 asciitounicode(&EnvW, pEnvironment);
6695 asciitounicode(&DriverW, pDriverName);
6697 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6699 RtlFreeUnicodeString(&DriverW);
6700 RtlFreeUnicodeString(&EnvW);
6701 RtlFreeUnicodeString(&NameW);
6703 return ret;
6706 /******************************************************************************
6707 * DeletePrinterDataExW (WINSPOOL.@)
6709 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6710 LPCWSTR pValueName)
6712 FIXME("%p %s %s\n", hPrinter,
6713 debugstr_w(pKeyName), debugstr_w(pValueName));
6714 return ERROR_INVALID_PARAMETER;
6717 /******************************************************************************
6718 * DeletePrinterDataExA (WINSPOOL.@)
6720 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6721 LPCSTR pValueName)
6723 FIXME("%p %s %s\n", hPrinter,
6724 debugstr_a(pKeyName), debugstr_a(pValueName));
6725 return ERROR_INVALID_PARAMETER;
6728 /******************************************************************************
6729 * DeletePrintProcessorA (WINSPOOL.@)
6731 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6733 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6734 debugstr_a(pPrintProcessorName));
6735 return TRUE;
6738 /******************************************************************************
6739 * DeletePrintProcessorW (WINSPOOL.@)
6741 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6743 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6744 debugstr_w(pPrintProcessorName));
6745 return TRUE;
6748 /******************************************************************************
6749 * DeletePrintProvidorA (WINSPOOL.@)
6751 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6753 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6754 debugstr_a(pPrintProviderName));
6755 return TRUE;
6758 /******************************************************************************
6759 * DeletePrintProvidorW (WINSPOOL.@)
6761 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6763 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6764 debugstr_w(pPrintProviderName));
6765 return TRUE;
6768 /******************************************************************************
6769 * EnumFormsA (WINSPOOL.@)
6771 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6772 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6774 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6775 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6776 return FALSE;
6779 /******************************************************************************
6780 * EnumFormsW (WINSPOOL.@)
6782 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6783 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6785 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6786 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6787 return FALSE;
6790 /*****************************************************************************
6791 * EnumMonitorsA [WINSPOOL.@]
6793 * See EnumMonitorsW.
6796 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6797 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6799 BOOL res;
6800 LPBYTE bufferW = NULL;
6801 LPWSTR nameW = NULL;
6802 DWORD needed = 0;
6803 DWORD numentries = 0;
6804 INT len;
6806 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6807 cbBuf, pcbNeeded, pcReturned);
6809 /* convert servername to unicode */
6810 if (pName) {
6811 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6812 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6813 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6815 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6816 needed = cbBuf * sizeof(WCHAR);
6817 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6818 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6820 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6821 if (pcbNeeded) needed = *pcbNeeded;
6822 /* HeapReAlloc return NULL, when bufferW was NULL */
6823 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6824 HeapAlloc(GetProcessHeap(), 0, needed);
6826 /* Try again with the large Buffer */
6827 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6829 numentries = pcReturned ? *pcReturned : 0;
6830 needed = 0;
6832 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6833 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6835 if (res) {
6836 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6837 DWORD entrysize = 0;
6838 DWORD index;
6839 LPSTR ptr;
6840 LPMONITOR_INFO_2W mi2w;
6841 LPMONITOR_INFO_2A mi2a;
6843 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6844 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6846 /* First pass: calculate the size for all Entries */
6847 mi2w = (LPMONITOR_INFO_2W) bufferW;
6848 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6849 index = 0;
6850 while (index < numentries) {
6851 index++;
6852 needed += entrysize; /* MONITOR_INFO_?A */
6853 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6855 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6856 NULL, 0, NULL, NULL);
6857 if (Level > 1) {
6858 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6859 NULL, 0, NULL, NULL);
6860 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6861 NULL, 0, NULL, NULL);
6863 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6864 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6865 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6868 /* check for errors and quit on failure */
6869 if (cbBuf < needed) {
6870 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6871 res = FALSE;
6872 goto emA_cleanup;
6874 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6875 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6876 cbBuf -= len ; /* free Bytes in the user-Buffer */
6877 mi2w = (LPMONITOR_INFO_2W) bufferW;
6878 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6879 index = 0;
6880 /* Second Pass: Fill the User Buffer (if we have one) */
6881 while ((index < numentries) && pMonitors) {
6882 index++;
6883 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6884 mi2a->pName = ptr;
6885 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6886 ptr, cbBuf , NULL, NULL);
6887 ptr += len;
6888 cbBuf -= len;
6889 if (Level > 1) {
6890 mi2a->pEnvironment = ptr;
6891 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6892 ptr, cbBuf, NULL, NULL);
6893 ptr += len;
6894 cbBuf -= len;
6896 mi2a->pDLLName = ptr;
6897 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6898 ptr, cbBuf, NULL, NULL);
6899 ptr += len;
6900 cbBuf -= len;
6902 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6903 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6904 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6907 emA_cleanup:
6908 if (pcbNeeded) *pcbNeeded = needed;
6909 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6911 HeapFree(GetProcessHeap(), 0, nameW);
6912 HeapFree(GetProcessHeap(), 0, bufferW);
6914 TRACE("returning %d with %d (%d byte for %d entries)\n",
6915 (res), GetLastError(), needed, numentries);
6917 return (res);
6921 /*****************************************************************************
6922 * EnumMonitorsW [WINSPOOL.@]
6924 * Enumerate available Port-Monitors
6926 * PARAMS
6927 * pName [I] Servername or NULL (local Computer)
6928 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6929 * pMonitors [O] PTR to Buffer that receives the Result
6930 * cbBuf [I] Size of Buffer at pMonitors
6931 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6932 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6934 * RETURNS
6935 * Success: TRUE
6936 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6939 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6940 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6943 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6944 cbBuf, pcbNeeded, pcReturned);
6946 if ((backend == NULL) && !load_backend()) return FALSE;
6948 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6949 SetLastError(RPC_X_NULL_REF_POINTER);
6950 return FALSE;
6953 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6956 /******************************************************************************
6957 * SpoolerInit (WINSPOOL.@)
6959 * Initialize the Spooler
6961 * RETURNS
6962 * Success: TRUE
6963 * Failure: FALSE
6965 * NOTES
6966 * The function fails on windows, when the spooler service is not running
6969 BOOL WINAPI SpoolerInit(void)
6972 if ((backend == NULL) && !load_backend()) return FALSE;
6973 return TRUE;
6976 /******************************************************************************
6977 * XcvDataW (WINSPOOL.@)
6979 * Execute commands in the Printmonitor DLL
6981 * PARAMS
6982 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6983 * pszDataName [i] Name of the command to execute
6984 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6985 * cbInputData [i] Size in Bytes of Buffer at pInputData
6986 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6987 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6988 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6989 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6991 * RETURNS
6992 * Success: TRUE
6993 * Failure: FALSE
6995 * NOTES
6996 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6997 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6999 * Minimal List of commands, that a Printmonitor DLL should support:
7001 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7002 *| "AddPort" : Add a Port
7003 *| "DeletePort": Delete a Port
7005 * Many Printmonitors support additional commands. Examples for localspl.dll:
7006 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7007 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7010 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7011 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7012 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7014 opened_printer_t *printer;
7016 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7017 pInputData, cbInputData, pOutputData,
7018 cbOutputData, pcbOutputNeeded, pdwStatus);
7020 if ((backend == NULL) && !load_backend()) return FALSE;
7022 printer = get_opened_printer(hXcv);
7023 if (!printer || (!printer->backend_printer)) {
7024 SetLastError(ERROR_INVALID_HANDLE);
7025 return FALSE;
7028 if (!pcbOutputNeeded) {
7029 SetLastError(ERROR_INVALID_PARAMETER);
7030 return FALSE;
7033 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7034 SetLastError(RPC_X_NULL_REF_POINTER);
7035 return FALSE;
7038 *pcbOutputNeeded = 0;
7040 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7041 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7045 /*****************************************************************************
7046 * EnumPrinterDataA [WINSPOOL.@]
7049 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7050 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7051 DWORD cbData, LPDWORD pcbData )
7053 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7054 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7055 return ERROR_NO_MORE_ITEMS;
7058 /*****************************************************************************
7059 * EnumPrinterDataW [WINSPOOL.@]
7062 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7063 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7064 DWORD cbData, LPDWORD pcbData )
7066 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7067 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7068 return ERROR_NO_MORE_ITEMS;
7071 /*****************************************************************************
7072 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7075 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7076 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7077 LPDWORD pcbNeeded, LPDWORD pcReturned)
7079 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7080 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7081 pcbNeeded, pcReturned);
7082 return FALSE;
7085 /*****************************************************************************
7086 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7089 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7090 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7091 LPDWORD pcbNeeded, LPDWORD pcReturned)
7093 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7094 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7095 pcbNeeded, pcReturned);
7096 return FALSE;
7099 /*****************************************************************************
7100 * EnumPrintProcessorsA [WINSPOOL.@]
7102 * See EnumPrintProcessorsW.
7105 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7106 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7108 BOOL res;
7109 LPBYTE bufferW = NULL;
7110 LPWSTR nameW = NULL;
7111 LPWSTR envW = NULL;
7112 DWORD needed = 0;
7113 DWORD numentries = 0;
7114 INT len;
7116 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7117 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7119 /* convert names to unicode */
7120 if (pName) {
7121 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7122 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7123 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7125 if (pEnvironment) {
7126 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7127 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7128 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7131 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7132 needed = cbBuf * sizeof(WCHAR);
7133 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7134 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7136 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7137 if (pcbNeeded) needed = *pcbNeeded;
7138 /* HeapReAlloc return NULL, when bufferW was NULL */
7139 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7140 HeapAlloc(GetProcessHeap(), 0, needed);
7142 /* Try again with the large Buffer */
7143 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7145 numentries = pcReturned ? *pcReturned : 0;
7146 needed = 0;
7148 if (res) {
7149 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7150 DWORD index;
7151 LPSTR ptr;
7152 PPRINTPROCESSOR_INFO_1W ppiw;
7153 PPRINTPROCESSOR_INFO_1A ppia;
7155 /* First pass: calculate the size for all Entries */
7156 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7157 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7158 index = 0;
7159 while (index < numentries) {
7160 index++;
7161 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7162 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7164 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7165 NULL, 0, NULL, NULL);
7167 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7168 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7171 /* check for errors and quit on failure */
7172 if (cbBuf < needed) {
7173 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7174 res = FALSE;
7175 goto epp_cleanup;
7178 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7179 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7180 cbBuf -= len ; /* free Bytes in the user-Buffer */
7181 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7182 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7183 index = 0;
7184 /* Second Pass: Fill the User Buffer (if we have one) */
7185 while ((index < numentries) && pPPInfo) {
7186 index++;
7187 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7188 ppia->pName = ptr;
7189 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7190 ptr, cbBuf , NULL, NULL);
7191 ptr += len;
7192 cbBuf -= len;
7194 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7195 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7199 epp_cleanup:
7200 if (pcbNeeded) *pcbNeeded = needed;
7201 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7203 HeapFree(GetProcessHeap(), 0, nameW);
7204 HeapFree(GetProcessHeap(), 0, envW);
7205 HeapFree(GetProcessHeap(), 0, bufferW);
7207 TRACE("returning %d with %d (%d byte for %d entries)\n",
7208 (res), GetLastError(), needed, numentries);
7210 return (res);
7213 /*****************************************************************************
7214 * EnumPrintProcessorsW [WINSPOOL.@]
7216 * Enumerate available Print Processors
7218 * PARAMS
7219 * pName [I] Servername or NULL (local Computer)
7220 * pEnvironment [I] Printing-Environment or NULL (Default)
7221 * Level [I] Structure-Level (Only 1 is allowed)
7222 * pPPInfo [O] PTR to Buffer that receives the Result
7223 * cbBuf [I] Size of Buffer at pPPInfo
7224 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7225 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7227 * RETURNS
7228 * Success: TRUE
7229 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7232 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7233 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7236 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7237 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7239 if ((backend == NULL) && !load_backend()) return FALSE;
7241 if (!pcbNeeded || !pcReturned) {
7242 SetLastError(RPC_X_NULL_REF_POINTER);
7243 return FALSE;
7246 if (!pPPInfo && (cbBuf > 0)) {
7247 SetLastError(ERROR_INVALID_USER_BUFFER);
7248 return FALSE;
7251 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7252 cbBuf, pcbNeeded, pcReturned);
7255 /*****************************************************************************
7256 * ExtDeviceMode [WINSPOOL.@]
7259 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7260 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7261 DWORD fMode)
7263 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7264 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7265 debugstr_a(pProfile), fMode);
7266 return -1;
7269 /*****************************************************************************
7270 * FindClosePrinterChangeNotification [WINSPOOL.@]
7273 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7275 FIXME("Stub: %p\n", hChange);
7276 return TRUE;
7279 /*****************************************************************************
7280 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7283 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7284 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7286 FIXME("Stub: %p %x %x %p\n",
7287 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7288 return INVALID_HANDLE_VALUE;
7291 /*****************************************************************************
7292 * FindNextPrinterChangeNotification [WINSPOOL.@]
7295 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7296 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7298 FIXME("Stub: %p %p %p %p\n",
7299 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7300 return FALSE;
7303 /*****************************************************************************
7304 * FreePrinterNotifyInfo [WINSPOOL.@]
7307 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7309 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7310 return TRUE;
7313 /*****************************************************************************
7314 * string_to_buf
7316 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7317 * ansi depending on the unicode parameter.
7319 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7321 if(!str)
7323 *size = 0;
7324 return TRUE;
7327 if(unicode)
7329 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7330 if(*size <= cb)
7332 memcpy(ptr, str, *size);
7333 return TRUE;
7335 return FALSE;
7337 else
7339 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7340 if(*size <= cb)
7342 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7343 return TRUE;
7345 return FALSE;
7349 /*****************************************************************************
7350 * get_job_info_1
7352 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7353 LPDWORD pcbNeeded, BOOL unicode)
7355 DWORD size, left = cbBuf;
7356 BOOL space = (cbBuf > 0);
7357 LPBYTE ptr = buf;
7359 *pcbNeeded = 0;
7361 if(space)
7363 ji1->JobId = job->job_id;
7366 string_to_buf(job->document_title, ptr, left, &size, unicode);
7367 if(space && size <= left)
7369 ji1->pDocument = (LPWSTR)ptr;
7370 ptr += size;
7371 left -= size;
7373 else
7374 space = FALSE;
7375 *pcbNeeded += size;
7377 if (job->printer_name)
7379 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7380 if(space && size <= left)
7382 ji1->pPrinterName = (LPWSTR)ptr;
7383 ptr += size;
7384 left -= size;
7386 else
7387 space = FALSE;
7388 *pcbNeeded += size;
7391 return space;
7394 /*****************************************************************************
7395 * get_job_info_2
7397 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7398 LPDWORD pcbNeeded, BOOL unicode)
7400 DWORD size, left = cbBuf;
7401 DWORD shift;
7402 BOOL space = (cbBuf > 0);
7403 LPBYTE ptr = buf;
7404 LPDEVMODEA dmA = NULL;
7405 LPDEVMODEW devmode;
7407 *pcbNeeded = 0;
7409 if(space)
7411 ji2->JobId = job->job_id;
7414 string_to_buf(job->document_title, ptr, left, &size, unicode);
7415 if(space && size <= left)
7417 ji2->pDocument = (LPWSTR)ptr;
7418 ptr += size;
7419 left -= size;
7421 else
7422 space = FALSE;
7423 *pcbNeeded += size;
7425 if (job->printer_name)
7427 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7428 if(space && size <= left)
7430 ji2->pPrinterName = (LPWSTR)ptr;
7431 ptr += size;
7432 left -= size;
7434 else
7435 space = FALSE;
7436 *pcbNeeded += size;
7439 if (job->devmode)
7441 if (!unicode)
7443 dmA = DEVMODEdupWtoA(job->devmode);
7444 devmode = (LPDEVMODEW) dmA;
7445 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7447 else
7449 devmode = job->devmode;
7450 size = devmode->dmSize + devmode->dmDriverExtra;
7453 if (!devmode)
7454 FIXME("Can't convert DEVMODE W to A\n");
7455 else
7457 /* align DEVMODE to a DWORD boundary */
7458 shift = (4 - (*pcbNeeded & 3)) & 3;
7459 size += shift;
7461 if (size <= left)
7463 ptr += shift;
7464 memcpy(ptr, devmode, size-shift);
7465 ji2->pDevMode = (LPDEVMODEW)ptr;
7466 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7467 ptr += size-shift;
7468 left -= size;
7470 else
7471 space = FALSE;
7472 *pcbNeeded +=size;
7476 return space;
7479 /*****************************************************************************
7480 * get_job_info
7482 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7483 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7485 BOOL ret = FALSE;
7486 DWORD needed = 0, size;
7487 job_t *job;
7488 LPBYTE ptr = pJob;
7490 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7492 EnterCriticalSection(&printer_handles_cs);
7493 job = get_job(hPrinter, JobId);
7494 if(!job)
7495 goto end;
7497 switch(Level)
7499 case 1:
7500 size = sizeof(JOB_INFO_1W);
7501 if(cbBuf >= size)
7503 cbBuf -= size;
7504 ptr += size;
7505 memset(pJob, 0, size);
7507 else
7508 cbBuf = 0;
7509 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7510 needed += size;
7511 break;
7513 case 2:
7514 size = sizeof(JOB_INFO_2W);
7515 if(cbBuf >= size)
7517 cbBuf -= size;
7518 ptr += size;
7519 memset(pJob, 0, size);
7521 else
7522 cbBuf = 0;
7523 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7524 needed += size;
7525 break;
7527 case 3:
7528 size = sizeof(JOB_INFO_3);
7529 if(cbBuf >= size)
7531 cbBuf -= size;
7532 memset(pJob, 0, size);
7533 ret = TRUE;
7535 else
7536 cbBuf = 0;
7537 needed = size;
7538 break;
7540 default:
7541 SetLastError(ERROR_INVALID_LEVEL);
7542 goto end;
7544 if(pcbNeeded)
7545 *pcbNeeded = needed;
7546 end:
7547 LeaveCriticalSection(&printer_handles_cs);
7548 return ret;
7551 /*****************************************************************************
7552 * GetJobA [WINSPOOL.@]
7555 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7556 DWORD cbBuf, LPDWORD pcbNeeded)
7558 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7561 /*****************************************************************************
7562 * GetJobW [WINSPOOL.@]
7565 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7566 DWORD cbBuf, LPDWORD pcbNeeded)
7568 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7571 /*****************************************************************************
7572 * schedule_pipe
7574 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7576 #ifdef HAVE_FORK
7577 char *unixname, *cmdA;
7578 DWORD len;
7579 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7580 BOOL ret = FALSE;
7581 char buf[1024];
7582 pid_t pid, wret;
7583 int status;
7585 if(!(unixname = wine_get_unix_file_name(filename)))
7586 return FALSE;
7588 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7589 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7590 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7592 TRACE("printing with: %s\n", cmdA);
7594 if((file_fd = open(unixname, O_RDONLY)) == -1)
7595 goto end;
7597 if (pipe(fds))
7599 ERR("pipe() failed!\n");
7600 goto end;
7603 if ((pid = fork()) == 0)
7605 close(0);
7606 dup2(fds[0], 0);
7607 close(fds[1]);
7609 /* reset signals that we previously set to SIG_IGN */
7610 signal(SIGPIPE, SIG_DFL);
7612 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7613 _exit(1);
7615 else if (pid == -1)
7617 ERR("fork() failed!\n");
7618 goto end;
7621 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7622 write(fds[1], buf, no_read);
7624 close(fds[1]);
7625 fds[1] = -1;
7627 /* reap child */
7628 do {
7629 wret = waitpid(pid, &status, 0);
7630 } while (wret < 0 && errno == EINTR);
7631 if (wret < 0)
7633 ERR("waitpid() failed!\n");
7634 goto end;
7636 if (!WIFEXITED(status) || WEXITSTATUS(status))
7638 ERR("child process failed! %d\n", status);
7639 goto end;
7642 ret = TRUE;
7644 end:
7645 if(file_fd != -1) close(file_fd);
7646 if(fds[0] != -1) close(fds[0]);
7647 if(fds[1] != -1) close(fds[1]);
7649 HeapFree(GetProcessHeap(), 0, cmdA);
7650 HeapFree(GetProcessHeap(), 0, unixname);
7651 return ret;
7652 #else
7653 return FALSE;
7654 #endif
7657 /*****************************************************************************
7658 * schedule_lpr
7660 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7662 WCHAR *cmd;
7663 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7664 BOOL r;
7666 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7667 sprintfW(cmd, fmtW, printer_name);
7669 r = schedule_pipe(cmd, filename);
7671 HeapFree(GetProcessHeap(), 0, cmd);
7672 return r;
7675 #ifdef SONAME_LIBCUPS
7676 /*****************************************************************************
7677 * get_cups_jobs_ticket_options
7679 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7680 * The CUPS scheduler only looks for these in Print-File requests, and since
7681 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7682 * parsed.
7684 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7686 FILE *fp = fopen( file, "r" );
7687 char buf[257]; /* DSC max of 256 + '\0' */
7688 const char *ps_adobe = "%!PS-Adobe-";
7689 const char *cups_job = "%cupsJobTicket:";
7691 if (!fp) return num_options;
7692 if (!fgets( buf, sizeof(buf), fp )) goto end;
7693 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7694 while (fgets( buf, sizeof(buf), fp ))
7696 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7697 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7700 end:
7701 fclose( fp );
7702 return num_options;
7704 #endif
7706 /*****************************************************************************
7707 * schedule_cups
7709 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7711 #ifdef SONAME_LIBCUPS
7712 if(pcupsPrintFile)
7714 char *unixname, *queue, *unix_doc_title;
7715 DWORD len;
7716 BOOL ret;
7717 int num_options = 0, i;
7718 cups_option_t *options = NULL;
7720 if(!(unixname = wine_get_unix_file_name(filename)))
7721 return FALSE;
7723 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7724 queue = HeapAlloc(GetProcessHeap(), 0, len);
7725 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7727 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7728 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7729 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7731 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7733 TRACE( "printing via cups with options:\n" );
7734 for (i = 0; i < num_options; i++)
7735 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7737 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7739 pcupsFreeOptions( num_options, options );
7741 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7742 HeapFree(GetProcessHeap(), 0, queue);
7743 HeapFree(GetProcessHeap(), 0, unixname);
7744 return ret;
7746 else
7747 #endif
7749 return schedule_lpr(printer_name, filename);
7753 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7755 LPWSTR filename;
7757 switch(msg)
7759 case WM_INITDIALOG:
7760 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7761 return TRUE;
7763 case WM_COMMAND:
7764 if(HIWORD(wparam) == BN_CLICKED)
7766 if(LOWORD(wparam) == IDOK)
7768 HANDLE hf;
7769 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7770 LPWSTR *output;
7772 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7773 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7775 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7777 WCHAR caption[200], message[200];
7778 int mb_ret;
7780 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7781 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7782 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7783 if(mb_ret == IDCANCEL)
7785 HeapFree(GetProcessHeap(), 0, filename);
7786 return TRUE;
7789 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7790 if(hf == INVALID_HANDLE_VALUE)
7792 WCHAR caption[200], message[200];
7794 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7795 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7796 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7797 HeapFree(GetProcessHeap(), 0, filename);
7798 return TRUE;
7800 CloseHandle(hf);
7801 DeleteFileW(filename);
7802 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7803 *output = filename;
7804 EndDialog(hwnd, IDOK);
7805 return TRUE;
7807 if(LOWORD(wparam) == IDCANCEL)
7809 EndDialog(hwnd, IDCANCEL);
7810 return TRUE;
7813 return FALSE;
7815 return FALSE;
7818 /*****************************************************************************
7819 * get_filename
7821 static BOOL get_filename(LPWSTR *filename)
7823 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7824 file_dlg_proc, (LPARAM)filename) == IDOK;
7827 /*****************************************************************************
7828 * schedule_file
7830 static BOOL schedule_file(LPCWSTR filename)
7832 LPWSTR output = NULL;
7834 if(get_filename(&output))
7836 BOOL r;
7837 TRACE("copy to %s\n", debugstr_w(output));
7838 r = CopyFileW(filename, output, FALSE);
7839 HeapFree(GetProcessHeap(), 0, output);
7840 return r;
7842 return FALSE;
7845 /*****************************************************************************
7846 * schedule_unixfile
7848 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7850 int in_fd, out_fd, no_read;
7851 char buf[1024];
7852 BOOL ret = FALSE;
7853 char *unixname, *outputA;
7854 DWORD len;
7856 if(!(unixname = wine_get_unix_file_name(filename)))
7857 return FALSE;
7859 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7860 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7861 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7863 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7864 in_fd = open(unixname, O_RDONLY);
7865 if(out_fd == -1 || in_fd == -1)
7866 goto end;
7868 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7869 write(out_fd, buf, no_read);
7871 ret = TRUE;
7872 end:
7873 if(in_fd != -1) close(in_fd);
7874 if(out_fd != -1) close(out_fd);
7875 HeapFree(GetProcessHeap(), 0, outputA);
7876 HeapFree(GetProcessHeap(), 0, unixname);
7877 return ret;
7880 /*****************************************************************************
7881 * ScheduleJob [WINSPOOL.@]
7884 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7886 opened_printer_t *printer;
7887 BOOL ret = FALSE;
7888 struct list *cursor, *cursor2;
7890 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7891 EnterCriticalSection(&printer_handles_cs);
7892 printer = get_opened_printer(hPrinter);
7893 if(!printer)
7894 goto end;
7896 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7898 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7899 HANDLE hf;
7901 if(job->job_id != dwJobID) continue;
7903 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7904 if(hf != INVALID_HANDLE_VALUE)
7906 PRINTER_INFO_5W *pi5 = NULL;
7907 LPWSTR portname = job->portname;
7908 DWORD needed;
7909 HKEY hkey;
7910 WCHAR output[1024];
7911 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7912 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7914 if (!portname)
7916 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7917 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7918 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7919 portname = pi5->pPortName;
7921 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7922 debugstr_w(portname));
7924 output[0] = 0;
7926 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7927 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7929 DWORD type, count = sizeof(output);
7930 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7931 RegCloseKey(hkey);
7933 if(output[0] == '|')
7935 ret = schedule_pipe(output + 1, job->filename);
7937 else if(output[0])
7939 ret = schedule_unixfile(output, job->filename);
7941 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7943 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7945 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7947 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7949 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7951 ret = schedule_file(job->filename);
7953 else
7955 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7957 HeapFree(GetProcessHeap(), 0, pi5);
7958 CloseHandle(hf);
7959 DeleteFileW(job->filename);
7961 list_remove(cursor);
7962 HeapFree(GetProcessHeap(), 0, job->document_title);
7963 HeapFree(GetProcessHeap(), 0, job->printer_name);
7964 HeapFree(GetProcessHeap(), 0, job->portname);
7965 HeapFree(GetProcessHeap(), 0, job->filename);
7966 HeapFree(GetProcessHeap(), 0, job->devmode);
7967 HeapFree(GetProcessHeap(), 0, job);
7968 break;
7970 end:
7971 LeaveCriticalSection(&printer_handles_cs);
7972 return ret;
7975 /*****************************************************************************
7976 * StartDocDlgA [WINSPOOL.@]
7978 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7980 UNICODE_STRING usBuffer;
7981 DOCINFOW docW;
7982 LPWSTR retW;
7983 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7984 LPSTR ret = NULL;
7986 docW.cbSize = sizeof(docW);
7987 if (doc->lpszDocName)
7989 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7990 if (!(docW.lpszDocName = docnameW)) return NULL;
7992 if (doc->lpszOutput)
7994 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7995 if (!(docW.lpszOutput = outputW)) return NULL;
7997 if (doc->lpszDatatype)
7999 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8000 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8002 docW.fwType = doc->fwType;
8004 retW = StartDocDlgW(hPrinter, &docW);
8006 if(retW)
8008 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8009 ret = HeapAlloc(GetProcessHeap(), 0, len);
8010 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8011 HeapFree(GetProcessHeap(), 0, retW);
8014 HeapFree(GetProcessHeap(), 0, datatypeW);
8015 HeapFree(GetProcessHeap(), 0, outputW);
8016 HeapFree(GetProcessHeap(), 0, docnameW);
8018 return ret;
8021 /*****************************************************************************
8022 * StartDocDlgW [WINSPOOL.@]
8024 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8025 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8026 * port is "FILE:". Also returns the full path if passed a relative path.
8028 * The caller should free the returned string from the process heap.
8030 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8032 LPWSTR ret = NULL;
8033 DWORD len, attr;
8035 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8037 PRINTER_INFO_5W *pi5;
8038 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8039 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8040 return NULL;
8041 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8042 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8043 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8045 HeapFree(GetProcessHeap(), 0, pi5);
8046 return NULL;
8048 HeapFree(GetProcessHeap(), 0, pi5);
8051 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8053 LPWSTR name;
8055 if (get_filename(&name))
8057 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8059 HeapFree(GetProcessHeap(), 0, name);
8060 return NULL;
8062 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8063 GetFullPathNameW(name, len, ret, NULL);
8064 HeapFree(GetProcessHeap(), 0, name);
8066 return ret;
8069 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8070 return NULL;
8072 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8073 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8075 attr = GetFileAttributesW(ret);
8076 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8078 HeapFree(GetProcessHeap(), 0, ret);
8079 ret = NULL;
8081 return ret;