winspool: Don't leak the handle returned by AddPrinter.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob2f098553f8f3b0fa4604e2576dfe3375778a575a
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};
187 static const WCHAR backslashW[] = {'\\',0};
188 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW[] = {'R','A','W',0};
222 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW[] = {',',0};
226 static WCHAR emptyStringW[] = {0};
228 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
230 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
234 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
237 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
238 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
239 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
240 0, sizeof(DRIVER_INFO_8W)};
243 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
244 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
245 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
246 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
247 sizeof(PRINTER_INFO_9W)};
249 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
251 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
253 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
258 * PARAMS
259 * env [I] PTR to Environment-String or NULL
261 * RETURNS
262 * Failure: NULL
263 * Success: PTR to printenv_t
265 * NOTES
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
271 static const printenv_t * validate_envW(LPCWSTR env)
273 const printenv_t *result = NULL;
274 unsigned int i;
276 TRACE("testing %s\n", debugstr_w(env));
277 if (env && env[0])
279 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
281 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
283 result = all_printenv[i];
284 break;
288 if (result == NULL) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env));
290 SetLastError(ERROR_INVALID_ENVIRONMENT);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
294 else
296 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
298 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
300 return result;
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
309 if ( (src) )
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
312 return usBufferPtr->Buffer;
314 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
315 return NULL;
318 static LPWSTR strdupW(LPCWSTR p)
320 LPWSTR ret;
321 DWORD len;
323 if(!p) return NULL;
324 len = (strlenW(p) + 1) * sizeof(WCHAR);
325 ret = HeapAlloc(GetProcessHeap(), 0, len);
326 memcpy(ret, p, len);
327 return ret;
330 static LPSTR strdupWtoA( LPCWSTR str )
332 LPSTR ret;
333 INT len;
335 if (!str) return NULL;
336 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
337 ret = HeapAlloc( GetProcessHeap(), 0, len );
338 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
339 return ret;
342 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
344 DEVMODEW *ret;
346 if (!dm) return NULL;
347 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
348 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
349 return ret;
352 /***********************************************************
353 * DEVMODEdupWtoA
354 * Creates an ansi copy of supplied devmode
356 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
358 LPDEVMODEA dmA;
359 DWORD size;
361 if (!dmW) return NULL;
362 size = dmW->dmSize - CCHDEVICENAME -
363 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
365 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
366 if (!dmA) return NULL;
368 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
369 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
371 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
373 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
374 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
376 else
378 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
379 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
380 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
381 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
383 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
386 dmA->dmSize = size;
387 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
388 return dmA;
392 /******************************************************************
393 * verify, that the filename is a local file
396 static inline BOOL is_local_file(LPWSTR name)
398 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
401 /* ################################ */
403 static int multi_sz_lenA(const char *str)
405 const char *ptr = str;
406 if(!str) return 0;
409 ptr += lstrlenA(ptr) + 1;
410 } while(*ptr);
412 return ptr - str + 1;
415 static void
416 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
417 char qbuf[200];
419 /* If forcing, or no profile string entry for device yet, set the entry
421 * The always change entry if not WINEPS yet is discussable.
423 if (force ||
424 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
425 !strcmp(qbuf,"*") ||
426 !strstr(qbuf,"WINEPS.DRV")
428 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
429 HKEY hkey;
431 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
432 WriteProfileStringA("windows","device",buf);
433 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
434 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
435 RegCloseKey(hkey);
437 HeapFree(GetProcessHeap(),0,buf);
441 static BOOL add_printer_driver(WCHAR *name)
443 DRIVER_INFO_3W di3;
445 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
446 di3.cVersion = 3;
447 di3.pName = name;
448 di3.pEnvironment = envname_x86W;
449 di3.pDriverPath = driver_nt;
450 di3.pDataFile = generic_ppdW;
451 di3.pConfigFile = driver_nt;
452 di3.pDefaultDataType = rawW;
454 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
455 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
457 di3.cVersion = 0;
458 di3.pEnvironment = envname_win40W;
459 di3.pDriverPath = driver_9x;
460 di3.pConfigFile = driver_9x;
461 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
462 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
464 return TRUE;
467 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
468 return FALSE;
471 #ifdef SONAME_LIBCUPS
473 static void *cupshandle;
475 #define CUPS_FUNCS \
476 DO_FUNC(cupsFreeDests); \
477 DO_FUNC(cupsFreeOptions); \
478 DO_FUNC(cupsGetDests); \
479 DO_FUNC(cupsGetPPD); \
480 DO_FUNC(cupsParseOptions); \
481 DO_FUNC(cupsPrintFile);
483 #define DO_FUNC(f) static typeof(f) *p##f
484 CUPS_FUNCS;
485 #undef DO_FUNC
487 static BOOL CUPS_LoadPrinters(void)
489 int i, nrofdests;
490 BOOL hadprinter = FALSE, haddefault = FALSE;
491 cups_dest_t *dests;
492 PRINTER_INFO_2W pi2;
493 WCHAR *port;
494 HKEY hkeyPrinter, hkeyPrinters;
495 char loaderror[256];
496 WCHAR nameW[MAX_PATH];
497 HANDLE added_printer;
499 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
500 if (!cupshandle) {
501 TRACE("%s\n", loaderror);
502 return FALSE;
504 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
506 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
507 CUPS_FUNCS;
508 #undef DO_FUNC
510 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
511 ERROR_SUCCESS) {
512 ERR("Can't create Printers key\n");
513 return FALSE;
516 nrofdests = pcupsGetDests(&dests);
517 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
518 for (i=0;i<nrofdests;i++) {
519 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
521 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
522 lstrcpyW(port, CUPS_Port);
523 lstrcatW(port, nameW);
525 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
526 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
527 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
528 and continue */
529 TRACE("Printer already exists\n");
530 /* overwrite old LPR:* port */
531 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
532 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
533 RegCloseKey(hkeyPrinter);
534 } else {
535 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
536 ' ','u','s','i','n','g',' ','C','U','P','S',0};
538 add_printer_driver(nameW);
540 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
541 pi2.pPrinterName = nameW;
542 pi2.pDatatype = rawW;
543 pi2.pPrintProcessor = WinPrintW;
544 pi2.pDriverName = nameW;
545 pi2.pComment = comment_cups;
546 pi2.pLocation = emptyStringW;
547 pi2.pPortName = port;
548 pi2.pParameters = emptyStringW;
549 pi2.pShareName = emptyStringW;
550 pi2.pSepFile = emptyStringW;
552 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
553 if (added_printer) ClosePrinter( added_printer );
554 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
555 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
557 HeapFree(GetProcessHeap(),0,port);
559 hadprinter = TRUE;
560 if (dests[i].is_default) {
561 SetDefaultPrinterW(nameW);
562 haddefault = TRUE;
565 if (hadprinter && !haddefault) {
566 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
567 SetDefaultPrinterW(nameW);
569 pcupsFreeDests(nrofdests, dests);
570 RegCloseKey(hkeyPrinters);
571 return TRUE;
573 #endif
575 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
577 PRINTER_INFO_2A pinfo2a;
578 const char *r;
579 size_t name_len;
580 char *e,*s,*name,*prettyname,*devname;
581 BOOL ret = FALSE, set_default = FALSE;
582 char *port = NULL, *env_default;
583 HKEY hkeyPrinter, hkeyPrinters;
584 WCHAR devnameW[MAX_PATH];
585 HANDLE added_printer;
587 while (isspace(*pent)) pent++;
588 r = strchr(pent,':');
589 if (r)
590 name_len = r - pent;
591 else
592 name_len = strlen(pent);
593 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
594 memcpy(name, pent, name_len);
595 name[name_len] = '\0';
596 if (r)
597 pent = r;
598 else
599 pent = "";
601 TRACE("name=%s entry=%s\n",name, pent);
603 if(ispunct(*name)) { /* a tc entry, not a real printer */
604 TRACE("skipping tc entry\n");
605 goto end;
608 if(strstr(pent,":server")) { /* server only version so skip */
609 TRACE("skipping server entry\n");
610 goto end;
613 /* Determine whether this is a postscript printer. */
615 ret = TRUE;
616 env_default = getenv("PRINTER");
617 prettyname = name;
618 /* Get longest name, usually the one at the right for later display. */
619 while((s=strchr(prettyname,'|'))) {
620 *s = '\0';
621 e = s;
622 while(isspace(*--e)) *e = '\0';
623 TRACE("\t%s\n", debugstr_a(prettyname));
624 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
625 for(prettyname = s+1; isspace(*prettyname); prettyname++)
628 e = prettyname + strlen(prettyname);
629 while(isspace(*--e)) *e = '\0';
630 TRACE("\t%s\n", debugstr_a(prettyname));
631 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
633 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
634 * if it is too long, we use it as comment below. */
635 devname = prettyname;
636 if (strlen(devname)>=CCHDEVICENAME-1)
637 devname = name;
638 if (strlen(devname)>=CCHDEVICENAME-1) {
639 ret = FALSE;
640 goto end;
643 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
644 sprintf(port,"LPR:%s",name);
646 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
647 ERROR_SUCCESS) {
648 ERR("Can't create Printers key\n");
649 ret = FALSE;
650 goto end;
653 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
655 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
656 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
657 and continue */
658 TRACE("Printer already exists\n");
659 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
660 RegCloseKey(hkeyPrinter);
661 } else {
662 static CHAR data_type[] = "RAW",
663 print_proc[] = "WinPrint",
664 comment[] = "WINEPS Printer using LPR",
665 params[] = "<parameters?>",
666 share_name[] = "<share name?>",
667 sep_file[] = "<sep file?>";
669 add_printer_driver(devnameW);
671 memset(&pinfo2a,0,sizeof(pinfo2a));
672 pinfo2a.pPrinterName = devname;
673 pinfo2a.pDatatype = data_type;
674 pinfo2a.pPrintProcessor = print_proc;
675 pinfo2a.pDriverName = devname;
676 pinfo2a.pComment = comment;
677 pinfo2a.pLocation = prettyname;
678 pinfo2a.pPortName = port;
679 pinfo2a.pParameters = params;
680 pinfo2a.pShareName = share_name;
681 pinfo2a.pSepFile = sep_file;
683 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
684 if (added_printer) ClosePrinter( added_printer );
685 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
686 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
688 RegCloseKey(hkeyPrinters);
690 if (isfirst || set_default)
691 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
693 end:
694 HeapFree(GetProcessHeap(), 0, port);
695 HeapFree(GetProcessHeap(), 0, name);
696 return ret;
699 static BOOL
700 PRINTCAP_LoadPrinters(void) {
701 BOOL hadprinter = FALSE;
702 char buf[200];
703 FILE *f;
704 char *pent = NULL;
705 BOOL had_bash = FALSE;
707 f = fopen("/etc/printcap","r");
708 if (!f)
709 return FALSE;
711 while(fgets(buf,sizeof(buf),f)) {
712 char *start, *end;
714 end=strchr(buf,'\n');
715 if (end) *end='\0';
717 start = buf;
718 while(isspace(*start)) start++;
719 if(*start == '#' || *start == '\0')
720 continue;
722 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
723 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
724 HeapFree(GetProcessHeap(),0,pent);
725 pent = NULL;
728 if (end && *--end == '\\') {
729 *end = '\0';
730 had_bash = TRUE;
731 } else
732 had_bash = FALSE;
734 if (pent) {
735 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
736 strcat(pent,start);
737 } else {
738 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
739 strcpy(pent,start);
743 if(pent) {
744 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
745 HeapFree(GetProcessHeap(),0,pent);
747 fclose(f);
748 return hadprinter;
751 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
753 if (value)
754 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
755 (lstrlenW(value) + 1) * sizeof(WCHAR));
756 else
757 return ERROR_FILE_NOT_FOUND;
760 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
762 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
763 DWORD ret = ERROR_FILE_NOT_FOUND;
765 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
766 and we support these drivers. NT writes DEVMODEW so somehow
767 we'll need to distinguish between these when we support NT
768 drivers */
770 if (dmA)
772 ret = RegSetValueExW( key, name, 0, REG_BINARY,
773 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
774 HeapFree( GetProcessHeap(), 0, dmA );
777 return ret;
780 /******************************************************************
781 * get_servername_from_name (internal)
783 * for an external server, a copy of the serverpart from the full name is returned
786 static LPWSTR get_servername_from_name(LPCWSTR name)
788 LPWSTR server;
789 LPWSTR ptr;
790 WCHAR buffer[MAX_PATH];
791 DWORD len;
793 if (name == NULL) return NULL;
794 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
796 server = strdupW(&name[2]); /* skip over both backslash */
797 if (server == NULL) return NULL;
799 /* strip '\' and the printername */
800 ptr = strchrW(server, '\\');
801 if (ptr) ptr[0] = '\0';
803 TRACE("found %s\n", debugstr_w(server));
805 len = sizeof(buffer)/sizeof(buffer[0]);
806 if (GetComputerNameW(buffer, &len)) {
807 if (lstrcmpW(buffer, server) == 0) {
808 /* The requested Servername is our computername */
809 HeapFree(GetProcessHeap(), 0, server);
810 return NULL;
813 return server;
816 /******************************************************************
817 * get_basename_from_name (internal)
819 * skip over the serverpart from the full name
822 static LPCWSTR get_basename_from_name(LPCWSTR name)
824 if (name == NULL) return NULL;
825 if ((name[0] == '\\') && (name[1] == '\\')) {
826 /* skip over the servername and search for the following '\' */
827 name = strchrW(&name[2], '\\');
828 if ((name) && (name[1])) {
829 /* found a separator ('\') followed by a name:
830 skip over the separator and return the rest */
831 name++;
833 else
835 /* no basename present (we found only a servername) */
836 return NULL;
839 return name;
842 static void free_printer_entry( opened_printer_t *printer )
844 /* the queue is shared, so don't free that here */
845 HeapFree( GetProcessHeap(), 0, printer->printername );
846 HeapFree( GetProcessHeap(), 0, printer->name );
847 HeapFree( GetProcessHeap(), 0, printer->devmode );
848 HeapFree( GetProcessHeap(), 0, printer );
851 /******************************************************************
852 * get_opened_printer_entry
853 * Get the first place empty in the opened printer table
855 * ToDo:
856 * - pDefault is ignored
858 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
860 UINT_PTR handle = nb_printer_handles, i;
861 jobqueue_t *queue = NULL;
862 opened_printer_t *printer = NULL;
863 LPWSTR servername;
864 LPCWSTR printername;
866 if ((backend == NULL) && !load_backend()) return NULL;
868 servername = get_servername_from_name(name);
869 if (servername) {
870 FIXME("server %s not supported\n", debugstr_w(servername));
871 HeapFree(GetProcessHeap(), 0, servername);
872 SetLastError(ERROR_INVALID_PRINTER_NAME);
873 return NULL;
876 printername = get_basename_from_name(name);
877 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
879 /* an empty printername is invalid */
880 if (printername && (!printername[0])) {
881 SetLastError(ERROR_INVALID_PARAMETER);
882 return NULL;
885 EnterCriticalSection(&printer_handles_cs);
887 for (i = 0; i < nb_printer_handles; i++)
889 if (!printer_handles[i])
891 if(handle == nb_printer_handles)
892 handle = i;
894 else
896 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
897 queue = printer_handles[i]->queue;
901 if (handle >= nb_printer_handles)
903 opened_printer_t **new_array;
904 if (printer_handles)
905 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
906 (nb_printer_handles + 16) * sizeof(*new_array) );
907 else
908 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
909 (nb_printer_handles + 16) * sizeof(*new_array) );
911 if (!new_array)
913 handle = 0;
914 goto end;
916 printer_handles = new_array;
917 nb_printer_handles += 16;
920 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
922 handle = 0;
923 goto end;
926 /* get a printer handle from the backend */
927 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
928 handle = 0;
929 goto end;
932 /* clone the base name. This is NULL for the printserver */
933 printer->printername = strdupW(printername);
935 /* clone the full name */
936 printer->name = strdupW(name);
937 if (name && (!printer->name)) {
938 handle = 0;
939 goto end;
942 if (pDefault && pDefault->pDevMode)
943 printer->devmode = dup_devmode( pDefault->pDevMode );
945 if(queue)
946 printer->queue = queue;
947 else
949 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
950 if (!printer->queue) {
951 handle = 0;
952 goto end;
954 list_init(&printer->queue->jobs);
955 printer->queue->ref = 0;
957 InterlockedIncrement(&printer->queue->ref);
959 printer_handles[handle] = printer;
960 handle++;
961 end:
962 LeaveCriticalSection(&printer_handles_cs);
963 if (!handle && printer) {
964 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
965 free_printer_entry( printer );
968 return (HANDLE)handle;
971 /******************************************************************
972 * get_opened_printer
973 * Get the pointer to the opened printer referred by the handle
975 static opened_printer_t *get_opened_printer(HANDLE hprn)
977 UINT_PTR idx = (UINT_PTR)hprn;
978 opened_printer_t *ret = NULL;
980 EnterCriticalSection(&printer_handles_cs);
982 if ((idx > 0) && (idx <= nb_printer_handles)) {
983 ret = printer_handles[idx - 1];
985 LeaveCriticalSection(&printer_handles_cs);
986 return ret;
989 /******************************************************************
990 * get_opened_printer_name
991 * Get the pointer to the opened printer name referred by the handle
993 static LPCWSTR get_opened_printer_name(HANDLE hprn)
995 opened_printer_t *printer = get_opened_printer(hprn);
996 if(!printer) return NULL;
997 return printer->name;
1000 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1002 HKEY printers;
1003 DWORD err;
1005 *key = NULL;
1006 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1007 if (err) return err;
1009 err = RegOpenKeyW( printers, name, key );
1010 if (err) err = ERROR_INVALID_PRINTER_NAME;
1011 RegCloseKey( printers );
1012 return err;
1015 /******************************************************************
1016 * WINSPOOL_GetOpenedPrinterRegKey
1019 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1021 LPCWSTR name = get_opened_printer_name(hPrinter);
1023 if(!name) return ERROR_INVALID_HANDLE;
1024 return open_printer_reg_key( name, phkey );
1027 static void old_printer_check( BOOL delete_phase )
1029 PRINTER_INFO_5W* pi;
1030 DWORD needed, type, num, delete, i, size;
1031 const DWORD one = 1;
1032 HKEY key;
1033 HANDLE hprn;
1035 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1036 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1038 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1039 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1040 for (i = 0; i < num; i++)
1042 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1043 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1044 continue;
1046 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1048 if (!delete_phase)
1050 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1051 RegCloseKey( key );
1053 else
1055 delete = 0;
1056 size = sizeof( delete );
1057 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1058 RegCloseKey( key );
1059 if (delete)
1061 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1062 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1064 DeletePrinter( hprn );
1065 ClosePrinter( hprn );
1067 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1071 HeapFree(GetProcessHeap(), 0, pi);
1074 void WINSPOOL_LoadSystemPrinters(void)
1076 HKEY hkey, hkeyPrinters;
1077 DWORD needed, num, i;
1078 WCHAR PrinterName[256];
1079 BOOL done = FALSE;
1081 /* This ensures that all printer entries have a valid Name value. If causes
1082 problems later if they don't. If one is found to be missed we create one
1083 and set it equal to the name of the key */
1084 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1085 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1086 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1087 for(i = 0; i < num; i++) {
1088 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1089 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1090 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1091 set_reg_szW(hkey, NameW, PrinterName);
1093 RegCloseKey(hkey);
1098 RegCloseKey(hkeyPrinters);
1101 old_printer_check( FALSE );
1103 #ifdef SONAME_LIBCUPS
1104 done = CUPS_LoadPrinters();
1105 #endif
1107 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1108 PRINTCAP_LoadPrinters();
1110 old_printer_check( TRUE );
1112 return;
1115 /******************************************************************
1116 * get_job
1118 * Get the pointer to the specified job.
1119 * Should hold the printer_handles_cs before calling.
1121 static job_t *get_job(HANDLE hprn, DWORD JobId)
1123 opened_printer_t *printer = get_opened_printer(hprn);
1124 job_t *job;
1126 if(!printer) return NULL;
1127 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1129 if(job->job_id == JobId)
1130 return job;
1132 return NULL;
1135 /***********************************************************
1136 * DEVMODEcpyAtoW
1138 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1140 BOOL Formname;
1141 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1142 DWORD size;
1144 Formname = (dmA->dmSize > off_formname);
1145 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1146 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1147 dmW->dmDeviceName, CCHDEVICENAME);
1148 if(!Formname) {
1149 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1150 dmA->dmSize - CCHDEVICENAME);
1151 } else {
1152 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1153 off_formname - CCHDEVICENAME);
1154 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1155 dmW->dmFormName, CCHFORMNAME);
1156 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1157 (off_formname + CCHFORMNAME));
1159 dmW->dmSize = size;
1160 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1161 dmA->dmDriverExtra);
1162 return dmW;
1165 /******************************************************************
1166 * convert_printerinfo_W_to_A [internal]
1169 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1170 DWORD level, DWORD outlen, DWORD numentries)
1172 DWORD id = 0;
1173 LPSTR ptr;
1174 INT len;
1176 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1178 len = pi_sizeof[level] * numentries;
1179 ptr = (LPSTR) out + len;
1180 outlen -= len;
1182 /* copy the numbers of all PRINTER_INFO_* first */
1183 memcpy(out, pPrintersW, len);
1185 while (id < numentries) {
1186 switch (level) {
1187 case 1:
1189 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1190 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1192 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1193 if (piW->pDescription) {
1194 piA->pDescription = ptr;
1195 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1196 ptr, outlen, NULL, NULL);
1197 ptr += len;
1198 outlen -= len;
1200 if (piW->pName) {
1201 piA->pName = ptr;
1202 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1203 ptr, outlen, NULL, NULL);
1204 ptr += len;
1205 outlen -= len;
1207 if (piW->pComment) {
1208 piA->pComment = ptr;
1209 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1210 ptr, outlen, NULL, NULL);
1211 ptr += len;
1212 outlen -= len;
1214 break;
1217 case 2:
1219 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1220 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1221 LPDEVMODEA dmA;
1223 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1224 if (piW->pServerName) {
1225 piA->pServerName = ptr;
1226 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1227 ptr, outlen, NULL, NULL);
1228 ptr += len;
1229 outlen -= len;
1231 if (piW->pPrinterName) {
1232 piA->pPrinterName = ptr;
1233 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1234 ptr, outlen, NULL, NULL);
1235 ptr += len;
1236 outlen -= len;
1238 if (piW->pShareName) {
1239 piA->pShareName = ptr;
1240 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1241 ptr, outlen, NULL, NULL);
1242 ptr += len;
1243 outlen -= len;
1245 if (piW->pPortName) {
1246 piA->pPortName = ptr;
1247 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1248 ptr, outlen, NULL, NULL);
1249 ptr += len;
1250 outlen -= len;
1252 if (piW->pDriverName) {
1253 piA->pDriverName = ptr;
1254 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1255 ptr, outlen, NULL, NULL);
1256 ptr += len;
1257 outlen -= len;
1259 if (piW->pComment) {
1260 piA->pComment = ptr;
1261 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1262 ptr, outlen, NULL, NULL);
1263 ptr += len;
1264 outlen -= len;
1266 if (piW->pLocation) {
1267 piA->pLocation = ptr;
1268 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1269 ptr, outlen, NULL, NULL);
1270 ptr += len;
1271 outlen -= len;
1274 dmA = DEVMODEdupWtoA(piW->pDevMode);
1275 if (dmA) {
1276 /* align DEVMODEA to a DWORD boundary */
1277 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1278 ptr += len;
1279 outlen -= len;
1281 piA->pDevMode = (LPDEVMODEA) ptr;
1282 len = dmA->dmSize + dmA->dmDriverExtra;
1283 memcpy(ptr, dmA, len);
1284 HeapFree(GetProcessHeap(), 0, dmA);
1286 ptr += len;
1287 outlen -= len;
1290 if (piW->pSepFile) {
1291 piA->pSepFile = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1293 ptr, outlen, NULL, NULL);
1294 ptr += len;
1295 outlen -= len;
1297 if (piW->pPrintProcessor) {
1298 piA->pPrintProcessor = ptr;
1299 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1300 ptr, outlen, NULL, NULL);
1301 ptr += len;
1302 outlen -= len;
1304 if (piW->pDatatype) {
1305 piA->pDatatype = ptr;
1306 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1307 ptr, outlen, NULL, NULL);
1308 ptr += len;
1309 outlen -= len;
1311 if (piW->pParameters) {
1312 piA->pParameters = ptr;
1313 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1314 ptr, outlen, NULL, NULL);
1315 ptr += len;
1316 outlen -= len;
1318 if (piW->pSecurityDescriptor) {
1319 piA->pSecurityDescriptor = NULL;
1320 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1322 break;
1325 case 4:
1327 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1328 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1330 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1332 if (piW->pPrinterName) {
1333 piA->pPrinterName = ptr;
1334 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1335 ptr, outlen, NULL, NULL);
1336 ptr += len;
1337 outlen -= len;
1339 if (piW->pServerName) {
1340 piA->pServerName = ptr;
1341 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1342 ptr, outlen, NULL, NULL);
1343 ptr += len;
1344 outlen -= len;
1346 break;
1349 case 5:
1351 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1352 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1354 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1356 if (piW->pPrinterName) {
1357 piA->pPrinterName = ptr;
1358 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1359 ptr, outlen, NULL, NULL);
1360 ptr += len;
1361 outlen -= len;
1363 if (piW->pPortName) {
1364 piA->pPortName = ptr;
1365 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1366 ptr, outlen, NULL, NULL);
1367 ptr += len;
1368 outlen -= len;
1370 break;
1373 case 6: /* 6A and 6W are the same structure */
1374 break;
1376 case 7:
1378 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1379 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1381 TRACE("(%u) #%u\n", level, id);
1382 if (piW->pszObjectGUID) {
1383 piA->pszObjectGUID = ptr;
1384 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1385 ptr, outlen, NULL, NULL);
1386 ptr += len;
1387 outlen -= len;
1389 break;
1392 case 9:
1394 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1395 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1396 LPDEVMODEA dmA;
1398 TRACE("(%u) #%u\n", level, id);
1399 dmA = DEVMODEdupWtoA(piW->pDevMode);
1400 if (dmA) {
1401 /* align DEVMODEA to a DWORD boundary */
1402 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1403 ptr += len;
1404 outlen -= len;
1406 piA->pDevMode = (LPDEVMODEA) ptr;
1407 len = dmA->dmSize + dmA->dmDriverExtra;
1408 memcpy(ptr, dmA, len);
1409 HeapFree(GetProcessHeap(), 0, dmA);
1411 ptr += len;
1412 outlen -= len;
1415 break;
1418 default:
1419 FIXME("for level %u\n", level);
1421 pPrintersW += pi_sizeof[level];
1422 out += pi_sizeof[level];
1423 id++;
1427 /******************************************************************
1428 * convert_driverinfo_W_to_A [internal]
1431 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1432 DWORD level, DWORD outlen, DWORD numentries)
1434 DWORD id = 0;
1435 LPSTR ptr;
1436 INT len;
1438 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1440 len = di_sizeof[level] * numentries;
1441 ptr = (LPSTR) out + len;
1442 outlen -= len;
1444 /* copy the numbers of all PRINTER_INFO_* first */
1445 memcpy(out, pDriversW, len);
1447 #define COPY_STRING(fld) \
1448 { if (diW->fld){ \
1449 diA->fld = ptr; \
1450 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1451 ptr += len; outlen -= len;\
1453 #define COPY_MULTIZ_STRING(fld) \
1454 { LPWSTR p = diW->fld; if (p){ \
1455 diA->fld = ptr; \
1456 do {\
1457 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1458 ptr += len; outlen -= len; p += len;\
1460 while(len > 1 && outlen > 0); \
1463 while (id < numentries)
1465 switch (level)
1467 case 1:
1469 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1470 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1472 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1474 COPY_STRING(pName);
1475 break;
1477 case 2:
1479 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1480 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1482 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1484 COPY_STRING(pName);
1485 COPY_STRING(pEnvironment);
1486 COPY_STRING(pDriverPath);
1487 COPY_STRING(pDataFile);
1488 COPY_STRING(pConfigFile);
1489 break;
1491 case 3:
1493 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1494 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1496 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1498 COPY_STRING(pName);
1499 COPY_STRING(pEnvironment);
1500 COPY_STRING(pDriverPath);
1501 COPY_STRING(pDataFile);
1502 COPY_STRING(pConfigFile);
1503 COPY_STRING(pHelpFile);
1504 COPY_MULTIZ_STRING(pDependentFiles);
1505 COPY_STRING(pMonitorName);
1506 COPY_STRING(pDefaultDataType);
1507 break;
1509 case 4:
1511 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1512 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1514 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1516 COPY_STRING(pName);
1517 COPY_STRING(pEnvironment);
1518 COPY_STRING(pDriverPath);
1519 COPY_STRING(pDataFile);
1520 COPY_STRING(pConfigFile);
1521 COPY_STRING(pHelpFile);
1522 COPY_MULTIZ_STRING(pDependentFiles);
1523 COPY_STRING(pMonitorName);
1524 COPY_STRING(pDefaultDataType);
1525 COPY_MULTIZ_STRING(pszzPreviousNames);
1526 break;
1528 case 5:
1530 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1531 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1533 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1535 COPY_STRING(pName);
1536 COPY_STRING(pEnvironment);
1537 COPY_STRING(pDriverPath);
1538 COPY_STRING(pDataFile);
1539 COPY_STRING(pConfigFile);
1540 break;
1542 case 6:
1544 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1545 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1547 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1549 COPY_STRING(pName);
1550 COPY_STRING(pEnvironment);
1551 COPY_STRING(pDriverPath);
1552 COPY_STRING(pDataFile);
1553 COPY_STRING(pConfigFile);
1554 COPY_STRING(pHelpFile);
1555 COPY_MULTIZ_STRING(pDependentFiles);
1556 COPY_STRING(pMonitorName);
1557 COPY_STRING(pDefaultDataType);
1558 COPY_MULTIZ_STRING(pszzPreviousNames);
1559 COPY_STRING(pszMfgName);
1560 COPY_STRING(pszOEMUrl);
1561 COPY_STRING(pszHardwareID);
1562 COPY_STRING(pszProvider);
1563 break;
1565 case 8:
1567 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1568 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1570 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1572 COPY_STRING(pName);
1573 COPY_STRING(pEnvironment);
1574 COPY_STRING(pDriverPath);
1575 COPY_STRING(pDataFile);
1576 COPY_STRING(pConfigFile);
1577 COPY_STRING(pHelpFile);
1578 COPY_MULTIZ_STRING(pDependentFiles);
1579 COPY_STRING(pMonitorName);
1580 COPY_STRING(pDefaultDataType);
1581 COPY_MULTIZ_STRING(pszzPreviousNames);
1582 COPY_STRING(pszMfgName);
1583 COPY_STRING(pszOEMUrl);
1584 COPY_STRING(pszHardwareID);
1585 COPY_STRING(pszProvider);
1586 COPY_STRING(pszPrintProcessor);
1587 COPY_STRING(pszVendorSetup);
1588 COPY_MULTIZ_STRING(pszzColorProfiles);
1589 COPY_STRING(pszInfPath);
1590 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1591 break;
1595 default:
1596 FIXME("for level %u\n", level);
1599 pDriversW += di_sizeof[level];
1600 out += di_sizeof[level];
1601 id++;
1604 #undef COPY_STRING
1605 #undef COPY_MULTIZ_STRING
1609 /***********************************************************
1610 * printer_info_AtoW
1612 static void *printer_info_AtoW( const void *data, DWORD level )
1614 void *ret;
1615 UNICODE_STRING usBuffer;
1617 if (!data) return NULL;
1619 if (level < 1 || level > 9) return NULL;
1621 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1622 if (!ret) return NULL;
1624 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1626 switch (level)
1628 case 2:
1630 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1631 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1633 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1634 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1635 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1636 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1637 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1638 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1639 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1640 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1641 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1642 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1643 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1644 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1645 break;
1648 case 8:
1649 case 9:
1651 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1652 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1654 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1655 break;
1658 default:
1659 FIXME( "Unhandled level %d\n", level );
1660 HeapFree( GetProcessHeap(), 0, ret );
1661 return NULL;
1664 return ret;
1667 /***********************************************************
1668 * free_printer_info
1670 static void free_printer_info( void *data, DWORD level )
1672 if (!data) return;
1674 switch (level)
1676 case 2:
1678 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1680 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1681 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1682 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1683 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1684 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1685 HeapFree( GetProcessHeap(), 0, piW->pComment );
1686 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1687 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1688 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1689 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1690 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1691 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1692 break;
1695 case 8:
1696 case 9:
1698 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1700 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1701 break;
1704 default:
1705 FIXME( "Unhandled level %d\n", level );
1708 HeapFree( GetProcessHeap(), 0, data );
1709 return;
1712 /******************************************************************
1713 * DeviceCapabilities [WINSPOOL.@]
1714 * DeviceCapabilitiesA [WINSPOOL.@]
1717 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1718 LPSTR pOutput, LPDEVMODEA lpdm)
1720 INT ret;
1722 if (!GDI_CallDeviceCapabilities16)
1724 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1725 (LPCSTR)104 );
1726 if (!GDI_CallDeviceCapabilities16) return -1;
1728 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1730 /* If DC_PAPERSIZE map POINT16s to POINTs */
1731 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1732 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1733 POINT *pt = (POINT *)pOutput;
1734 INT i;
1735 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1736 for(i = 0; i < ret; i++, pt++)
1738 pt->x = tmp[i].x;
1739 pt->y = tmp[i].y;
1741 HeapFree( GetProcessHeap(), 0, tmp );
1743 return ret;
1747 /*****************************************************************************
1748 * DeviceCapabilitiesW [WINSPOOL.@]
1750 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1753 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1754 WORD fwCapability, LPWSTR pOutput,
1755 const DEVMODEW *pDevMode)
1757 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1758 LPSTR pDeviceA = strdupWtoA(pDevice);
1759 LPSTR pPortA = strdupWtoA(pPort);
1760 INT ret;
1762 if(pOutput && (fwCapability == DC_BINNAMES ||
1763 fwCapability == DC_FILEDEPENDENCIES ||
1764 fwCapability == DC_PAPERNAMES)) {
1765 /* These need A -> W translation */
1766 INT size = 0, i;
1767 LPSTR pOutputA;
1768 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1769 dmA);
1770 if(ret == -1)
1771 return ret;
1772 switch(fwCapability) {
1773 case DC_BINNAMES:
1774 size = 24;
1775 break;
1776 case DC_PAPERNAMES:
1777 case DC_FILEDEPENDENCIES:
1778 size = 64;
1779 break;
1781 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1782 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1783 dmA);
1784 for(i = 0; i < ret; i++)
1785 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1786 pOutput + (i * size), size);
1787 HeapFree(GetProcessHeap(), 0, pOutputA);
1788 } else {
1789 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1790 (LPSTR)pOutput, dmA);
1792 HeapFree(GetProcessHeap(),0,pPortA);
1793 HeapFree(GetProcessHeap(),0,pDeviceA);
1794 HeapFree(GetProcessHeap(),0,dmA);
1795 return ret;
1798 /******************************************************************
1799 * DocumentPropertiesA [WINSPOOL.@]
1801 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1803 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1804 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1805 LPDEVMODEA pDevModeInput,DWORD fMode )
1807 LPSTR lpName = pDeviceName;
1808 static CHAR port[] = "LPT1:";
1809 LONG ret;
1811 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1812 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1815 if(!pDeviceName) {
1816 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1817 if(!lpNameW) {
1818 ERR("no name from hPrinter?\n");
1819 SetLastError(ERROR_INVALID_HANDLE);
1820 return -1;
1822 lpName = strdupWtoA(lpNameW);
1825 if (!GDI_CallExtDeviceMode16)
1827 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1828 (LPCSTR)102 );
1829 if (!GDI_CallExtDeviceMode16) {
1830 ERR("No CallExtDeviceMode16?\n");
1831 return -1;
1834 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1835 pDevModeInput, NULL, fMode);
1837 if(!pDeviceName)
1838 HeapFree(GetProcessHeap(),0,lpName);
1839 return ret;
1843 /*****************************************************************************
1844 * DocumentPropertiesW (WINSPOOL.@)
1846 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1848 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1849 LPWSTR pDeviceName,
1850 LPDEVMODEW pDevModeOutput,
1851 LPDEVMODEW pDevModeInput, DWORD fMode)
1854 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1855 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1856 LPDEVMODEA pDevModeOutputA = NULL;
1857 LONG ret;
1859 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1860 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1861 fMode);
1862 if(pDevModeOutput) {
1863 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1864 if(ret < 0) return ret;
1865 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1867 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1868 pDevModeInputA, fMode);
1869 if(pDevModeOutput) {
1870 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1871 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1873 if(fMode == 0 && ret > 0)
1874 ret += (CCHDEVICENAME + CCHFORMNAME);
1875 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1876 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1877 return ret;
1880 /*****************************************************************************
1881 * IsValidDevmodeA [WINSPOOL.@]
1883 * Validate a DEVMODE structure and fix errors if possible.
1886 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1888 FIXME("(%p,%ld): stub\n", pDevMode, size);
1890 if(!pDevMode)
1891 return FALSE;
1893 return TRUE;
1896 /*****************************************************************************
1897 * IsValidDevmodeW [WINSPOOL.@]
1899 * Validate a DEVMODE structure and fix errors if possible.
1902 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1904 FIXME("(%p,%ld): stub\n", pDevMode, size);
1906 if(!pDevMode)
1907 return FALSE;
1909 return TRUE;
1912 /******************************************************************
1913 * OpenPrinterA [WINSPOOL.@]
1915 * See OpenPrinterW.
1918 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1919 LPPRINTER_DEFAULTSA pDefault)
1921 UNICODE_STRING lpPrinterNameW;
1922 UNICODE_STRING usBuffer;
1923 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1924 PWSTR pwstrPrinterNameW;
1925 BOOL ret;
1927 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1929 if(pDefault) {
1930 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1931 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1932 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1933 pDefaultW = &DefaultW;
1935 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1936 if(pDefault) {
1937 RtlFreeUnicodeString(&usBuffer);
1938 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1940 RtlFreeUnicodeString(&lpPrinterNameW);
1941 return ret;
1944 /******************************************************************
1945 * OpenPrinterW [WINSPOOL.@]
1947 * Open a Printer / Printserver or a Printer-Object
1949 * PARAMS
1950 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1951 * phPrinter [O] The resulting Handle is stored here
1952 * pDefault [I] PTR to Default Printer Settings or NULL
1954 * RETURNS
1955 * Success: TRUE
1956 * Failure: FALSE
1958 * NOTES
1959 * lpPrinterName is one of:
1960 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1961 *| Printer: "PrinterName"
1962 *| Printer-Object: "PrinterName,Job xxx"
1963 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1964 *| XcvPort: "Servername,XcvPort PortName"
1966 * BUGS
1967 *| Printer-Object not supported
1968 *| pDefaults is ignored
1971 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1974 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1976 if(!phPrinter) {
1977 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1978 SetLastError(ERROR_INVALID_PARAMETER);
1979 return FALSE;
1982 /* Get the unique handle of the printer or Printserver */
1983 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1984 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1985 return (*phPrinter != 0);
1988 /******************************************************************
1989 * AddMonitorA [WINSPOOL.@]
1991 * See AddMonitorW.
1994 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1996 LPWSTR nameW = NULL;
1997 INT len;
1998 BOOL res;
1999 LPMONITOR_INFO_2A mi2a;
2000 MONITOR_INFO_2W mi2w;
2002 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2003 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2004 debugstr_a(mi2a ? mi2a->pName : NULL),
2005 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2006 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2008 if (Level != 2) {
2009 SetLastError(ERROR_INVALID_LEVEL);
2010 return FALSE;
2013 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2014 if (mi2a == NULL) {
2015 return FALSE;
2018 if (pName) {
2019 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2020 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2021 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2024 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2025 if (mi2a->pName) {
2026 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2027 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2028 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2030 if (mi2a->pEnvironment) {
2031 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2032 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2033 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2035 if (mi2a->pDLLName) {
2036 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2037 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2038 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2041 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2043 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2044 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2045 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2047 HeapFree(GetProcessHeap(), 0, nameW);
2048 return (res);
2051 /******************************************************************************
2052 * AddMonitorW [WINSPOOL.@]
2054 * Install a Printmonitor
2056 * PARAMS
2057 * pName [I] Servername or NULL (local Computer)
2058 * Level [I] Structure-Level (Must be 2)
2059 * pMonitors [I] PTR to MONITOR_INFO_2
2061 * RETURNS
2062 * Success: TRUE
2063 * Failure: FALSE
2065 * NOTES
2066 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2069 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2071 LPMONITOR_INFO_2W mi2w;
2073 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2074 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2075 debugstr_w(mi2w ? mi2w->pName : NULL),
2076 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2077 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2079 if ((backend == NULL) && !load_backend()) return FALSE;
2081 if (Level != 2) {
2082 SetLastError(ERROR_INVALID_LEVEL);
2083 return FALSE;
2086 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2087 if (mi2w == NULL) {
2088 return FALSE;
2091 return backend->fpAddMonitor(pName, Level, pMonitors);
2094 /******************************************************************
2095 * DeletePrinterDriverA [WINSPOOL.@]
2098 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2100 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2103 /******************************************************************
2104 * DeletePrinterDriverW [WINSPOOL.@]
2107 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2109 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2112 /******************************************************************
2113 * DeleteMonitorA [WINSPOOL.@]
2115 * See DeleteMonitorW.
2118 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2120 LPWSTR nameW = NULL;
2121 LPWSTR EnvironmentW = NULL;
2122 LPWSTR MonitorNameW = NULL;
2123 BOOL res;
2124 INT len;
2126 if (pName) {
2127 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2128 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2129 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2132 if (pEnvironment) {
2133 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2134 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2135 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2137 if (pMonitorName) {
2138 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2139 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2140 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2143 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2145 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2146 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2147 HeapFree(GetProcessHeap(), 0, nameW);
2148 return (res);
2151 /******************************************************************
2152 * DeleteMonitorW [WINSPOOL.@]
2154 * Delete a specific Printmonitor from a Printing-Environment
2156 * PARAMS
2157 * pName [I] Servername or NULL (local Computer)
2158 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2159 * pMonitorName [I] Name of the Monitor, that should be deleted
2161 * RETURNS
2162 * Success: TRUE
2163 * Failure: FALSE
2165 * NOTES
2166 * pEnvironment is ignored in Windows for the local Computer.
2169 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2172 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2173 debugstr_w(pMonitorName));
2175 if ((backend == NULL) && !load_backend()) return FALSE;
2177 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2181 /******************************************************************
2182 * DeletePortA [WINSPOOL.@]
2184 * See DeletePortW.
2187 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2189 LPWSTR nameW = NULL;
2190 LPWSTR portW = NULL;
2191 INT len;
2192 DWORD res;
2194 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2196 /* convert servername to unicode */
2197 if (pName) {
2198 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2199 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2200 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2203 /* convert portname to unicode */
2204 if (pPortName) {
2205 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2206 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2207 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2210 res = DeletePortW(nameW, hWnd, portW);
2211 HeapFree(GetProcessHeap(), 0, nameW);
2212 HeapFree(GetProcessHeap(), 0, portW);
2213 return res;
2216 /******************************************************************
2217 * DeletePortW [WINSPOOL.@]
2219 * Delete a specific Port
2221 * PARAMS
2222 * pName [I] Servername or NULL (local Computer)
2223 * hWnd [I] Handle to parent Window for the Dialog-Box
2224 * pPortName [I] Name of the Port, that should be deleted
2226 * RETURNS
2227 * Success: TRUE
2228 * Failure: FALSE
2231 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2233 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2235 if ((backend == NULL) && !load_backend()) return FALSE;
2237 if (!pPortName) {
2238 SetLastError(RPC_X_NULL_REF_POINTER);
2239 return FALSE;
2242 return backend->fpDeletePort(pName, hWnd, pPortName);
2245 /******************************************************************************
2246 * WritePrinter [WINSPOOL.@]
2248 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2250 opened_printer_t *printer;
2251 BOOL ret = FALSE;
2253 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2255 EnterCriticalSection(&printer_handles_cs);
2256 printer = get_opened_printer(hPrinter);
2257 if(!printer)
2259 SetLastError(ERROR_INVALID_HANDLE);
2260 goto end;
2263 if(!printer->doc)
2265 SetLastError(ERROR_SPL_NO_STARTDOC);
2266 goto end;
2269 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2270 end:
2271 LeaveCriticalSection(&printer_handles_cs);
2272 return ret;
2275 /*****************************************************************************
2276 * AddFormA [WINSPOOL.@]
2278 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2280 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2281 return 1;
2284 /*****************************************************************************
2285 * AddFormW [WINSPOOL.@]
2287 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2289 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2290 return 1;
2293 /*****************************************************************************
2294 * AddJobA [WINSPOOL.@]
2296 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2298 BOOL ret;
2299 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2300 DWORD needed;
2302 if(Level != 1) {
2303 SetLastError(ERROR_INVALID_LEVEL);
2304 return FALSE;
2307 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2309 if(ret) {
2310 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2311 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2312 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2313 if(*pcbNeeded > cbBuf) {
2314 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2315 ret = FALSE;
2316 } else {
2317 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2318 addjobA->JobId = addjobW->JobId;
2319 addjobA->Path = (char *)(addjobA + 1);
2320 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2323 return ret;
2326 /*****************************************************************************
2327 * AddJobW [WINSPOOL.@]
2329 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2331 opened_printer_t *printer;
2332 job_t *job;
2333 BOOL ret = FALSE;
2334 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2335 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2336 WCHAR path[MAX_PATH], filename[MAX_PATH];
2337 DWORD len;
2338 ADDJOB_INFO_1W *addjob;
2340 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2342 EnterCriticalSection(&printer_handles_cs);
2344 printer = get_opened_printer(hPrinter);
2346 if(!printer) {
2347 SetLastError(ERROR_INVALID_HANDLE);
2348 goto end;
2351 if(Level != 1) {
2352 SetLastError(ERROR_INVALID_LEVEL);
2353 goto end;
2356 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2357 if(!job)
2358 goto end;
2360 job->job_id = InterlockedIncrement(&next_job_id);
2362 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2363 if(path[len - 1] != '\\')
2364 path[len++] = '\\';
2365 memcpy(path + len, spool_path, sizeof(spool_path));
2366 sprintfW(filename, fmtW, path, job->job_id);
2368 len = strlenW(filename);
2369 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2370 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2371 job->portname = NULL;
2372 job->document_title = strdupW(default_doc_title);
2373 job->printer_name = strdupW(printer->name);
2374 job->devmode = dup_devmode( printer->devmode );
2375 list_add_tail(&printer->queue->jobs, &job->entry);
2377 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2378 if(*pcbNeeded <= cbBuf) {
2379 addjob = (ADDJOB_INFO_1W*)pData;
2380 addjob->JobId = job->job_id;
2381 addjob->Path = (WCHAR *)(addjob + 1);
2382 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2383 ret = TRUE;
2384 } else
2385 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2387 end:
2388 LeaveCriticalSection(&printer_handles_cs);
2389 return ret;
2392 /*****************************************************************************
2393 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2395 * Return the PATH for the Print-Processors
2397 * See GetPrintProcessorDirectoryW.
2401 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2402 DWORD level, LPBYTE Info,
2403 DWORD cbBuf, LPDWORD pcbNeeded)
2405 LPWSTR serverW = NULL;
2406 LPWSTR envW = NULL;
2407 BOOL ret;
2408 INT len;
2410 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2411 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2414 if (server) {
2415 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2416 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2417 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2420 if (env) {
2421 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2422 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2423 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2426 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2427 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2429 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2430 cbBuf, pcbNeeded);
2432 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2433 cbBuf, NULL, NULL) > 0;
2436 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2437 HeapFree(GetProcessHeap(), 0, envW);
2438 HeapFree(GetProcessHeap(), 0, serverW);
2439 return ret;
2442 /*****************************************************************************
2443 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2445 * Return the PATH for the Print-Processors
2447 * PARAMS
2448 * server [I] Servername (NT only) or NULL (local Computer)
2449 * env [I] Printing-Environment (see below) or NULL (Default)
2450 * level [I] Structure-Level (must be 1)
2451 * Info [O] PTR to Buffer that receives the Result
2452 * cbBuf [I] Size of Buffer at "Info"
2453 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2454 * required for the Buffer at "Info"
2456 * RETURNS
2457 * Success: TRUE and in pcbNeeded the Bytes used in Info
2458 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2459 * if cbBuf is too small
2461 * Native Values returned in Info on Success:
2462 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2463 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2464 *| win9x(Windows 4.0): "%winsysdir%"
2466 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2468 * BUGS
2469 * Only NULL or "" is supported for server
2472 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2473 DWORD level, LPBYTE Info,
2474 DWORD cbBuf, LPDWORD pcbNeeded)
2477 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2478 Info, cbBuf, pcbNeeded);
2480 if ((backend == NULL) && !load_backend()) return FALSE;
2482 if (level != 1) {
2483 /* (Level != 1) is ignored in win9x */
2484 SetLastError(ERROR_INVALID_LEVEL);
2485 return FALSE;
2488 if (pcbNeeded == NULL) {
2489 /* (pcbNeeded == NULL) is ignored in win9x */
2490 SetLastError(RPC_X_NULL_REF_POINTER);
2491 return FALSE;
2494 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2497 /*****************************************************************************
2498 * WINSPOOL_OpenDriverReg [internal]
2500 * opens the registry for the printer drivers depending on the given input
2501 * variable pEnvironment
2503 * RETURNS:
2504 * the opened hkey on success
2505 * NULL on error
2507 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2509 HKEY retval = NULL;
2510 LPWSTR buffer;
2511 const printenv_t * env;
2513 TRACE("(%s)\n", debugstr_w(pEnvironment));
2515 env = validate_envW(pEnvironment);
2516 if (!env) return NULL;
2518 buffer = HeapAlloc( GetProcessHeap(), 0,
2519 (strlenW(DriversW) + strlenW(env->envname) +
2520 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2521 if(buffer) {
2522 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2523 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2524 HeapFree(GetProcessHeap(), 0, buffer);
2526 return retval;
2529 /*****************************************************************************
2530 * set_devices_and_printerports [internal]
2532 * set the [Devices] and [PrinterPorts] entries for a printer.
2535 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2537 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2538 WCHAR *devline;
2539 HKEY hkey;
2541 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2543 /* FIXME: the driver must change to "winspool" */
2544 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2545 if (devline) {
2546 lstrcpyW(devline, driver_nt);
2547 lstrcatW(devline, commaW);
2548 lstrcatW(devline, pi->pPortName);
2550 TRACE("using %s\n", debugstr_w(devline));
2551 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2552 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2553 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2554 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2555 RegCloseKey(hkey);
2558 lstrcatW(devline, timeout_15_45);
2559 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2560 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2561 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2562 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2563 RegCloseKey(hkey);
2565 HeapFree(GetProcessHeap(), 0, devline);
2569 /*****************************************************************************
2570 * AddPrinterW [WINSPOOL.@]
2572 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2574 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2575 LPDEVMODEW dm;
2576 HANDLE retval;
2577 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2578 LONG size;
2579 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2580 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2581 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2582 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2583 statusW[] = {'S','t','a','t','u','s',0},
2584 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2586 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2588 if(pName != NULL) {
2589 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2590 SetLastError(ERROR_INVALID_PARAMETER);
2591 return 0;
2593 if(Level != 2) {
2594 ERR("Level = %d, unsupported!\n", Level);
2595 SetLastError(ERROR_INVALID_LEVEL);
2596 return 0;
2598 if(!pPrinter) {
2599 SetLastError(ERROR_INVALID_PARAMETER);
2600 return 0;
2602 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2603 ERROR_SUCCESS) {
2604 ERR("Can't create Printers key\n");
2605 return 0;
2607 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2608 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2609 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2610 RegCloseKey(hkeyPrinter);
2611 RegCloseKey(hkeyPrinters);
2612 return 0;
2614 RegCloseKey(hkeyPrinter);
2616 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2617 if(!hkeyDrivers) {
2618 ERR("Can't create Drivers key\n");
2619 RegCloseKey(hkeyPrinters);
2620 return 0;
2622 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2623 ERROR_SUCCESS) {
2624 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2625 RegCloseKey(hkeyPrinters);
2626 RegCloseKey(hkeyDrivers);
2627 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2628 return 0;
2630 RegCloseKey(hkeyDriver);
2631 RegCloseKey(hkeyDrivers);
2633 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2634 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2635 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2636 RegCloseKey(hkeyPrinters);
2637 return 0;
2640 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2641 ERROR_SUCCESS) {
2642 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2643 SetLastError(ERROR_INVALID_PRINTER_NAME);
2644 RegCloseKey(hkeyPrinters);
2645 return 0;
2648 set_devices_and_printerports(pi);
2649 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2650 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2651 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2653 /* See if we can load the driver. We may need the devmode structure anyway
2655 * FIXME:
2656 * Note that DocumentPropertiesW will briefly try to open the printer we
2657 * just create to find a DEVMODE struct (it will use the WINEPS default
2658 * one in case it is not there, so we are ok).
2660 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2662 if(size < 0) {
2663 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2664 size = sizeof(DEVMODEW);
2666 if(pi->pDevMode)
2667 dm = pi->pDevMode;
2668 else
2670 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2671 dm->dmSize = size;
2672 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2674 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2675 HeapFree( GetProcessHeap(), 0, dm );
2676 dm = NULL;
2678 else
2680 /* set devmode to printer name */
2681 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2685 set_reg_devmode( hkeyPrinter, default_devmodeW, dm );
2686 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2688 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2689 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2690 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2691 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2693 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2694 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2695 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2696 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2697 (LPBYTE)&pi->Priority, sizeof(DWORD));
2698 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2699 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2700 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2701 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2702 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2703 (LPBYTE)&pi->Status, sizeof(DWORD));
2704 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2705 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2707 RegCloseKey(hkeyPrinter);
2708 RegCloseKey(hkeyPrinters);
2709 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2710 ERR("OpenPrinter failing\n");
2711 return 0;
2713 return retval;
2716 /*****************************************************************************
2717 * AddPrinterA [WINSPOOL.@]
2719 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2721 UNICODE_STRING pNameW;
2722 PWSTR pwstrNameW;
2723 PRINTER_INFO_2W *piW;
2724 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2725 HANDLE ret;
2727 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2728 if(Level != 2) {
2729 ERR("Level = %d, unsupported!\n", Level);
2730 SetLastError(ERROR_INVALID_LEVEL);
2731 return 0;
2733 pwstrNameW = asciitounicode(&pNameW,pName);
2734 piW = printer_info_AtoW( piA, Level );
2736 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2738 free_printer_info( piW, Level );
2739 RtlFreeUnicodeString(&pNameW);
2740 return ret;
2744 /*****************************************************************************
2745 * ClosePrinter [WINSPOOL.@]
2747 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2749 UINT_PTR i = (UINT_PTR)hPrinter;
2750 opened_printer_t *printer = NULL;
2751 BOOL ret = FALSE;
2753 TRACE("(%p)\n", hPrinter);
2755 EnterCriticalSection(&printer_handles_cs);
2757 if ((i > 0) && (i <= nb_printer_handles))
2758 printer = printer_handles[i - 1];
2761 if(printer)
2763 struct list *cursor, *cursor2;
2765 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2767 if (printer->backend_printer) {
2768 backend->fpClosePrinter(printer->backend_printer);
2771 if(printer->doc)
2772 EndDocPrinter(hPrinter);
2774 if(InterlockedDecrement(&printer->queue->ref) == 0)
2776 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2778 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2779 ScheduleJob(hPrinter, job->job_id);
2781 HeapFree(GetProcessHeap(), 0, printer->queue);
2784 free_printer_entry( printer );
2785 printer_handles[i - 1] = NULL;
2786 ret = TRUE;
2788 LeaveCriticalSection(&printer_handles_cs);
2789 return ret;
2792 /*****************************************************************************
2793 * DeleteFormA [WINSPOOL.@]
2795 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2797 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2798 return 1;
2801 /*****************************************************************************
2802 * DeleteFormW [WINSPOOL.@]
2804 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2806 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2807 return 1;
2810 /*****************************************************************************
2811 * DeletePrinter [WINSPOOL.@]
2813 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2815 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2816 HKEY hkeyPrinters, hkey;
2817 WCHAR def[MAX_PATH];
2818 DWORD size = sizeof( def ) / sizeof( def[0] );
2820 if(!lpNameW) {
2821 SetLastError(ERROR_INVALID_HANDLE);
2822 return FALSE;
2824 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2825 RegDeleteTreeW(hkeyPrinters, lpNameW);
2826 RegCloseKey(hkeyPrinters);
2828 WriteProfileStringW(devicesW, lpNameW, NULL);
2829 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2831 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2832 RegDeleteValueW(hkey, lpNameW);
2833 RegCloseKey(hkey);
2836 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2837 RegDeleteValueW(hkey, lpNameW);
2838 RegCloseKey(hkey);
2841 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
2843 WriteProfileStringW( windowsW, deviceW, NULL );
2844 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
2846 RegDeleteValueW( hkey, deviceW );
2847 RegCloseKey( hkey );
2849 SetDefaultPrinterW( NULL );
2852 return TRUE;
2855 /*****************************************************************************
2856 * SetPrinterA [WINSPOOL.@]
2858 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2860 BYTE *dataW = data;
2861 BOOL ret;
2863 if (level != 0)
2865 dataW = printer_info_AtoW( data, level );
2866 if (!dataW) return FALSE;
2869 ret = SetPrinterW( printer, level, dataW, command );
2871 if (dataW != data) free_printer_info( dataW, level );
2873 return ret;
2876 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2878 if (!pi->pDevMode) return FALSE;
2880 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2881 return TRUE;
2884 /******************************************************************************
2885 * SetPrinterW [WINSPOOL.@]
2887 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2889 HKEY key;
2890 BOOL ret = FALSE;
2892 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2894 if (command != 0) FIXME( "Ignoring command %d\n", command );
2896 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2897 return FALSE;
2899 switch (level)
2901 case 9:
2903 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2904 ret = set_printer_9( key, pi );
2905 break;
2908 default:
2909 FIXME( "Unimplemented level %d\n", level );
2910 SetLastError( ERROR_INVALID_LEVEL );
2913 RegCloseKey( key );
2914 return ret;
2917 /*****************************************************************************
2918 * SetJobA [WINSPOOL.@]
2920 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2921 LPBYTE pJob, DWORD Command)
2923 BOOL ret;
2924 LPBYTE JobW;
2925 UNICODE_STRING usBuffer;
2927 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2929 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2930 are all ignored by SetJob, so we don't bother copying them */
2931 switch(Level)
2933 case 0:
2934 JobW = NULL;
2935 break;
2936 case 1:
2938 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2939 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2941 JobW = (LPBYTE)info1W;
2942 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2943 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2944 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2945 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2946 info1W->Status = info1A->Status;
2947 info1W->Priority = info1A->Priority;
2948 info1W->Position = info1A->Position;
2949 info1W->PagesPrinted = info1A->PagesPrinted;
2950 break;
2952 case 2:
2954 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2955 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2957 JobW = (LPBYTE)info2W;
2958 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2959 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2960 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2961 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2962 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2963 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2964 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2965 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2966 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2967 info2W->Status = info2A->Status;
2968 info2W->Priority = info2A->Priority;
2969 info2W->Position = info2A->Position;
2970 info2W->StartTime = info2A->StartTime;
2971 info2W->UntilTime = info2A->UntilTime;
2972 info2W->PagesPrinted = info2A->PagesPrinted;
2973 break;
2975 case 3:
2976 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2977 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2978 break;
2979 default:
2980 SetLastError(ERROR_INVALID_LEVEL);
2981 return FALSE;
2984 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2986 switch(Level)
2988 case 1:
2990 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2991 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2992 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2993 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2994 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2995 break;
2997 case 2:
2999 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3000 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3001 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3002 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3003 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3004 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3005 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3006 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3007 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3008 break;
3011 HeapFree(GetProcessHeap(), 0, JobW);
3013 return ret;
3016 /*****************************************************************************
3017 * SetJobW [WINSPOOL.@]
3019 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3020 LPBYTE pJob, DWORD Command)
3022 BOOL ret = FALSE;
3023 job_t *job;
3025 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3026 FIXME("Ignoring everything other than document title\n");
3028 EnterCriticalSection(&printer_handles_cs);
3029 job = get_job(hPrinter, JobId);
3030 if(!job)
3031 goto end;
3033 switch(Level)
3035 case 0:
3036 break;
3037 case 1:
3039 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3040 HeapFree(GetProcessHeap(), 0, job->document_title);
3041 job->document_title = strdupW(info1->pDocument);
3042 break;
3044 case 2:
3046 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3047 HeapFree(GetProcessHeap(), 0, job->document_title);
3048 job->document_title = strdupW(info2->pDocument);
3049 HeapFree(GetProcessHeap(), 0, job->devmode);
3050 job->devmode = dup_devmode( info2->pDevMode );
3051 break;
3053 case 3:
3054 break;
3055 default:
3056 SetLastError(ERROR_INVALID_LEVEL);
3057 goto end;
3059 ret = TRUE;
3060 end:
3061 LeaveCriticalSection(&printer_handles_cs);
3062 return ret;
3065 /*****************************************************************************
3066 * EndDocPrinter [WINSPOOL.@]
3068 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3070 opened_printer_t *printer;
3071 BOOL ret = FALSE;
3072 TRACE("(%p)\n", hPrinter);
3074 EnterCriticalSection(&printer_handles_cs);
3076 printer = get_opened_printer(hPrinter);
3077 if(!printer)
3079 SetLastError(ERROR_INVALID_HANDLE);
3080 goto end;
3083 if(!printer->doc)
3085 SetLastError(ERROR_SPL_NO_STARTDOC);
3086 goto end;
3089 CloseHandle(printer->doc->hf);
3090 ScheduleJob(hPrinter, printer->doc->job_id);
3091 HeapFree(GetProcessHeap(), 0, printer->doc);
3092 printer->doc = NULL;
3093 ret = TRUE;
3094 end:
3095 LeaveCriticalSection(&printer_handles_cs);
3096 return ret;
3099 /*****************************************************************************
3100 * EndPagePrinter [WINSPOOL.@]
3102 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3104 FIXME("(%p): stub\n", hPrinter);
3105 return TRUE;
3108 /*****************************************************************************
3109 * StartDocPrinterA [WINSPOOL.@]
3111 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3113 UNICODE_STRING usBuffer;
3114 DOC_INFO_2W doc2W;
3115 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3116 DWORD ret;
3118 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3119 or one (DOC_INFO_3) extra DWORDs */
3121 switch(Level) {
3122 case 2:
3123 doc2W.JobId = doc2->JobId;
3124 /* fall through */
3125 case 3:
3126 doc2W.dwMode = doc2->dwMode;
3127 /* fall through */
3128 case 1:
3129 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3130 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3131 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3132 break;
3134 default:
3135 SetLastError(ERROR_INVALID_LEVEL);
3136 return FALSE;
3139 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3141 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3142 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3143 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3145 return ret;
3148 /*****************************************************************************
3149 * StartDocPrinterW [WINSPOOL.@]
3151 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3153 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3154 opened_printer_t *printer;
3155 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3156 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3157 JOB_INFO_1W job_info;
3158 DWORD needed, ret = 0;
3159 HANDLE hf;
3160 WCHAR *filename;
3161 job_t *job;
3163 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3164 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3165 debugstr_w(doc->pDatatype));
3167 if(Level < 1 || Level > 3)
3169 SetLastError(ERROR_INVALID_LEVEL);
3170 return 0;
3173 EnterCriticalSection(&printer_handles_cs);
3174 printer = get_opened_printer(hPrinter);
3175 if(!printer)
3177 SetLastError(ERROR_INVALID_HANDLE);
3178 goto end;
3181 if(printer->doc)
3183 SetLastError(ERROR_INVALID_PRINTER_STATE);
3184 goto end;
3187 /* Even if we're printing to a file we still add a print job, we'll
3188 just ignore the spool file name */
3190 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3192 ERR("AddJob failed gle %u\n", GetLastError());
3193 goto end;
3196 /* use pOutputFile only, when it is a real filename */
3197 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3198 filename = doc->pOutputFile;
3199 else
3200 filename = addjob->Path;
3202 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3203 if(hf == INVALID_HANDLE_VALUE)
3204 goto end;
3206 memset(&job_info, 0, sizeof(job_info));
3207 job_info.pDocument = doc->pDocName;
3208 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3210 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3211 printer->doc->hf = hf;
3212 ret = printer->doc->job_id = addjob->JobId;
3213 job = get_job(hPrinter, ret);
3214 job->portname = strdupW(doc->pOutputFile);
3216 end:
3217 LeaveCriticalSection(&printer_handles_cs);
3219 return ret;
3222 /*****************************************************************************
3223 * StartPagePrinter [WINSPOOL.@]
3225 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3227 FIXME("(%p): stub\n", hPrinter);
3228 return TRUE;
3231 /*****************************************************************************
3232 * GetFormA [WINSPOOL.@]
3234 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3235 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3237 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3238 Level,pForm,cbBuf,pcbNeeded);
3239 return FALSE;
3242 /*****************************************************************************
3243 * GetFormW [WINSPOOL.@]
3245 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3246 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3248 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3249 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3250 return FALSE;
3253 /*****************************************************************************
3254 * SetFormA [WINSPOOL.@]
3256 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3257 LPBYTE pForm)
3259 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3260 return FALSE;
3263 /*****************************************************************************
3264 * SetFormW [WINSPOOL.@]
3266 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3267 LPBYTE pForm)
3269 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3270 return FALSE;
3273 /*****************************************************************************
3274 * ReadPrinter [WINSPOOL.@]
3276 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3277 LPDWORD pNoBytesRead)
3279 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3280 return FALSE;
3283 /*****************************************************************************
3284 * ResetPrinterA [WINSPOOL.@]
3286 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3288 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3289 return FALSE;
3292 /*****************************************************************************
3293 * ResetPrinterW [WINSPOOL.@]
3295 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3297 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3298 return FALSE;
3301 /*****************************************************************************
3302 * WINSPOOL_GetDWORDFromReg
3304 * Return DWORD associated with ValueName from hkey.
3306 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3308 DWORD sz = sizeof(DWORD), type, value = 0;
3309 LONG ret;
3311 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3313 if(ret != ERROR_SUCCESS) {
3314 WARN("Got ret = %d on name %s\n", ret, ValueName);
3315 return 0;
3317 if(type != REG_DWORD) {
3318 ERR("Got type %d\n", type);
3319 return 0;
3321 return value;
3325 /*****************************************************************************
3326 * get_filename_from_reg [internal]
3328 * Get ValueName from hkey storing result in out
3329 * when the Value in the registry has only a filename, use driverdir as prefix
3330 * outlen is space left in out
3331 * String is stored either as unicode or ascii
3335 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3336 LPBYTE out, DWORD outlen, LPDWORD needed)
3338 WCHAR filename[MAX_PATH];
3339 DWORD size;
3340 DWORD type;
3341 LONG ret;
3342 LPWSTR buffer = filename;
3343 LPWSTR ptr;
3345 *needed = 0;
3346 size = sizeof(filename);
3347 buffer[0] = '\0';
3348 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3349 if (ret == ERROR_MORE_DATA) {
3350 TRACE("need dynamic buffer: %u\n", size);
3351 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3352 if (!buffer) {
3353 /* No Memory is bad */
3354 return FALSE;
3356 buffer[0] = '\0';
3357 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3360 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3361 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3362 return FALSE;
3365 ptr = buffer;
3366 while (ptr) {
3367 /* do we have a full path ? */
3368 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3369 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3371 if (!ret) {
3372 /* we must build the full Path */
3373 *needed += dirlen;
3374 if ((out) && (outlen > dirlen)) {
3375 lstrcpyW((LPWSTR)out, driverdir);
3376 out += dirlen;
3377 outlen -= dirlen;
3379 else
3380 out = NULL;
3383 /* write the filename */
3384 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3385 if ((out) && (outlen >= size)) {
3386 lstrcpyW((LPWSTR)out, ptr);
3387 out += size;
3388 outlen -= size;
3390 else
3391 out = NULL;
3392 *needed += size;
3393 ptr += lstrlenW(ptr)+1;
3394 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3397 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3399 /* write the multisz-termination */
3400 if (type == REG_MULTI_SZ) {
3401 size = sizeof(WCHAR);
3403 *needed += size;
3404 if (out && (outlen >= size)) {
3405 memset (out, 0, size);
3408 return TRUE;
3411 /*****************************************************************************
3412 * WINSPOOL_GetStringFromReg
3414 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3415 * String is stored as unicode.
3417 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3418 DWORD buflen, DWORD *needed)
3420 DWORD sz = buflen, type;
3421 LONG ret;
3423 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3424 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3425 WARN("Got ret = %d\n", ret);
3426 *needed = 0;
3427 return FALSE;
3429 /* add space for terminating '\0' */
3430 sz += sizeof(WCHAR);
3431 *needed = sz;
3433 if (ptr)
3434 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3436 return TRUE;
3439 /*****************************************************************************
3440 * WINSPOOL_GetDefaultDevMode
3442 * Get a default DevMode values for wineps.
3443 * FIXME - use ppd.
3446 static void WINSPOOL_GetDefaultDevMode(
3447 LPBYTE ptr,
3448 DWORD buflen, DWORD *needed)
3450 DEVMODEW dm;
3451 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3453 /* fill default DEVMODE - should be read from ppd... */
3454 ZeroMemory( &dm, sizeof(dm) );
3455 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3456 dm.dmSpecVersion = DM_SPECVERSION;
3457 dm.dmDriverVersion = 1;
3458 dm.dmSize = sizeof(DEVMODEW);
3459 dm.dmDriverExtra = 0;
3460 dm.dmFields =
3461 DM_ORIENTATION | DM_PAPERSIZE |
3462 DM_PAPERLENGTH | DM_PAPERWIDTH |
3463 DM_SCALE |
3464 DM_COPIES |
3465 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3466 DM_YRESOLUTION | DM_TTOPTION;
3468 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3469 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3470 dm.u1.s1.dmPaperLength = 2970;
3471 dm.u1.s1.dmPaperWidth = 2100;
3473 dm.u1.s1.dmScale = 100;
3474 dm.u1.s1.dmCopies = 1;
3475 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3476 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3477 /* dm.dmColor */
3478 /* dm.dmDuplex */
3479 dm.dmYResolution = 300; /* 300dpi */
3480 dm.dmTTOption = DMTT_BITMAP;
3481 /* dm.dmCollate */
3482 /* dm.dmFormName */
3483 /* dm.dmLogPixels */
3484 /* dm.dmBitsPerPel */
3485 /* dm.dmPelsWidth */
3486 /* dm.dmPelsHeight */
3487 /* dm.u2.dmDisplayFlags */
3488 /* dm.dmDisplayFrequency */
3489 /* dm.dmICMMethod */
3490 /* dm.dmICMIntent */
3491 /* dm.dmMediaType */
3492 /* dm.dmDitherType */
3493 /* dm.dmReserved1 */
3494 /* dm.dmReserved2 */
3495 /* dm.dmPanningWidth */
3496 /* dm.dmPanningHeight */
3498 if(buflen >= sizeof(DEVMODEW))
3499 memcpy(ptr, &dm, sizeof(DEVMODEW));
3500 *needed = sizeof(DEVMODEW);
3503 /*****************************************************************************
3504 * WINSPOOL_GetDevModeFromReg
3506 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3507 * DevMode is stored either as unicode or ascii.
3509 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3510 LPBYTE ptr,
3511 DWORD buflen, DWORD *needed)
3513 DWORD sz = buflen, type;
3514 LONG ret;
3516 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3517 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3518 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3519 if (sz < sizeof(DEVMODEA))
3521 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3522 return FALSE;
3524 /* ensures that dmSize is not erratically bogus if registry is invalid */
3525 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3526 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3527 sz += (CCHDEVICENAME + CCHFORMNAME);
3528 if (ptr && (buflen >= sz)) {
3529 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3530 memcpy(ptr, dmW, sz);
3531 HeapFree(GetProcessHeap(),0,dmW);
3533 *needed = sz;
3534 return TRUE;
3537 /*********************************************************************
3538 * WINSPOOL_GetPrinter_1
3540 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3542 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3543 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3545 DWORD size, left = cbBuf;
3546 BOOL space = (cbBuf > 0);
3547 LPBYTE ptr = buf;
3549 *pcbNeeded = 0;
3551 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3552 if(space && size <= left) {
3553 pi1->pName = (LPWSTR)ptr;
3554 ptr += size;
3555 left -= size;
3556 } else
3557 space = FALSE;
3558 *pcbNeeded += size;
3561 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3562 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3563 if(space && size <= left) {
3564 pi1->pDescription = (LPWSTR)ptr;
3565 ptr += size;
3566 left -= size;
3567 } else
3568 space = FALSE;
3569 *pcbNeeded += size;
3572 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3573 if(space && size <= left) {
3574 pi1->pComment = (LPWSTR)ptr;
3575 ptr += size;
3576 left -= size;
3577 } else
3578 space = FALSE;
3579 *pcbNeeded += size;
3582 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3584 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3585 memset(pi1, 0, sizeof(*pi1));
3587 return space;
3589 /*********************************************************************
3590 * WINSPOOL_GetPrinter_2
3592 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3594 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3595 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3597 DWORD size, left = cbBuf;
3598 BOOL space = (cbBuf > 0);
3599 LPBYTE ptr = buf;
3601 *pcbNeeded = 0;
3603 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3604 if(space && size <= left) {
3605 pi2->pPrinterName = (LPWSTR)ptr;
3606 ptr += size;
3607 left -= size;
3608 } else
3609 space = FALSE;
3610 *pcbNeeded += size;
3612 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3613 if(space && size <= left) {
3614 pi2->pShareName = (LPWSTR)ptr;
3615 ptr += size;
3616 left -= size;
3617 } else
3618 space = FALSE;
3619 *pcbNeeded += size;
3621 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3622 if(space && size <= left) {
3623 pi2->pPortName = (LPWSTR)ptr;
3624 ptr += size;
3625 left -= size;
3626 } else
3627 space = FALSE;
3628 *pcbNeeded += size;
3630 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3631 if(space && size <= left) {
3632 pi2->pDriverName = (LPWSTR)ptr;
3633 ptr += size;
3634 left -= size;
3635 } else
3636 space = FALSE;
3637 *pcbNeeded += size;
3639 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3640 if(space && size <= left) {
3641 pi2->pComment = (LPWSTR)ptr;
3642 ptr += size;
3643 left -= size;
3644 } else
3645 space = FALSE;
3646 *pcbNeeded += size;
3648 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3649 if(space && size <= left) {
3650 pi2->pLocation = (LPWSTR)ptr;
3651 ptr += size;
3652 left -= size;
3653 } else
3654 space = FALSE;
3655 *pcbNeeded += size;
3657 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3658 if(space && size <= left) {
3659 pi2->pDevMode = (LPDEVMODEW)ptr;
3660 ptr += size;
3661 left -= size;
3662 } else
3663 space = FALSE;
3664 *pcbNeeded += size;
3666 else
3668 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3669 if(space && size <= left) {
3670 pi2->pDevMode = (LPDEVMODEW)ptr;
3671 ptr += size;
3672 left -= size;
3673 } else
3674 space = FALSE;
3675 *pcbNeeded += size;
3677 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3678 if(space && size <= left) {
3679 pi2->pSepFile = (LPWSTR)ptr;
3680 ptr += size;
3681 left -= size;
3682 } else
3683 space = FALSE;
3684 *pcbNeeded += size;
3686 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3687 if(space && size <= left) {
3688 pi2->pPrintProcessor = (LPWSTR)ptr;
3689 ptr += size;
3690 left -= size;
3691 } else
3692 space = FALSE;
3693 *pcbNeeded += size;
3695 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3696 if(space && size <= left) {
3697 pi2->pDatatype = (LPWSTR)ptr;
3698 ptr += size;
3699 left -= size;
3700 } else
3701 space = FALSE;
3702 *pcbNeeded += size;
3704 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3705 if(space && size <= left) {
3706 pi2->pParameters = (LPWSTR)ptr;
3707 ptr += size;
3708 left -= size;
3709 } else
3710 space = FALSE;
3711 *pcbNeeded += size;
3713 if(pi2) {
3714 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3715 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3716 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3717 "Default Priority");
3718 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3719 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3722 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3723 memset(pi2, 0, sizeof(*pi2));
3725 return space;
3728 /*********************************************************************
3729 * WINSPOOL_GetPrinter_4
3731 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3733 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3734 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3736 DWORD size, left = cbBuf;
3737 BOOL space = (cbBuf > 0);
3738 LPBYTE ptr = buf;
3740 *pcbNeeded = 0;
3742 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3743 if(space && size <= left) {
3744 pi4->pPrinterName = (LPWSTR)ptr;
3745 ptr += size;
3746 left -= size;
3747 } else
3748 space = FALSE;
3749 *pcbNeeded += size;
3751 if(pi4) {
3752 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3755 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3756 memset(pi4, 0, sizeof(*pi4));
3758 return space;
3761 /*********************************************************************
3762 * WINSPOOL_GetPrinter_5
3764 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3766 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3767 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3769 DWORD size, left = cbBuf;
3770 BOOL space = (cbBuf > 0);
3771 LPBYTE ptr = buf;
3773 *pcbNeeded = 0;
3775 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3776 if(space && size <= left) {
3777 pi5->pPrinterName = (LPWSTR)ptr;
3778 ptr += size;
3779 left -= size;
3780 } else
3781 space = FALSE;
3782 *pcbNeeded += size;
3784 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3785 if(space && size <= left) {
3786 pi5->pPortName = (LPWSTR)ptr;
3787 ptr += size;
3788 left -= size;
3789 } else
3790 space = FALSE;
3791 *pcbNeeded += size;
3793 if(pi5) {
3794 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3795 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3796 "dnsTimeout");
3797 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3798 "txTimeout");
3801 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3802 memset(pi5, 0, sizeof(*pi5));
3804 return space;
3807 /*********************************************************************
3808 * WINSPOOL_GetPrinter_7
3810 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3812 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3813 DWORD cbBuf, LPDWORD pcbNeeded)
3815 DWORD size, left = cbBuf;
3816 BOOL space = (cbBuf > 0);
3817 LPBYTE ptr = buf;
3819 *pcbNeeded = 0;
3821 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3823 ptr = NULL;
3824 size = sizeof(pi7->pszObjectGUID);
3826 if (space && size <= left) {
3827 pi7->pszObjectGUID = (LPWSTR)ptr;
3828 ptr += size;
3829 left -= size;
3830 } else
3831 space = FALSE;
3832 *pcbNeeded += size;
3833 if (pi7) {
3834 /* We do not have a Directory Service */
3835 pi7->dwAction = DSPRINT_UNPUBLISH;
3838 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3839 memset(pi7, 0, sizeof(*pi7));
3841 return space;
3844 /*********************************************************************
3845 * WINSPOOL_GetPrinter_9
3847 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3849 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3850 DWORD cbBuf, LPDWORD pcbNeeded)
3852 DWORD size;
3853 BOOL space = (cbBuf > 0);
3855 *pcbNeeded = 0;
3857 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3858 if(space && size <= cbBuf) {
3859 pi9->pDevMode = (LPDEVMODEW)buf;
3860 } else
3861 space = FALSE;
3862 *pcbNeeded += size;
3864 else
3866 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3867 if(space && size <= cbBuf) {
3868 pi9->pDevMode = (LPDEVMODEW)buf;
3869 } else
3870 space = FALSE;
3871 *pcbNeeded += size;
3874 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3875 memset(pi9, 0, sizeof(*pi9));
3877 return space;
3880 /*****************************************************************************
3881 * GetPrinterW [WINSPOOL.@]
3883 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3884 DWORD cbBuf, LPDWORD pcbNeeded)
3886 DWORD size, needed = 0, err;
3887 LPBYTE ptr = NULL;
3888 HKEY hkeyPrinter;
3889 BOOL ret;
3891 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3893 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
3894 if (err)
3896 SetLastError( err );
3897 return FALSE;
3900 switch(Level) {
3901 case 2:
3903 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3905 size = sizeof(PRINTER_INFO_2W);
3906 if(size <= cbBuf) {
3907 ptr = pPrinter + size;
3908 cbBuf -= size;
3909 memset(pPrinter, 0, size);
3910 } else {
3911 pi2 = NULL;
3912 cbBuf = 0;
3914 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3915 needed += size;
3916 break;
3919 case 4:
3921 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3923 size = sizeof(PRINTER_INFO_4W);
3924 if(size <= cbBuf) {
3925 ptr = pPrinter + size;
3926 cbBuf -= size;
3927 memset(pPrinter, 0, size);
3928 } else {
3929 pi4 = NULL;
3930 cbBuf = 0;
3932 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3933 needed += size;
3934 break;
3938 case 5:
3940 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3942 size = sizeof(PRINTER_INFO_5W);
3943 if(size <= cbBuf) {
3944 ptr = pPrinter + size;
3945 cbBuf -= size;
3946 memset(pPrinter, 0, size);
3947 } else {
3948 pi5 = NULL;
3949 cbBuf = 0;
3952 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3953 needed += size;
3954 break;
3958 case 6:
3960 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3962 size = sizeof(PRINTER_INFO_6);
3963 if (size <= cbBuf) {
3964 /* FIXME: We do not update the status yet */
3965 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3966 ret = TRUE;
3967 } else {
3968 ret = FALSE;
3971 needed += size;
3972 break;
3975 case 7:
3977 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3979 size = sizeof(PRINTER_INFO_7W);
3980 if (size <= cbBuf) {
3981 ptr = pPrinter + size;
3982 cbBuf -= size;
3983 memset(pPrinter, 0, size);
3984 } else {
3985 pi7 = NULL;
3986 cbBuf = 0;
3989 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3990 needed += size;
3991 break;
3995 case 9:
3997 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3999 size = sizeof(PRINTER_INFO_9W);
4000 if(size <= cbBuf) {
4001 ptr = pPrinter + size;
4002 cbBuf -= size;
4003 memset(pPrinter, 0, size);
4004 } else {
4005 pi9 = NULL;
4006 cbBuf = 0;
4009 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4010 needed += size;
4011 break;
4015 default:
4016 FIXME("Unimplemented level %d\n", Level);
4017 SetLastError(ERROR_INVALID_LEVEL);
4018 RegCloseKey(hkeyPrinter);
4019 return FALSE;
4022 RegCloseKey(hkeyPrinter);
4024 TRACE("returning %d needed = %d\n", ret, needed);
4025 if(pcbNeeded) *pcbNeeded = needed;
4026 if(!ret)
4027 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4028 return ret;
4031 /*****************************************************************************
4032 * GetPrinterA [WINSPOOL.@]
4034 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4035 DWORD cbBuf, LPDWORD pcbNeeded)
4037 BOOL ret;
4038 LPBYTE buf = NULL;
4040 if (cbBuf)
4041 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4043 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4044 if (ret)
4045 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4046 HeapFree(GetProcessHeap(), 0, buf);
4048 return ret;
4051 /*****************************************************************************
4052 * WINSPOOL_EnumPrintersW
4054 * Implementation of EnumPrintersW
4056 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4057 DWORD dwLevel, LPBYTE lpbPrinters,
4058 DWORD cbBuf, LPDWORD lpdwNeeded,
4059 LPDWORD lpdwReturned)
4062 HKEY hkeyPrinters, hkeyPrinter;
4063 WCHAR PrinterName[255];
4064 DWORD needed = 0, number = 0;
4065 DWORD used, i, left;
4066 PBYTE pi, buf;
4068 if(lpbPrinters)
4069 memset(lpbPrinters, 0, cbBuf);
4070 if(lpdwReturned)
4071 *lpdwReturned = 0;
4072 if(lpdwNeeded)
4073 *lpdwNeeded = 0;
4075 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4076 if(dwType == PRINTER_ENUM_DEFAULT)
4077 return TRUE;
4079 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4080 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4081 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4082 if (!dwType) {
4083 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4084 return TRUE;
4089 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4090 FIXME("dwType = %08x\n", dwType);
4091 SetLastError(ERROR_INVALID_FLAGS);
4092 return FALSE;
4095 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4096 ERROR_SUCCESS) {
4097 ERR("Can't create Printers key\n");
4098 return FALSE;
4101 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4102 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4103 RegCloseKey(hkeyPrinters);
4104 ERR("Can't query Printers key\n");
4105 return FALSE;
4107 TRACE("Found %d printers\n", number);
4109 switch(dwLevel) {
4110 case 1:
4111 used = number * sizeof(PRINTER_INFO_1W);
4112 break;
4113 case 2:
4114 used = number * sizeof(PRINTER_INFO_2W);
4115 break;
4116 case 4:
4117 used = number * sizeof(PRINTER_INFO_4W);
4118 break;
4119 case 5:
4120 used = number * sizeof(PRINTER_INFO_5W);
4121 break;
4123 default:
4124 SetLastError(ERROR_INVALID_LEVEL);
4125 RegCloseKey(hkeyPrinters);
4126 return FALSE;
4128 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4130 for(i = 0; i < number; i++) {
4131 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4132 ERROR_SUCCESS) {
4133 ERR("Can't enum key number %d\n", i);
4134 RegCloseKey(hkeyPrinters);
4135 return FALSE;
4137 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4138 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4139 ERROR_SUCCESS) {
4140 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4141 RegCloseKey(hkeyPrinters);
4142 return FALSE;
4145 if(cbBuf > used) {
4146 buf = lpbPrinters + used;
4147 left = cbBuf - used;
4148 } else {
4149 buf = NULL;
4150 left = 0;
4153 switch(dwLevel) {
4154 case 1:
4155 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4156 left, &needed);
4157 used += needed;
4158 if(pi) pi += sizeof(PRINTER_INFO_1W);
4159 break;
4160 case 2:
4161 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4162 left, &needed);
4163 used += needed;
4164 if(pi) pi += sizeof(PRINTER_INFO_2W);
4165 break;
4166 case 4:
4167 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4168 left, &needed);
4169 used += needed;
4170 if(pi) pi += sizeof(PRINTER_INFO_4W);
4171 break;
4172 case 5:
4173 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4174 left, &needed);
4175 used += needed;
4176 if(pi) pi += sizeof(PRINTER_INFO_5W);
4177 break;
4178 default:
4179 ERR("Shouldn't be here!\n");
4180 RegCloseKey(hkeyPrinter);
4181 RegCloseKey(hkeyPrinters);
4182 return FALSE;
4184 RegCloseKey(hkeyPrinter);
4186 RegCloseKey(hkeyPrinters);
4188 if(lpdwNeeded)
4189 *lpdwNeeded = used;
4191 if(used > cbBuf) {
4192 if(lpbPrinters)
4193 memset(lpbPrinters, 0, cbBuf);
4194 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4195 return FALSE;
4197 if(lpdwReturned)
4198 *lpdwReturned = number;
4199 SetLastError(ERROR_SUCCESS);
4200 return TRUE;
4204 /******************************************************************
4205 * EnumPrintersW [WINSPOOL.@]
4207 * Enumerates the available printers, print servers and print
4208 * providers, depending on the specified flags, name and level.
4210 * RETURNS:
4212 * If level is set to 1:
4213 * Returns an array of PRINTER_INFO_1 data structures in the
4214 * lpbPrinters buffer.
4216 * If level is set to 2:
4217 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4218 * Returns an array of PRINTER_INFO_2 data structures in the
4219 * lpbPrinters buffer. Note that according to MSDN also an
4220 * OpenPrinter should be performed on every remote printer.
4222 * If level is set to 4 (officially WinNT only):
4223 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4224 * Fast: Only the registry is queried to retrieve printer names,
4225 * no connection to the driver is made.
4226 * Returns an array of PRINTER_INFO_4 data structures in the
4227 * lpbPrinters buffer.
4229 * If level is set to 5 (officially WinNT4/Win9x only):
4230 * Fast: Only the registry is queried to retrieve printer names,
4231 * no connection to the driver is made.
4232 * Returns an array of PRINTER_INFO_5 data structures in the
4233 * lpbPrinters buffer.
4235 * If level set to 3 or 6+:
4236 * returns zero (failure!)
4238 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4239 * for information.
4241 * BUGS:
4242 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4243 * - Only levels 2, 4 and 5 are implemented at the moment.
4244 * - 16-bit printer drivers are not enumerated.
4245 * - Returned amount of bytes used/needed does not match the real Windoze
4246 * implementation (as in this implementation, all strings are part
4247 * of the buffer, whereas Win32 keeps them somewhere else)
4248 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4250 * NOTE:
4251 * - In a regular Wine installation, no registry settings for printers
4252 * exist, which makes this function return an empty list.
4254 BOOL WINAPI EnumPrintersW(
4255 DWORD dwType, /* [in] Types of print objects to enumerate */
4256 LPWSTR lpszName, /* [in] name of objects to enumerate */
4257 DWORD dwLevel, /* [in] type of printer info structure */
4258 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4259 DWORD cbBuf, /* [in] max size of buffer in bytes */
4260 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4261 LPDWORD lpdwReturned /* [out] number of entries returned */
4264 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4265 lpdwNeeded, lpdwReturned);
4268 /******************************************************************
4269 * EnumPrintersA [WINSPOOL.@]
4271 * See EnumPrintersW
4274 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4275 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4277 BOOL ret;
4278 UNICODE_STRING pNameU;
4279 LPWSTR pNameW;
4280 LPBYTE pPrintersW;
4282 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4283 pPrinters, cbBuf, pcbNeeded, pcReturned);
4285 pNameW = asciitounicode(&pNameU, pName);
4287 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4288 MS Office need this */
4289 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4291 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4293 RtlFreeUnicodeString(&pNameU);
4294 if (ret) {
4295 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4297 HeapFree(GetProcessHeap(), 0, pPrintersW);
4298 return ret;
4301 /*****************************************************************************
4302 * WINSPOOL_GetDriverInfoFromReg [internal]
4304 * Enters the information from the registry into the DRIVER_INFO struct
4306 * RETURNS
4307 * zero if the printer driver does not exist in the registry
4308 * (only if Level > 1) otherwise nonzero
4310 static BOOL WINSPOOL_GetDriverInfoFromReg(
4311 HKEY hkeyDrivers,
4312 LPWSTR DriverName,
4313 const printenv_t * env,
4314 DWORD Level,
4315 LPBYTE ptr, /* DRIVER_INFO */
4316 LPBYTE pDriverStrings, /* strings buffer */
4317 DWORD cbBuf, /* size of string buffer */
4318 LPDWORD pcbNeeded) /* space needed for str. */
4320 DWORD size, tmp;
4321 HKEY hkeyDriver;
4322 WCHAR driverdir[MAX_PATH];
4323 DWORD dirlen;
4324 LPBYTE strPtr = pDriverStrings;
4325 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4327 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4328 debugstr_w(DriverName), env,
4329 Level, di, pDriverStrings, cbBuf);
4331 if (di) ZeroMemory(di, di_sizeof[Level]);
4333 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4334 if (*pcbNeeded <= cbBuf)
4335 strcpyW((LPWSTR)strPtr, DriverName);
4337 /* pName for level 1 has a different offset! */
4338 if (Level == 1) {
4339 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4340 return TRUE;
4343 /* .cVersion and .pName for level > 1 */
4344 if (di) {
4345 di->cVersion = env->driverversion;
4346 di->pName = (LPWSTR) strPtr;
4347 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4350 /* Reserve Space for the largest subdir and a Backslash*/
4351 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4352 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4353 /* Should never Fail */
4354 return FALSE;
4356 lstrcatW(driverdir, env->versionsubdir);
4357 lstrcatW(driverdir, backslashW);
4359 /* dirlen must not include the terminating zero */
4360 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4362 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4363 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4364 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4365 return FALSE;
4368 /* pEnvironment */
4369 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4371 *pcbNeeded += size;
4372 if (*pcbNeeded <= cbBuf) {
4373 lstrcpyW((LPWSTR)strPtr, env->envname);
4374 if (di) di->pEnvironment = (LPWSTR)strPtr;
4375 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4378 /* .pDriverPath is the Graphics rendering engine.
4379 The full Path is required to avoid a crash in some apps */
4380 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4381 *pcbNeeded += size;
4382 if (*pcbNeeded <= cbBuf)
4383 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4385 if (di) di->pDriverPath = (LPWSTR)strPtr;
4386 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4389 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4390 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4391 *pcbNeeded += size;
4392 if (*pcbNeeded <= cbBuf)
4393 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4395 if (di) di->pDataFile = (LPWSTR)strPtr;
4396 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4399 /* .pConfigFile is the Driver user Interface */
4400 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4401 *pcbNeeded += size;
4402 if (*pcbNeeded <= cbBuf)
4403 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4405 if (di) di->pConfigFile = (LPWSTR)strPtr;
4406 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4409 if (Level == 2 ) {
4410 RegCloseKey(hkeyDriver);
4411 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4412 return TRUE;
4415 if (Level == 5 ) {
4416 RegCloseKey(hkeyDriver);
4417 FIXME("level 5: incomplete\n");
4418 return TRUE;
4421 /* .pHelpFile */
4422 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4423 *pcbNeeded += size;
4424 if (*pcbNeeded <= cbBuf)
4425 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4427 if (di) di->pHelpFile = (LPWSTR)strPtr;
4428 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4431 /* .pDependentFiles */
4432 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4433 *pcbNeeded += size;
4434 if (*pcbNeeded <= cbBuf)
4435 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4437 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4438 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4440 else if (GetVersion() & 0x80000000) {
4441 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4442 size = 2 * sizeof(WCHAR);
4443 *pcbNeeded += size;
4444 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4446 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4447 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4450 /* .pMonitorName is the optional Language Monitor */
4451 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4452 *pcbNeeded += size;
4453 if (*pcbNeeded <= cbBuf)
4454 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4456 if (di) di->pMonitorName = (LPWSTR)strPtr;
4457 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4460 /* .pDefaultDataType */
4461 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4462 *pcbNeeded += size;
4463 if(*pcbNeeded <= cbBuf)
4464 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4466 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4467 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4470 if (Level == 3 ) {
4471 RegCloseKey(hkeyDriver);
4472 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4473 return TRUE;
4476 /* .pszzPreviousNames */
4477 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4478 *pcbNeeded += size;
4479 if(*pcbNeeded <= cbBuf)
4480 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4482 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4483 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4486 if (Level == 4 ) {
4487 RegCloseKey(hkeyDriver);
4488 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4489 return TRUE;
4492 /* support is missing, but not important enough for a FIXME */
4493 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4495 /* .pszMfgName */
4496 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4497 *pcbNeeded += size;
4498 if(*pcbNeeded <= cbBuf)
4499 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4501 if (di) di->pszMfgName = (LPWSTR)strPtr;
4502 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4505 /* .pszOEMUrl */
4506 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4507 *pcbNeeded += size;
4508 if(*pcbNeeded <= cbBuf)
4509 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4511 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4512 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4515 /* .pszHardwareID */
4516 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4517 *pcbNeeded += size;
4518 if(*pcbNeeded <= cbBuf)
4519 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4521 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4522 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4525 /* .pszProvider */
4526 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4527 *pcbNeeded += size;
4528 if(*pcbNeeded <= cbBuf)
4529 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4531 if (di) di->pszProvider = (LPWSTR)strPtr;
4532 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4535 if (Level == 6 ) {
4536 RegCloseKey(hkeyDriver);
4537 return TRUE;
4540 /* support is missing, but not important enough for a FIXME */
4541 TRACE("level 8: incomplete\n");
4543 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4544 RegCloseKey(hkeyDriver);
4545 return TRUE;
4548 /*****************************************************************************
4549 * GetPrinterDriverW [WINSPOOL.@]
4551 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4552 DWORD Level, LPBYTE pDriverInfo,
4553 DWORD cbBuf, LPDWORD pcbNeeded)
4555 LPCWSTR name;
4556 WCHAR DriverName[100];
4557 DWORD ret, type, size, needed = 0;
4558 LPBYTE ptr = NULL;
4559 HKEY hkeyPrinter, hkeyDrivers;
4560 const printenv_t * env;
4562 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4563 Level,pDriverInfo,cbBuf, pcbNeeded);
4565 if (cbBuf > 0)
4566 ZeroMemory(pDriverInfo, cbBuf);
4568 if (!(name = get_opened_printer_name(hPrinter))) {
4569 SetLastError(ERROR_INVALID_HANDLE);
4570 return FALSE;
4573 if (Level < 1 || Level == 7 || Level > 8) {
4574 SetLastError(ERROR_INVALID_LEVEL);
4575 return FALSE;
4578 env = validate_envW(pEnvironment);
4579 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4581 ret = open_printer_reg_key( name, &hkeyPrinter );
4582 if (ret)
4584 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4585 SetLastError( ret );
4586 return FALSE;
4589 size = sizeof(DriverName);
4590 DriverName[0] = 0;
4591 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4592 (LPBYTE)DriverName, &size);
4593 RegCloseKey(hkeyPrinter);
4594 if(ret != ERROR_SUCCESS) {
4595 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4596 return FALSE;
4599 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4600 if(!hkeyDrivers) {
4601 ERR("Can't create Drivers key\n");
4602 return FALSE;
4605 size = di_sizeof[Level];
4606 if ((size <= cbBuf) && pDriverInfo)
4607 ptr = pDriverInfo + size;
4609 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4610 env, Level, pDriverInfo, ptr,
4611 (cbBuf < size) ? 0 : cbBuf - size,
4612 &needed)) {
4613 RegCloseKey(hkeyDrivers);
4614 return FALSE;
4617 RegCloseKey(hkeyDrivers);
4619 if(pcbNeeded) *pcbNeeded = size + needed;
4620 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4621 if(cbBuf >= size + needed) return TRUE;
4622 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4623 return FALSE;
4626 /*****************************************************************************
4627 * GetPrinterDriverA [WINSPOOL.@]
4629 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4630 DWORD Level, LPBYTE pDriverInfo,
4631 DWORD cbBuf, LPDWORD pcbNeeded)
4633 BOOL ret;
4634 UNICODE_STRING pEnvW;
4635 PWSTR pwstrEnvW;
4636 LPBYTE buf = NULL;
4638 if (cbBuf)
4640 ZeroMemory(pDriverInfo, cbBuf);
4641 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4644 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4645 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4646 cbBuf, pcbNeeded);
4647 if (ret)
4648 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4650 HeapFree(GetProcessHeap(), 0, buf);
4652 RtlFreeUnicodeString(&pEnvW);
4653 return ret;
4656 /*****************************************************************************
4657 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4659 * Return the PATH for the Printer-Drivers (UNICODE)
4661 * PARAMS
4662 * pName [I] Servername (NT only) or NULL (local Computer)
4663 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4664 * Level [I] Structure-Level (must be 1)
4665 * pDriverDirectory [O] PTR to Buffer that receives the Result
4666 * cbBuf [I] Size of Buffer at pDriverDirectory
4667 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4668 * required for pDriverDirectory
4670 * RETURNS
4671 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4672 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4673 * if cbBuf is too small
4675 * Native Values returned in pDriverDirectory on Success:
4676 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4677 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4678 *| win9x(Windows 4.0): "%winsysdir%"
4680 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4682 * FIXME
4683 *- Only NULL or "" is supported for pName
4686 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4687 DWORD Level, LPBYTE pDriverDirectory,
4688 DWORD cbBuf, LPDWORD pcbNeeded)
4690 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4691 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4693 if ((backend == NULL) && !load_backend()) return FALSE;
4695 if (Level != 1) {
4696 /* (Level != 1) is ignored in win9x */
4697 SetLastError(ERROR_INVALID_LEVEL);
4698 return FALSE;
4700 if (pcbNeeded == NULL) {
4701 /* (pcbNeeded == NULL) is ignored in win9x */
4702 SetLastError(RPC_X_NULL_REF_POINTER);
4703 return FALSE;
4706 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4707 pDriverDirectory, cbBuf, pcbNeeded);
4712 /*****************************************************************************
4713 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4715 * Return the PATH for the Printer-Drivers (ANSI)
4717 * See GetPrinterDriverDirectoryW.
4719 * NOTES
4720 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4723 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4724 DWORD Level, LPBYTE pDriverDirectory,
4725 DWORD cbBuf, LPDWORD pcbNeeded)
4727 UNICODE_STRING nameW, environmentW;
4728 BOOL ret;
4729 DWORD pcbNeededW;
4730 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4731 WCHAR *driverDirectoryW = NULL;
4733 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4734 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4736 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4738 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4739 else nameW.Buffer = NULL;
4740 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4741 else environmentW.Buffer = NULL;
4743 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4744 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4745 if (ret) {
4746 DWORD needed;
4747 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4748 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4749 if(pcbNeeded)
4750 *pcbNeeded = needed;
4751 ret = (needed <= cbBuf) ? TRUE : FALSE;
4752 } else
4753 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4755 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4757 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4758 RtlFreeUnicodeString(&environmentW);
4759 RtlFreeUnicodeString(&nameW);
4761 return ret;
4764 /*****************************************************************************
4765 * AddPrinterDriverA [WINSPOOL.@]
4767 * See AddPrinterDriverW.
4770 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4772 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4773 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4776 /******************************************************************************
4777 * AddPrinterDriverW (WINSPOOL.@)
4779 * Install a Printer Driver
4781 * PARAMS
4782 * pName [I] Servername or NULL (local Computer)
4783 * level [I] Level for the supplied DRIVER_INFO_*W struct
4784 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4786 * RESULTS
4787 * Success: TRUE
4788 * Failure: FALSE
4791 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4793 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4794 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4797 /*****************************************************************************
4798 * AddPrintProcessorA [WINSPOOL.@]
4800 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4801 LPSTR pPrintProcessorName)
4803 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4804 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4805 return FALSE;
4808 /*****************************************************************************
4809 * AddPrintProcessorW [WINSPOOL.@]
4811 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4812 LPWSTR pPrintProcessorName)
4814 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4815 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4816 return TRUE;
4819 /*****************************************************************************
4820 * AddPrintProvidorA [WINSPOOL.@]
4822 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4824 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4825 return FALSE;
4828 /*****************************************************************************
4829 * AddPrintProvidorW [WINSPOOL.@]
4831 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4833 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4834 return FALSE;
4837 /*****************************************************************************
4838 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4840 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4841 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4843 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4844 pDevModeOutput, pDevModeInput);
4845 return 0;
4848 /*****************************************************************************
4849 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4851 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4852 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4854 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4855 pDevModeOutput, pDevModeInput);
4856 return 0;
4859 /*****************************************************************************
4860 * PrinterProperties [WINSPOOL.@]
4862 * Displays a dialog to set the properties of the printer.
4864 * RETURNS
4865 * nonzero on success or zero on failure
4867 * BUGS
4868 * implemented as stub only
4870 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4871 HANDLE hPrinter /* [in] handle to printer object */
4873 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4874 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4875 return FALSE;
4878 /*****************************************************************************
4879 * EnumJobsA [WINSPOOL.@]
4882 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4883 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4884 LPDWORD pcReturned)
4886 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4887 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4889 if(pcbNeeded) *pcbNeeded = 0;
4890 if(pcReturned) *pcReturned = 0;
4891 return FALSE;
4895 /*****************************************************************************
4896 * EnumJobsW [WINSPOOL.@]
4899 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4900 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4901 LPDWORD pcReturned)
4903 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4904 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4906 if(pcbNeeded) *pcbNeeded = 0;
4907 if(pcReturned) *pcReturned = 0;
4908 return FALSE;
4911 /*****************************************************************************
4912 * WINSPOOL_EnumPrinterDrivers [internal]
4914 * Delivers information about all printer drivers installed on the
4915 * localhost or a given server
4917 * RETURNS
4918 * nonzero on success or zero on failure. If the buffer for the returned
4919 * information is too small the function will return an error
4921 * BUGS
4922 * - only implemented for localhost, foreign hosts will return an error
4924 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4925 DWORD Level, LPBYTE pDriverInfo,
4926 DWORD driver_index,
4927 DWORD cbBuf, LPDWORD pcbNeeded,
4928 LPDWORD pcFound, DWORD data_offset)
4930 { HKEY hkeyDrivers;
4931 DWORD i, size = 0;
4932 const printenv_t * env;
4934 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4935 debugstr_w(pName), debugstr_w(pEnvironment),
4936 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4938 env = validate_envW(pEnvironment);
4939 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4941 *pcFound = 0;
4943 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4944 if(!hkeyDrivers) {
4945 ERR("Can't open Drivers key\n");
4946 return FALSE;
4949 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4950 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4951 RegCloseKey(hkeyDrivers);
4952 ERR("Can't query Drivers key\n");
4953 return FALSE;
4955 TRACE("Found %d Drivers\n", *pcFound);
4957 /* get size of single struct
4958 * unicode and ascii structure have the same size
4960 size = di_sizeof[Level];
4962 if (data_offset == 0)
4963 data_offset = size * (*pcFound);
4964 *pcbNeeded = data_offset;
4966 for( i = 0; i < *pcFound; i++) {
4967 WCHAR DriverNameW[255];
4968 PBYTE table_ptr = NULL;
4969 PBYTE data_ptr = NULL;
4970 DWORD needed = 0;
4972 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4973 != ERROR_SUCCESS) {
4974 ERR("Can't enum key number %d\n", i);
4975 RegCloseKey(hkeyDrivers);
4976 return FALSE;
4979 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4980 table_ptr = pDriverInfo + (driver_index + i) * size;
4981 if (pDriverInfo && *pcbNeeded <= cbBuf)
4982 data_ptr = pDriverInfo + *pcbNeeded;
4984 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4985 env, Level, table_ptr, data_ptr,
4986 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4987 &needed)) {
4988 RegCloseKey(hkeyDrivers);
4989 return FALSE;
4992 *pcbNeeded += needed;
4995 RegCloseKey(hkeyDrivers);
4997 if(cbBuf < *pcbNeeded){
4998 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4999 return FALSE;
5002 return TRUE;
5005 /*****************************************************************************
5006 * EnumPrinterDriversW [WINSPOOL.@]
5008 * see function EnumPrinterDrivers for RETURNS, BUGS
5010 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5011 LPBYTE pDriverInfo, DWORD cbBuf,
5012 LPDWORD pcbNeeded, LPDWORD pcReturned)
5014 static const WCHAR allW[] = {'a','l','l',0};
5015 BOOL ret;
5016 DWORD found;
5018 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5020 SetLastError(RPC_X_NULL_REF_POINTER);
5021 return FALSE;
5024 /* check for local drivers */
5025 if((pName) && (pName[0])) {
5026 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5027 SetLastError(ERROR_ACCESS_DENIED);
5028 return FALSE;
5031 /* check input parameter */
5032 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5033 SetLastError(ERROR_INVALID_LEVEL);
5034 return FALSE;
5037 if(pDriverInfo && cbBuf > 0)
5038 memset( pDriverInfo, 0, cbBuf);
5040 /* Exception: pull all printers */
5041 if (pEnvironment && !strcmpW(pEnvironment, allW))
5043 DWORD i, needed, bufsize = cbBuf;
5044 DWORD total_needed = 0;
5045 DWORD total_found = 0;
5046 DWORD data_offset;
5048 /* Precompute the overall total; we need this to know
5049 where pointers end and data begins (i.e. data_offset) */
5050 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5052 needed = found = 0;
5053 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5054 NULL, 0, 0, &needed, &found, 0);
5055 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5056 total_needed += needed;
5057 total_found += found;
5060 data_offset = di_sizeof[Level] * total_found;
5062 *pcReturned = 0;
5063 *pcbNeeded = 0;
5064 total_found = 0;
5065 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5067 needed = found = 0;
5068 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5069 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5070 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5071 else if (ret)
5072 *pcReturned += found;
5073 *pcbNeeded = needed;
5074 data_offset = needed;
5075 total_found += found;
5077 return ret;
5080 /* Normal behavior */
5081 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5082 0, cbBuf, pcbNeeded, &found, 0);
5083 if (ret)
5084 *pcReturned = found;
5086 return ret;
5089 /*****************************************************************************
5090 * EnumPrinterDriversA [WINSPOOL.@]
5092 * see function EnumPrinterDrivers for RETURNS, BUGS
5094 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5095 LPBYTE pDriverInfo, DWORD cbBuf,
5096 LPDWORD pcbNeeded, LPDWORD pcReturned)
5098 BOOL ret;
5099 UNICODE_STRING pNameW, pEnvironmentW;
5100 PWSTR pwstrNameW, pwstrEnvironmentW;
5101 LPBYTE buf = NULL;
5103 if (cbBuf)
5104 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5106 pwstrNameW = asciitounicode(&pNameW, pName);
5107 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5109 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5110 buf, cbBuf, pcbNeeded, pcReturned);
5111 if (ret)
5112 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5114 HeapFree(GetProcessHeap(), 0, buf);
5116 RtlFreeUnicodeString(&pNameW);
5117 RtlFreeUnicodeString(&pEnvironmentW);
5119 return ret;
5122 /******************************************************************************
5123 * EnumPortsA (WINSPOOL.@)
5125 * See EnumPortsW.
5128 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5129 LPDWORD pcbNeeded, LPDWORD pcReturned)
5131 BOOL res;
5132 LPBYTE bufferW = NULL;
5133 LPWSTR nameW = NULL;
5134 DWORD needed = 0;
5135 DWORD numentries = 0;
5136 INT len;
5138 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5139 cbBuf, pcbNeeded, pcReturned);
5141 /* convert servername to unicode */
5142 if (pName) {
5143 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5144 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5145 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5147 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5148 needed = cbBuf * sizeof(WCHAR);
5149 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5150 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5152 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5153 if (pcbNeeded) needed = *pcbNeeded;
5154 /* HeapReAlloc return NULL, when bufferW was NULL */
5155 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5156 HeapAlloc(GetProcessHeap(), 0, needed);
5158 /* Try again with the large Buffer */
5159 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5161 needed = pcbNeeded ? *pcbNeeded : 0;
5162 numentries = pcReturned ? *pcReturned : 0;
5165 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5166 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5168 if (res) {
5169 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5170 DWORD entrysize = 0;
5171 DWORD index;
5172 LPSTR ptr;
5173 LPPORT_INFO_2W pi2w;
5174 LPPORT_INFO_2A pi2a;
5176 needed = 0;
5177 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5179 /* First pass: calculate the size for all Entries */
5180 pi2w = (LPPORT_INFO_2W) bufferW;
5181 pi2a = (LPPORT_INFO_2A) pPorts;
5182 index = 0;
5183 while (index < numentries) {
5184 index++;
5185 needed += entrysize; /* PORT_INFO_?A */
5186 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5188 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5189 NULL, 0, NULL, NULL);
5190 if (Level > 1) {
5191 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5192 NULL, 0, NULL, NULL);
5193 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5194 NULL, 0, NULL, NULL);
5196 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5197 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5198 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5201 /* check for errors and quit on failure */
5202 if (cbBuf < needed) {
5203 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5204 res = FALSE;
5205 goto cleanup;
5207 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5208 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5209 cbBuf -= len ; /* free Bytes in the user-Buffer */
5210 pi2w = (LPPORT_INFO_2W) bufferW;
5211 pi2a = (LPPORT_INFO_2A) pPorts;
5212 index = 0;
5213 /* Second Pass: Fill the User Buffer (if we have one) */
5214 while ((index < numentries) && pPorts) {
5215 index++;
5216 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5217 pi2a->pPortName = ptr;
5218 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5219 ptr, cbBuf , NULL, NULL);
5220 ptr += len;
5221 cbBuf -= len;
5222 if (Level > 1) {
5223 pi2a->pMonitorName = ptr;
5224 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5225 ptr, cbBuf, NULL, NULL);
5226 ptr += len;
5227 cbBuf -= len;
5229 pi2a->pDescription = ptr;
5230 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5231 ptr, cbBuf, NULL, NULL);
5232 ptr += len;
5233 cbBuf -= len;
5235 pi2a->fPortType = pi2w->fPortType;
5236 pi2a->Reserved = 0; /* documented: "must be zero" */
5239 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5240 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5241 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5245 cleanup:
5246 if (pcbNeeded) *pcbNeeded = needed;
5247 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5249 HeapFree(GetProcessHeap(), 0, nameW);
5250 HeapFree(GetProcessHeap(), 0, bufferW);
5252 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5253 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5255 return (res);
5259 /******************************************************************************
5260 * EnumPortsW (WINSPOOL.@)
5262 * Enumerate available Ports
5264 * PARAMS
5265 * pName [I] Servername or NULL (local Computer)
5266 * Level [I] Structure-Level (1 or 2)
5267 * pPorts [O] PTR to Buffer that receives the Result
5268 * cbBuf [I] Size of Buffer at pPorts
5269 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5270 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5272 * RETURNS
5273 * Success: TRUE
5274 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5277 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5280 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5281 cbBuf, pcbNeeded, pcReturned);
5283 if ((backend == NULL) && !load_backend()) return FALSE;
5285 /* Level is not checked in win9x */
5286 if (!Level || (Level > 2)) {
5287 WARN("level (%d) is ignored in win9x\n", Level);
5288 SetLastError(ERROR_INVALID_LEVEL);
5289 return FALSE;
5291 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5292 SetLastError(RPC_X_NULL_REF_POINTER);
5293 return FALSE;
5296 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5299 /******************************************************************************
5300 * GetDefaultPrinterW (WINSPOOL.@)
5302 * FIXME
5303 * This function must read the value from data 'device' of key
5304 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5306 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5308 BOOL retval = TRUE;
5309 DWORD insize, len;
5310 WCHAR *buffer, *ptr;
5312 if (!namesize)
5314 SetLastError(ERROR_INVALID_PARAMETER);
5315 return FALSE;
5318 /* make the buffer big enough for the stuff from the profile/registry,
5319 * the content must fit into the local buffer to compute the correct
5320 * size even if the extern buffer is too small or not given.
5321 * (20 for ,driver,port) */
5322 insize = *namesize;
5323 len = max(100, (insize + 20));
5324 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5326 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5328 SetLastError (ERROR_FILE_NOT_FOUND);
5329 retval = FALSE;
5330 goto end;
5332 TRACE("%s\n", debugstr_w(buffer));
5334 if ((ptr = strchrW(buffer, ',')) == NULL)
5336 SetLastError(ERROR_INVALID_NAME);
5337 retval = FALSE;
5338 goto end;
5341 *ptr = 0;
5342 *namesize = strlenW(buffer) + 1;
5343 if(!name || (*namesize > insize))
5345 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5346 retval = FALSE;
5347 goto end;
5349 strcpyW(name, buffer);
5351 end:
5352 HeapFree( GetProcessHeap(), 0, buffer);
5353 return retval;
5357 /******************************************************************************
5358 * GetDefaultPrinterA (WINSPOOL.@)
5360 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5362 BOOL retval = TRUE;
5363 DWORD insize = 0;
5364 WCHAR *bufferW = NULL;
5366 if (!namesize)
5368 SetLastError(ERROR_INVALID_PARAMETER);
5369 return FALSE;
5372 if(name && *namesize) {
5373 insize = *namesize;
5374 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5377 if(!GetDefaultPrinterW( bufferW, namesize)) {
5378 retval = FALSE;
5379 goto end;
5382 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5383 NULL, NULL);
5384 if (!*namesize)
5386 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5387 retval = FALSE;
5389 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5391 end:
5392 HeapFree( GetProcessHeap(), 0, bufferW);
5393 return retval;
5397 /******************************************************************************
5398 * SetDefaultPrinterW (WINSPOOL.204)
5400 * Set the Name of the Default Printer
5402 * PARAMS
5403 * pszPrinter [I] Name of the Printer or NULL
5405 * RETURNS
5406 * Success: True
5407 * Failure: FALSE
5409 * NOTES
5410 * When the Parameter is NULL or points to an Empty String and
5411 * a Default Printer was already present, then this Function changes nothing.
5412 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5413 * the First enumerated local Printer is used.
5416 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5418 WCHAR default_printer[MAX_PATH];
5419 LPWSTR buffer = NULL;
5420 HKEY hreg;
5421 DWORD size;
5422 DWORD namelen;
5423 LONG lres;
5425 TRACE("(%s)\n", debugstr_w(pszPrinter));
5426 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5428 default_printer[0] = '\0';
5429 size = sizeof(default_printer)/sizeof(WCHAR);
5431 /* if we have a default Printer, do nothing. */
5432 if (GetDefaultPrinterW(default_printer, &size))
5433 return TRUE;
5435 pszPrinter = NULL;
5436 /* we have no default Printer: search local Printers and use the first */
5437 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5439 default_printer[0] = '\0';
5440 size = sizeof(default_printer)/sizeof(WCHAR);
5441 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5443 pszPrinter = default_printer;
5444 TRACE("using %s\n", debugstr_w(pszPrinter));
5446 RegCloseKey(hreg);
5449 if (pszPrinter == NULL) {
5450 TRACE("no local printer found\n");
5451 SetLastError(ERROR_FILE_NOT_FOUND);
5452 return FALSE;
5456 /* "pszPrinter" is never empty or NULL here. */
5457 namelen = lstrlenW(pszPrinter);
5458 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5459 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5460 if (!buffer ||
5461 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5462 HeapFree(GetProcessHeap(), 0, buffer);
5463 SetLastError(ERROR_FILE_NOT_FOUND);
5464 return FALSE;
5467 /* read the devices entry for the printer (driver,port) to build the string for the
5468 default device entry (printer,driver,port) */
5469 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5470 buffer[namelen] = ',';
5471 namelen++; /* move index to the start of the driver */
5473 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5474 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5475 if (!lres) {
5476 TRACE("set device to %s\n", debugstr_w(buffer));
5478 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5479 TRACE("failed to set the device entry: %d\n", GetLastError());
5480 lres = ERROR_INVALID_PRINTER_NAME;
5483 /* remove the next section, when INIFileMapping is implemented */
5485 HKEY hdev;
5486 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5487 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5488 RegCloseKey(hdev);
5492 else
5494 if (lres != ERROR_FILE_NOT_FOUND)
5495 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5497 SetLastError(ERROR_INVALID_PRINTER_NAME);
5500 RegCloseKey(hreg);
5501 HeapFree(GetProcessHeap(), 0, buffer);
5502 return (lres == ERROR_SUCCESS);
5505 /******************************************************************************
5506 * SetDefaultPrinterA (WINSPOOL.202)
5508 * See SetDefaultPrinterW.
5511 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5513 LPWSTR bufferW = NULL;
5514 BOOL res;
5516 TRACE("(%s)\n", debugstr_a(pszPrinter));
5517 if(pszPrinter) {
5518 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5519 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5520 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5522 res = SetDefaultPrinterW(bufferW);
5523 HeapFree(GetProcessHeap(), 0, bufferW);
5524 return res;
5527 /******************************************************************************
5528 * SetPrinterDataExA (WINSPOOL.@)
5530 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5531 LPCSTR pValueName, DWORD Type,
5532 LPBYTE pData, DWORD cbData)
5534 HKEY hkeyPrinter, hkeySubkey;
5535 DWORD ret;
5537 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5538 debugstr_a(pValueName), Type, pData, cbData);
5540 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5541 != ERROR_SUCCESS)
5542 return ret;
5544 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5545 != ERROR_SUCCESS) {
5546 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5547 RegCloseKey(hkeyPrinter);
5548 return ret;
5550 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5551 RegCloseKey(hkeySubkey);
5552 RegCloseKey(hkeyPrinter);
5553 return ret;
5556 /******************************************************************************
5557 * SetPrinterDataExW (WINSPOOL.@)
5559 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5560 LPCWSTR pValueName, DWORD Type,
5561 LPBYTE pData, DWORD cbData)
5563 HKEY hkeyPrinter, hkeySubkey;
5564 DWORD ret;
5566 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5567 debugstr_w(pValueName), Type, pData, cbData);
5569 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5570 != ERROR_SUCCESS)
5571 return ret;
5573 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5574 != ERROR_SUCCESS) {
5575 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5576 RegCloseKey(hkeyPrinter);
5577 return ret;
5579 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5580 RegCloseKey(hkeySubkey);
5581 RegCloseKey(hkeyPrinter);
5582 return ret;
5585 /******************************************************************************
5586 * SetPrinterDataA (WINSPOOL.@)
5588 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5589 LPBYTE pData, DWORD cbData)
5591 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5592 pData, cbData);
5595 /******************************************************************************
5596 * SetPrinterDataW (WINSPOOL.@)
5598 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5599 LPBYTE pData, DWORD cbData)
5601 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5602 pData, cbData);
5605 /******************************************************************************
5606 * GetPrinterDataExA (WINSPOOL.@)
5608 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5609 LPCSTR pValueName, LPDWORD pType,
5610 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5612 opened_printer_t *printer;
5613 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5614 DWORD ret;
5616 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5617 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5619 printer = get_opened_printer(hPrinter);
5620 if(!printer) return ERROR_INVALID_HANDLE;
5622 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5623 if (ret) return ret;
5625 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5627 if (printer->name) {
5629 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5630 if (ret) {
5631 RegCloseKey(hkeyPrinters);
5632 return ret;
5634 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5635 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5636 RegCloseKey(hkeyPrinter);
5637 RegCloseKey(hkeyPrinters);
5638 return ret;
5641 *pcbNeeded = nSize;
5642 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5643 0, pType, pData, pcbNeeded);
5645 if (!ret && !pData) ret = ERROR_MORE_DATA;
5647 RegCloseKey(hkeySubkey);
5648 RegCloseKey(hkeyPrinter);
5649 RegCloseKey(hkeyPrinters);
5651 TRACE("--> %d\n", ret);
5652 return ret;
5655 /******************************************************************************
5656 * GetPrinterDataExW (WINSPOOL.@)
5658 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5659 LPCWSTR pValueName, LPDWORD pType,
5660 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5662 opened_printer_t *printer;
5663 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5664 DWORD ret;
5666 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5667 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5669 printer = get_opened_printer(hPrinter);
5670 if(!printer) return ERROR_INVALID_HANDLE;
5672 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5673 if (ret) return ret;
5675 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5677 if (printer->name) {
5679 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5680 if (ret) {
5681 RegCloseKey(hkeyPrinters);
5682 return ret;
5684 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5685 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5686 RegCloseKey(hkeyPrinter);
5687 RegCloseKey(hkeyPrinters);
5688 return ret;
5691 *pcbNeeded = nSize;
5692 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5693 0, pType, pData, pcbNeeded);
5695 if (!ret && !pData) ret = ERROR_MORE_DATA;
5697 RegCloseKey(hkeySubkey);
5698 RegCloseKey(hkeyPrinter);
5699 RegCloseKey(hkeyPrinters);
5701 TRACE("--> %d\n", ret);
5702 return ret;
5705 /******************************************************************************
5706 * GetPrinterDataA (WINSPOOL.@)
5708 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5709 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5711 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5712 pData, nSize, pcbNeeded);
5715 /******************************************************************************
5716 * GetPrinterDataW (WINSPOOL.@)
5718 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5719 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5721 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5722 pData, nSize, pcbNeeded);
5725 /*******************************************************************************
5726 * EnumPrinterDataExW [WINSPOOL.@]
5728 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5729 LPBYTE pEnumValues, DWORD cbEnumValues,
5730 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5732 HKEY hkPrinter, hkSubKey;
5733 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5734 cbValueNameLen, cbMaxValueLen, cbValueLen,
5735 cbBufSize, dwType;
5736 LPWSTR lpValueName;
5737 HANDLE hHeap;
5738 PBYTE lpValue;
5739 PPRINTER_ENUM_VALUESW ppev;
5741 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5743 if (pKeyName == NULL || *pKeyName == 0)
5744 return ERROR_INVALID_PARAMETER;
5746 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5747 if (ret != ERROR_SUCCESS)
5749 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5750 hPrinter, ret);
5751 return ret;
5754 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5755 if (ret != ERROR_SUCCESS)
5757 r = RegCloseKey (hkPrinter);
5758 if (r != ERROR_SUCCESS)
5759 WARN ("RegCloseKey returned %i\n", r);
5760 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5761 debugstr_w (pKeyName), ret);
5762 return ret;
5765 ret = RegCloseKey (hkPrinter);
5766 if (ret != ERROR_SUCCESS)
5768 ERR ("RegCloseKey returned %i\n", ret);
5769 r = RegCloseKey (hkSubKey);
5770 if (r != ERROR_SUCCESS)
5771 WARN ("RegCloseKey returned %i\n", r);
5772 return ret;
5775 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5776 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5777 if (ret != ERROR_SUCCESS)
5779 r = RegCloseKey (hkSubKey);
5780 if (r != ERROR_SUCCESS)
5781 WARN ("RegCloseKey returned %i\n", r);
5782 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5783 return ret;
5786 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5787 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5789 if (cValues == 0) /* empty key */
5791 r = RegCloseKey (hkSubKey);
5792 if (r != ERROR_SUCCESS)
5793 WARN ("RegCloseKey returned %i\n", r);
5794 *pcbEnumValues = *pnEnumValues = 0;
5795 return ERROR_SUCCESS;
5798 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5800 hHeap = GetProcessHeap ();
5801 if (hHeap == NULL)
5803 ERR ("GetProcessHeap failed\n");
5804 r = RegCloseKey (hkSubKey);
5805 if (r != ERROR_SUCCESS)
5806 WARN ("RegCloseKey returned %i\n", r);
5807 return ERROR_OUTOFMEMORY;
5810 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5811 if (lpValueName == NULL)
5813 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5814 r = RegCloseKey (hkSubKey);
5815 if (r != ERROR_SUCCESS)
5816 WARN ("RegCloseKey returned %i\n", r);
5817 return ERROR_OUTOFMEMORY;
5820 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5821 if (lpValue == NULL)
5823 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5824 if (HeapFree (hHeap, 0, lpValueName) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5826 r = RegCloseKey (hkSubKey);
5827 if (r != ERROR_SUCCESS)
5828 WARN ("RegCloseKey returned %i\n", r);
5829 return ERROR_OUTOFMEMORY;
5832 TRACE ("pass 1: calculating buffer required for all names and values\n");
5834 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5836 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5838 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5840 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5841 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5842 NULL, NULL, lpValue, &cbValueLen);
5843 if (ret != ERROR_SUCCESS)
5845 if (HeapFree (hHeap, 0, lpValue) == 0)
5846 WARN ("HeapFree failed with code %i\n", GetLastError ());
5847 if (HeapFree (hHeap, 0, lpValueName) == 0)
5848 WARN ("HeapFree failed with code %i\n", GetLastError ());
5849 r = RegCloseKey (hkSubKey);
5850 if (r != ERROR_SUCCESS)
5851 WARN ("RegCloseKey returned %i\n", r);
5852 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5853 return ret;
5856 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5857 debugstr_w (lpValueName), dwIndex,
5858 cbValueNameLen + 1, cbValueLen);
5860 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5861 cbBufSize += cbValueLen;
5864 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5866 *pcbEnumValues = cbBufSize;
5867 *pnEnumValues = cValues;
5869 if (cbEnumValues < cbBufSize) /* buffer too small */
5871 if (HeapFree (hHeap, 0, lpValue) == 0)
5872 WARN ("HeapFree failed with code %i\n", GetLastError ());
5873 if (HeapFree (hHeap, 0, lpValueName) == 0)
5874 WARN ("HeapFree failed with code %i\n", GetLastError ());
5875 r = RegCloseKey (hkSubKey);
5876 if (r != ERROR_SUCCESS)
5877 WARN ("RegCloseKey returned %i\n", r);
5878 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5879 return ERROR_MORE_DATA;
5882 TRACE ("pass 2: copying all names and values to buffer\n");
5884 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5885 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5887 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5889 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5890 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5891 NULL, &dwType, lpValue, &cbValueLen);
5892 if (ret != ERROR_SUCCESS)
5894 if (HeapFree (hHeap, 0, lpValue) == 0)
5895 WARN ("HeapFree failed with code %i\n", GetLastError ());
5896 if (HeapFree (hHeap, 0, lpValueName) == 0)
5897 WARN ("HeapFree failed with code %i\n", GetLastError ());
5898 r = RegCloseKey (hkSubKey);
5899 if (r != ERROR_SUCCESS)
5900 WARN ("RegCloseKey returned %i\n", r);
5901 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5902 return ret;
5905 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5906 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5907 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5908 pEnumValues += cbValueNameLen;
5910 /* return # of *bytes* (including trailing \0), not # of chars */
5911 ppev[dwIndex].cbValueName = cbValueNameLen;
5913 ppev[dwIndex].dwType = dwType;
5915 memcpy (pEnumValues, lpValue, cbValueLen);
5916 ppev[dwIndex].pData = pEnumValues;
5917 pEnumValues += cbValueLen;
5919 ppev[dwIndex].cbData = cbValueLen;
5921 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5922 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5925 if (HeapFree (hHeap, 0, lpValue) == 0)
5927 ret = GetLastError ();
5928 ERR ("HeapFree failed with code %i\n", ret);
5929 if (HeapFree (hHeap, 0, lpValueName) == 0)
5930 WARN ("HeapFree failed with code %i\n", GetLastError ());
5931 r = RegCloseKey (hkSubKey);
5932 if (r != ERROR_SUCCESS)
5933 WARN ("RegCloseKey returned %i\n", r);
5934 return ret;
5937 if (HeapFree (hHeap, 0, lpValueName) == 0)
5939 ret = GetLastError ();
5940 ERR ("HeapFree failed with code %i\n", ret);
5941 r = RegCloseKey (hkSubKey);
5942 if (r != ERROR_SUCCESS)
5943 WARN ("RegCloseKey returned %i\n", r);
5944 return ret;
5947 ret = RegCloseKey (hkSubKey);
5948 if (ret != ERROR_SUCCESS)
5950 ERR ("RegCloseKey returned %i\n", ret);
5951 return ret;
5954 return ERROR_SUCCESS;
5957 /*******************************************************************************
5958 * EnumPrinterDataExA [WINSPOOL.@]
5960 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5961 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5962 * what Windows 2000 SP1 does.
5965 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5966 LPBYTE pEnumValues, DWORD cbEnumValues,
5967 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5969 INT len;
5970 LPWSTR pKeyNameW;
5971 DWORD ret, dwIndex, dwBufSize;
5972 HANDLE hHeap;
5973 LPSTR pBuffer;
5975 TRACE ("%p %s\n", hPrinter, pKeyName);
5977 if (pKeyName == NULL || *pKeyName == 0)
5978 return ERROR_INVALID_PARAMETER;
5980 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5981 if (len == 0)
5983 ret = GetLastError ();
5984 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5985 return ret;
5988 hHeap = GetProcessHeap ();
5989 if (hHeap == NULL)
5991 ERR ("GetProcessHeap failed\n");
5992 return ERROR_OUTOFMEMORY;
5995 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5996 if (pKeyNameW == NULL)
5998 ERR ("Failed to allocate %i bytes from process heap\n",
5999 (LONG)(len * sizeof (WCHAR)));
6000 return ERROR_OUTOFMEMORY;
6003 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6005 ret = GetLastError ();
6006 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6007 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6008 WARN ("HeapFree failed with code %i\n", GetLastError ());
6009 return ret;
6012 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6013 pcbEnumValues, pnEnumValues);
6014 if (ret != ERROR_SUCCESS)
6016 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6017 WARN ("HeapFree failed with code %i\n", GetLastError ());
6018 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6019 return ret;
6022 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6024 ret = GetLastError ();
6025 ERR ("HeapFree failed with code %i\n", ret);
6026 return ret;
6029 if (*pnEnumValues == 0) /* empty key */
6030 return ERROR_SUCCESS;
6032 dwBufSize = 0;
6033 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6035 PPRINTER_ENUM_VALUESW ppev =
6036 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6038 if (dwBufSize < ppev->cbValueName)
6039 dwBufSize = ppev->cbValueName;
6041 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6042 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6043 dwBufSize = ppev->cbData;
6046 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6048 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6049 if (pBuffer == NULL)
6051 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6052 return ERROR_OUTOFMEMORY;
6055 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6057 PPRINTER_ENUM_VALUESW ppev =
6058 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6060 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6061 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6062 NULL);
6063 if (len == 0)
6065 ret = GetLastError ();
6066 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6067 if (HeapFree (hHeap, 0, pBuffer) == 0)
6068 WARN ("HeapFree failed with code %i\n", GetLastError ());
6069 return ret;
6072 memcpy (ppev->pValueName, pBuffer, len);
6074 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6076 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6077 ppev->dwType != REG_MULTI_SZ)
6078 continue;
6080 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6081 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6082 if (len == 0)
6084 ret = GetLastError ();
6085 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6086 if (HeapFree (hHeap, 0, pBuffer) == 0)
6087 WARN ("HeapFree failed with code %i\n", GetLastError ());
6088 return ret;
6091 memcpy (ppev->pData, pBuffer, len);
6093 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6094 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6097 if (HeapFree (hHeap, 0, pBuffer) == 0)
6099 ret = GetLastError ();
6100 ERR ("HeapFree failed with code %i\n", ret);
6101 return ret;
6104 return ERROR_SUCCESS;
6107 /******************************************************************************
6108 * AbortPrinter (WINSPOOL.@)
6110 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6112 FIXME("(%p), stub!\n", hPrinter);
6113 return TRUE;
6116 /******************************************************************************
6117 * AddPortA (WINSPOOL.@)
6119 * See AddPortW.
6122 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6124 LPWSTR nameW = NULL;
6125 LPWSTR monitorW = NULL;
6126 DWORD len;
6127 BOOL res;
6129 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6131 if (pName) {
6132 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6133 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6134 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6137 if (pMonitorName) {
6138 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6139 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6140 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6142 res = AddPortW(nameW, hWnd, monitorW);
6143 HeapFree(GetProcessHeap(), 0, nameW);
6144 HeapFree(GetProcessHeap(), 0, monitorW);
6145 return res;
6148 /******************************************************************************
6149 * AddPortW (WINSPOOL.@)
6151 * Add a Port for a specific Monitor
6153 * PARAMS
6154 * pName [I] Servername or NULL (local Computer)
6155 * hWnd [I] Handle to parent Window for the Dialog-Box
6156 * pMonitorName [I] Name of the Monitor that manage the Port
6158 * RETURNS
6159 * Success: TRUE
6160 * Failure: FALSE
6163 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6165 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6167 if ((backend == NULL) && !load_backend()) return FALSE;
6169 if (!pMonitorName) {
6170 SetLastError(RPC_X_NULL_REF_POINTER);
6171 return FALSE;
6174 return backend->fpAddPort(pName, hWnd, pMonitorName);
6177 /******************************************************************************
6178 * AddPortExA (WINSPOOL.@)
6180 * See AddPortExW.
6183 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6185 PORT_INFO_2W pi2W;
6186 PORT_INFO_2A * pi2A;
6187 LPWSTR nameW = NULL;
6188 LPWSTR monitorW = NULL;
6189 DWORD len;
6190 BOOL res;
6192 pi2A = (PORT_INFO_2A *) pBuffer;
6194 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6195 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6197 if ((level < 1) || (level > 2)) {
6198 SetLastError(ERROR_INVALID_LEVEL);
6199 return FALSE;
6202 if (!pi2A) {
6203 SetLastError(ERROR_INVALID_PARAMETER);
6204 return FALSE;
6207 if (pName) {
6208 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6209 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6210 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6213 if (pMonitorName) {
6214 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6215 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6216 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6219 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6221 if (pi2A->pPortName) {
6222 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6223 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6224 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6227 if (level > 1) {
6228 if (pi2A->pMonitorName) {
6229 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6230 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6231 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6234 if (pi2A->pDescription) {
6235 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6236 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6237 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6239 pi2W.fPortType = pi2A->fPortType;
6240 pi2W.Reserved = pi2A->Reserved;
6243 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6245 HeapFree(GetProcessHeap(), 0, nameW);
6246 HeapFree(GetProcessHeap(), 0, monitorW);
6247 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6248 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6249 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6250 return res;
6254 /******************************************************************************
6255 * AddPortExW (WINSPOOL.@)
6257 * Add a Port for a specific Monitor, without presenting a user interface
6259 * PARAMS
6260 * pName [I] Servername or NULL (local Computer)
6261 * level [I] Structure-Level (1 or 2) for pBuffer
6262 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6263 * pMonitorName [I] Name of the Monitor that manage the Port
6265 * RETURNS
6266 * Success: TRUE
6267 * Failure: FALSE
6270 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6272 PORT_INFO_2W * pi2;
6274 pi2 = (PORT_INFO_2W *) pBuffer;
6276 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6277 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6278 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6279 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6281 if ((backend == NULL) && !load_backend()) return FALSE;
6283 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6284 SetLastError(ERROR_INVALID_PARAMETER);
6285 return FALSE;
6288 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6291 /******************************************************************************
6292 * AddPrinterConnectionA (WINSPOOL.@)
6294 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6296 FIXME("%s\n", debugstr_a(pName));
6297 return FALSE;
6300 /******************************************************************************
6301 * AddPrinterConnectionW (WINSPOOL.@)
6303 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6305 FIXME("%s\n", debugstr_w(pName));
6306 return FALSE;
6309 /******************************************************************************
6310 * AddPrinterDriverExW (WINSPOOL.@)
6312 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6314 * PARAMS
6315 * pName [I] Servername or NULL (local Computer)
6316 * level [I] Level for the supplied DRIVER_INFO_*W struct
6317 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6318 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6320 * RESULTS
6321 * Success: TRUE
6322 * Failure: FALSE
6325 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6327 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6329 if ((backend == NULL) && !load_backend()) return FALSE;
6331 if (level < 2 || level == 5 || level == 7 || level > 8) {
6332 SetLastError(ERROR_INVALID_LEVEL);
6333 return FALSE;
6336 if (!pDriverInfo) {
6337 SetLastError(ERROR_INVALID_PARAMETER);
6338 return FALSE;
6341 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6344 /******************************************************************************
6345 * AddPrinterDriverExA (WINSPOOL.@)
6347 * See AddPrinterDriverExW.
6350 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6352 DRIVER_INFO_8A *diA;
6353 DRIVER_INFO_8W diW;
6354 LPWSTR nameW = NULL;
6355 DWORD lenA;
6356 DWORD len;
6357 DWORD res = FALSE;
6359 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6361 diA = (DRIVER_INFO_8A *) pDriverInfo;
6362 ZeroMemory(&diW, sizeof(diW));
6364 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6365 SetLastError(ERROR_INVALID_LEVEL);
6366 return FALSE;
6369 if (diA == NULL) {
6370 SetLastError(ERROR_INVALID_PARAMETER);
6371 return FALSE;
6374 /* convert servername to unicode */
6375 if (pName) {
6376 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6377 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6378 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6381 /* common fields */
6382 diW.cVersion = diA->cVersion;
6384 if (diA->pName) {
6385 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6386 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6387 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6390 if (diA->pEnvironment) {
6391 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6392 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6393 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6396 if (diA->pDriverPath) {
6397 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6398 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6399 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6402 if (diA->pDataFile) {
6403 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6404 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6405 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6408 if (diA->pConfigFile) {
6409 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6410 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6411 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6414 if ((Level > 2) && diA->pDependentFiles) {
6415 lenA = multi_sz_lenA(diA->pDependentFiles);
6416 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6417 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6418 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6421 if ((Level > 2) && diA->pMonitorName) {
6422 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6423 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6424 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6427 if ((Level > 3) && diA->pDefaultDataType) {
6428 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6429 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6430 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6433 if ((Level > 3) && diA->pszzPreviousNames) {
6434 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6435 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6436 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6437 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6440 if ((Level > 5) && diA->pszMfgName) {
6441 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6442 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6443 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6446 if ((Level > 5) && diA->pszOEMUrl) {
6447 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6448 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6449 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6452 if ((Level > 5) && diA->pszHardwareID) {
6453 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6454 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6455 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6458 if ((Level > 5) && diA->pszProvider) {
6459 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6460 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6461 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6464 if (Level > 7) {
6465 FIXME("level %u is incomplete\n", Level);
6468 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6469 TRACE("got %u with %u\n", res, GetLastError());
6470 HeapFree(GetProcessHeap(), 0, nameW);
6471 HeapFree(GetProcessHeap(), 0, diW.pName);
6472 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6473 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6474 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6475 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6476 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6477 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6478 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6479 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6480 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6481 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6482 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6483 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6485 TRACE("=> %u with %u\n", res, GetLastError());
6486 return res;
6489 /******************************************************************************
6490 * ConfigurePortA (WINSPOOL.@)
6492 * See ConfigurePortW.
6495 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6497 LPWSTR nameW = NULL;
6498 LPWSTR portW = NULL;
6499 INT len;
6500 DWORD res;
6502 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6504 /* convert servername to unicode */
6505 if (pName) {
6506 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6507 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6508 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6511 /* convert portname to unicode */
6512 if (pPortName) {
6513 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6514 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6515 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6518 res = ConfigurePortW(nameW, hWnd, portW);
6519 HeapFree(GetProcessHeap(), 0, nameW);
6520 HeapFree(GetProcessHeap(), 0, portW);
6521 return res;
6524 /******************************************************************************
6525 * ConfigurePortW (WINSPOOL.@)
6527 * Display the Configuration-Dialog for a specific Port
6529 * PARAMS
6530 * pName [I] Servername or NULL (local Computer)
6531 * hWnd [I] Handle to parent Window for the Dialog-Box
6532 * pPortName [I] Name of the Port, that should be configured
6534 * RETURNS
6535 * Success: TRUE
6536 * Failure: FALSE
6539 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6542 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6544 if ((backend == NULL) && !load_backend()) return FALSE;
6546 if (!pPortName) {
6547 SetLastError(RPC_X_NULL_REF_POINTER);
6548 return FALSE;
6551 return backend->fpConfigurePort(pName, hWnd, pPortName);
6554 /******************************************************************************
6555 * ConnectToPrinterDlg (WINSPOOL.@)
6557 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6559 FIXME("%p %x\n", hWnd, Flags);
6560 return NULL;
6563 /******************************************************************************
6564 * DeletePrinterConnectionA (WINSPOOL.@)
6566 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6568 FIXME("%s\n", debugstr_a(pName));
6569 return TRUE;
6572 /******************************************************************************
6573 * DeletePrinterConnectionW (WINSPOOL.@)
6575 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6577 FIXME("%s\n", debugstr_w(pName));
6578 return TRUE;
6581 /******************************************************************************
6582 * DeletePrinterDriverExW (WINSPOOL.@)
6584 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6585 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6587 HKEY hkey_drivers;
6588 BOOL ret = FALSE;
6590 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6591 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6593 if(pName && pName[0])
6595 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6596 SetLastError(ERROR_INVALID_PARAMETER);
6597 return FALSE;
6600 if(dwDeleteFlag)
6602 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6603 SetLastError(ERROR_INVALID_PARAMETER);
6604 return FALSE;
6607 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6609 if(!hkey_drivers)
6611 ERR("Can't open drivers key\n");
6612 return FALSE;
6615 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6616 ret = TRUE;
6618 RegCloseKey(hkey_drivers);
6620 return ret;
6623 /******************************************************************************
6624 * DeletePrinterDriverExA (WINSPOOL.@)
6626 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6627 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6629 UNICODE_STRING NameW, EnvW, DriverW;
6630 BOOL ret;
6632 asciitounicode(&NameW, pName);
6633 asciitounicode(&EnvW, pEnvironment);
6634 asciitounicode(&DriverW, pDriverName);
6636 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6638 RtlFreeUnicodeString(&DriverW);
6639 RtlFreeUnicodeString(&EnvW);
6640 RtlFreeUnicodeString(&NameW);
6642 return ret;
6645 /******************************************************************************
6646 * DeletePrinterDataExW (WINSPOOL.@)
6648 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6649 LPCWSTR pValueName)
6651 FIXME("%p %s %s\n", hPrinter,
6652 debugstr_w(pKeyName), debugstr_w(pValueName));
6653 return ERROR_INVALID_PARAMETER;
6656 /******************************************************************************
6657 * DeletePrinterDataExA (WINSPOOL.@)
6659 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6660 LPCSTR pValueName)
6662 FIXME("%p %s %s\n", hPrinter,
6663 debugstr_a(pKeyName), debugstr_a(pValueName));
6664 return ERROR_INVALID_PARAMETER;
6667 /******************************************************************************
6668 * DeletePrintProcessorA (WINSPOOL.@)
6670 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6672 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6673 debugstr_a(pPrintProcessorName));
6674 return TRUE;
6677 /******************************************************************************
6678 * DeletePrintProcessorW (WINSPOOL.@)
6680 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6682 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6683 debugstr_w(pPrintProcessorName));
6684 return TRUE;
6687 /******************************************************************************
6688 * DeletePrintProvidorA (WINSPOOL.@)
6690 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6692 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6693 debugstr_a(pPrintProviderName));
6694 return TRUE;
6697 /******************************************************************************
6698 * DeletePrintProvidorW (WINSPOOL.@)
6700 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6702 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6703 debugstr_w(pPrintProviderName));
6704 return TRUE;
6707 /******************************************************************************
6708 * EnumFormsA (WINSPOOL.@)
6710 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6711 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6713 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6714 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6715 return FALSE;
6718 /******************************************************************************
6719 * EnumFormsW (WINSPOOL.@)
6721 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6722 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6724 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6725 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6726 return FALSE;
6729 /*****************************************************************************
6730 * EnumMonitorsA [WINSPOOL.@]
6732 * See EnumMonitorsW.
6735 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6736 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6738 BOOL res;
6739 LPBYTE bufferW = NULL;
6740 LPWSTR nameW = NULL;
6741 DWORD needed = 0;
6742 DWORD numentries = 0;
6743 INT len;
6745 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6746 cbBuf, pcbNeeded, pcReturned);
6748 /* convert servername to unicode */
6749 if (pName) {
6750 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6751 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6754 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6755 needed = cbBuf * sizeof(WCHAR);
6756 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6757 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6759 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6760 if (pcbNeeded) needed = *pcbNeeded;
6761 /* HeapReAlloc return NULL, when bufferW was NULL */
6762 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6763 HeapAlloc(GetProcessHeap(), 0, needed);
6765 /* Try again with the large Buffer */
6766 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6768 numentries = pcReturned ? *pcReturned : 0;
6769 needed = 0;
6771 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6772 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6774 if (res) {
6775 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6776 DWORD entrysize = 0;
6777 DWORD index;
6778 LPSTR ptr;
6779 LPMONITOR_INFO_2W mi2w;
6780 LPMONITOR_INFO_2A mi2a;
6782 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6783 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6785 /* First pass: calculate the size for all Entries */
6786 mi2w = (LPMONITOR_INFO_2W) bufferW;
6787 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6788 index = 0;
6789 while (index < numentries) {
6790 index++;
6791 needed += entrysize; /* MONITOR_INFO_?A */
6792 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6794 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6795 NULL, 0, NULL, NULL);
6796 if (Level > 1) {
6797 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6798 NULL, 0, NULL, NULL);
6799 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6800 NULL, 0, NULL, NULL);
6802 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6803 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6804 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6807 /* check for errors and quit on failure */
6808 if (cbBuf < needed) {
6809 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6810 res = FALSE;
6811 goto emA_cleanup;
6813 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6814 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6815 cbBuf -= len ; /* free Bytes in the user-Buffer */
6816 mi2w = (LPMONITOR_INFO_2W) bufferW;
6817 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6818 index = 0;
6819 /* Second Pass: Fill the User Buffer (if we have one) */
6820 while ((index < numentries) && pMonitors) {
6821 index++;
6822 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6823 mi2a->pName = ptr;
6824 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6825 ptr, cbBuf , NULL, NULL);
6826 ptr += len;
6827 cbBuf -= len;
6828 if (Level > 1) {
6829 mi2a->pEnvironment = ptr;
6830 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6831 ptr, cbBuf, NULL, NULL);
6832 ptr += len;
6833 cbBuf -= len;
6835 mi2a->pDLLName = ptr;
6836 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6837 ptr, cbBuf, NULL, NULL);
6838 ptr += len;
6839 cbBuf -= len;
6841 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6842 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6843 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6846 emA_cleanup:
6847 if (pcbNeeded) *pcbNeeded = needed;
6848 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6850 HeapFree(GetProcessHeap(), 0, nameW);
6851 HeapFree(GetProcessHeap(), 0, bufferW);
6853 TRACE("returning %d with %d (%d byte for %d entries)\n",
6854 (res), GetLastError(), needed, numentries);
6856 return (res);
6860 /*****************************************************************************
6861 * EnumMonitorsW [WINSPOOL.@]
6863 * Enumerate available Port-Monitors
6865 * PARAMS
6866 * pName [I] Servername or NULL (local Computer)
6867 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6868 * pMonitors [O] PTR to Buffer that receives the Result
6869 * cbBuf [I] Size of Buffer at pMonitors
6870 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6871 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6873 * RETURNS
6874 * Success: TRUE
6875 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6878 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6879 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6882 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6883 cbBuf, pcbNeeded, pcReturned);
6885 if ((backend == NULL) && !load_backend()) return FALSE;
6887 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6888 SetLastError(RPC_X_NULL_REF_POINTER);
6889 return FALSE;
6892 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6895 /******************************************************************************
6896 * SpoolerInit (WINSPOOL.@)
6898 * Initialize the Spooler
6900 * RETURNS
6901 * Success: TRUE
6902 * Failure: FALSE
6904 * NOTES
6905 * The function fails on windows, when the spooler service is not running
6908 BOOL WINAPI SpoolerInit(void)
6911 if ((backend == NULL) && !load_backend()) return FALSE;
6912 return TRUE;
6915 /******************************************************************************
6916 * XcvDataW (WINSPOOL.@)
6918 * Execute commands in the Printmonitor DLL
6920 * PARAMS
6921 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6922 * pszDataName [i] Name of the command to execute
6923 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6924 * cbInputData [i] Size in Bytes of Buffer at pInputData
6925 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6926 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6927 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6928 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6930 * RETURNS
6931 * Success: TRUE
6932 * Failure: FALSE
6934 * NOTES
6935 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6936 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6938 * Minimal List of commands, that a Printmonitor DLL should support:
6940 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6941 *| "AddPort" : Add a Port
6942 *| "DeletePort": Delete a Port
6944 * Many Printmonitors support additional commands. Examples for localspl.dll:
6945 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6946 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6949 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6950 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6951 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6953 opened_printer_t *printer;
6955 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6956 pInputData, cbInputData, pOutputData,
6957 cbOutputData, pcbOutputNeeded, pdwStatus);
6959 if ((backend == NULL) && !load_backend()) return FALSE;
6961 printer = get_opened_printer(hXcv);
6962 if (!printer || (!printer->backend_printer)) {
6963 SetLastError(ERROR_INVALID_HANDLE);
6964 return FALSE;
6967 if (!pcbOutputNeeded) {
6968 SetLastError(ERROR_INVALID_PARAMETER);
6969 return FALSE;
6972 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6973 SetLastError(RPC_X_NULL_REF_POINTER);
6974 return FALSE;
6977 *pcbOutputNeeded = 0;
6979 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6980 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6984 /*****************************************************************************
6985 * EnumPrinterDataA [WINSPOOL.@]
6988 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6989 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6990 DWORD cbData, LPDWORD pcbData )
6992 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6993 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6994 return ERROR_NO_MORE_ITEMS;
6997 /*****************************************************************************
6998 * EnumPrinterDataW [WINSPOOL.@]
7001 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7002 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7003 DWORD cbData, LPDWORD pcbData )
7005 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7006 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7007 return ERROR_NO_MORE_ITEMS;
7010 /*****************************************************************************
7011 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7014 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7015 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7016 LPDWORD pcbNeeded, LPDWORD pcReturned)
7018 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7019 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7020 pcbNeeded, pcReturned);
7021 return FALSE;
7024 /*****************************************************************************
7025 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7028 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7029 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7030 LPDWORD pcbNeeded, LPDWORD pcReturned)
7032 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7033 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7034 pcbNeeded, pcReturned);
7035 return FALSE;
7038 /*****************************************************************************
7039 * EnumPrintProcessorsA [WINSPOOL.@]
7041 * See EnumPrintProcessorsW.
7044 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7045 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7047 BOOL res;
7048 LPBYTE bufferW = NULL;
7049 LPWSTR nameW = NULL;
7050 LPWSTR envW = NULL;
7051 DWORD needed = 0;
7052 DWORD numentries = 0;
7053 INT len;
7055 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7056 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7058 /* convert names to unicode */
7059 if (pName) {
7060 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7061 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7062 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7064 if (pEnvironment) {
7065 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7066 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7067 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7070 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7071 needed = cbBuf * sizeof(WCHAR);
7072 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7073 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7075 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7076 if (pcbNeeded) needed = *pcbNeeded;
7077 /* HeapReAlloc return NULL, when bufferW was NULL */
7078 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7079 HeapAlloc(GetProcessHeap(), 0, needed);
7081 /* Try again with the large Buffer */
7082 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7084 numentries = pcReturned ? *pcReturned : 0;
7085 needed = 0;
7087 if (res) {
7088 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7089 DWORD index;
7090 LPSTR ptr;
7091 PPRINTPROCESSOR_INFO_1W ppiw;
7092 PPRINTPROCESSOR_INFO_1A ppia;
7094 /* First pass: calculate the size for all Entries */
7095 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7096 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7097 index = 0;
7098 while (index < numentries) {
7099 index++;
7100 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7101 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7103 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7104 NULL, 0, NULL, NULL);
7106 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7107 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7110 /* check for errors and quit on failure */
7111 if (cbBuf < needed) {
7112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7113 res = FALSE;
7114 goto epp_cleanup;
7117 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7118 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7119 cbBuf -= len ; /* free Bytes in the user-Buffer */
7120 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7121 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7122 index = 0;
7123 /* Second Pass: Fill the User Buffer (if we have one) */
7124 while ((index < numentries) && pPPInfo) {
7125 index++;
7126 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7127 ppia->pName = ptr;
7128 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7129 ptr, cbBuf , NULL, NULL);
7130 ptr += len;
7131 cbBuf -= len;
7133 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7134 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7138 epp_cleanup:
7139 if (pcbNeeded) *pcbNeeded = needed;
7140 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7142 HeapFree(GetProcessHeap(), 0, nameW);
7143 HeapFree(GetProcessHeap(), 0, envW);
7144 HeapFree(GetProcessHeap(), 0, bufferW);
7146 TRACE("returning %d with %d (%d byte for %d entries)\n",
7147 (res), GetLastError(), needed, numentries);
7149 return (res);
7152 /*****************************************************************************
7153 * EnumPrintProcessorsW [WINSPOOL.@]
7155 * Enumerate available Print Processors
7157 * PARAMS
7158 * pName [I] Servername or NULL (local Computer)
7159 * pEnvironment [I] Printing-Environment or NULL (Default)
7160 * Level [I] Structure-Level (Only 1 is allowed)
7161 * pPPInfo [O] PTR to Buffer that receives the Result
7162 * cbBuf [I] Size of Buffer at pPPInfo
7163 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7164 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7166 * RETURNS
7167 * Success: TRUE
7168 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7171 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7172 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7175 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7176 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7178 if ((backend == NULL) && !load_backend()) return FALSE;
7180 if (!pcbNeeded || !pcReturned) {
7181 SetLastError(RPC_X_NULL_REF_POINTER);
7182 return FALSE;
7185 if (!pPPInfo && (cbBuf > 0)) {
7186 SetLastError(ERROR_INVALID_USER_BUFFER);
7187 return FALSE;
7190 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7191 cbBuf, pcbNeeded, pcReturned);
7194 /*****************************************************************************
7195 * ExtDeviceMode [WINSPOOL.@]
7198 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7199 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7200 DWORD fMode)
7202 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7203 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7204 debugstr_a(pProfile), fMode);
7205 return -1;
7208 /*****************************************************************************
7209 * FindClosePrinterChangeNotification [WINSPOOL.@]
7212 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7214 FIXME("Stub: %p\n", hChange);
7215 return TRUE;
7218 /*****************************************************************************
7219 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7222 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7223 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7225 FIXME("Stub: %p %x %x %p\n",
7226 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7227 return INVALID_HANDLE_VALUE;
7230 /*****************************************************************************
7231 * FindNextPrinterChangeNotification [WINSPOOL.@]
7234 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7235 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7237 FIXME("Stub: %p %p %p %p\n",
7238 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7239 return FALSE;
7242 /*****************************************************************************
7243 * FreePrinterNotifyInfo [WINSPOOL.@]
7246 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7248 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7249 return TRUE;
7252 /*****************************************************************************
7253 * string_to_buf
7255 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7256 * ansi depending on the unicode parameter.
7258 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7260 if(!str)
7262 *size = 0;
7263 return TRUE;
7266 if(unicode)
7268 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7269 if(*size <= cb)
7271 memcpy(ptr, str, *size);
7272 return TRUE;
7274 return FALSE;
7276 else
7278 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7279 if(*size <= cb)
7281 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7282 return TRUE;
7284 return FALSE;
7288 /*****************************************************************************
7289 * get_job_info_1
7291 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7292 LPDWORD pcbNeeded, BOOL unicode)
7294 DWORD size, left = cbBuf;
7295 BOOL space = (cbBuf > 0);
7296 LPBYTE ptr = buf;
7298 *pcbNeeded = 0;
7300 if(space)
7302 ji1->JobId = job->job_id;
7305 string_to_buf(job->document_title, ptr, left, &size, unicode);
7306 if(space && size <= left)
7308 ji1->pDocument = (LPWSTR)ptr;
7309 ptr += size;
7310 left -= size;
7312 else
7313 space = FALSE;
7314 *pcbNeeded += size;
7316 if (job->printer_name)
7318 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7319 if(space && size <= left)
7321 ji1->pPrinterName = (LPWSTR)ptr;
7322 ptr += size;
7323 left -= size;
7325 else
7326 space = FALSE;
7327 *pcbNeeded += size;
7330 return space;
7333 /*****************************************************************************
7334 * get_job_info_2
7336 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7337 LPDWORD pcbNeeded, BOOL unicode)
7339 DWORD size, left = cbBuf;
7340 DWORD shift;
7341 BOOL space = (cbBuf > 0);
7342 LPBYTE ptr = buf;
7343 LPDEVMODEA dmA = NULL;
7344 LPDEVMODEW devmode;
7346 *pcbNeeded = 0;
7348 if(space)
7350 ji2->JobId = job->job_id;
7353 string_to_buf(job->document_title, ptr, left, &size, unicode);
7354 if(space && size <= left)
7356 ji2->pDocument = (LPWSTR)ptr;
7357 ptr += size;
7358 left -= size;
7360 else
7361 space = FALSE;
7362 *pcbNeeded += size;
7364 if (job->printer_name)
7366 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7367 if(space && size <= left)
7369 ji2->pPrinterName = (LPWSTR)ptr;
7370 ptr += size;
7371 left -= size;
7373 else
7374 space = FALSE;
7375 *pcbNeeded += size;
7378 if (job->devmode)
7380 if (!unicode)
7382 dmA = DEVMODEdupWtoA(job->devmode);
7383 devmode = (LPDEVMODEW) dmA;
7384 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7386 else
7388 devmode = job->devmode;
7389 size = devmode->dmSize + devmode->dmDriverExtra;
7392 if (!devmode)
7393 FIXME("Can't convert DEVMODE W to A\n");
7394 else
7396 /* align DEVMODE to a DWORD boundary */
7397 shift = (4 - (*pcbNeeded & 3)) & 3;
7398 size += shift;
7400 if (size <= left)
7402 ptr += shift;
7403 memcpy(ptr, devmode, size-shift);
7404 ji2->pDevMode = (LPDEVMODEW)ptr;
7405 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7406 ptr += size-shift;
7407 left -= size;
7409 else
7410 space = FALSE;
7411 *pcbNeeded +=size;
7415 return space;
7418 /*****************************************************************************
7419 * get_job_info
7421 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7422 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7424 BOOL ret = FALSE;
7425 DWORD needed = 0, size;
7426 job_t *job;
7427 LPBYTE ptr = pJob;
7429 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7431 EnterCriticalSection(&printer_handles_cs);
7432 job = get_job(hPrinter, JobId);
7433 if(!job)
7434 goto end;
7436 switch(Level)
7438 case 1:
7439 size = sizeof(JOB_INFO_1W);
7440 if(cbBuf >= size)
7442 cbBuf -= size;
7443 ptr += size;
7444 memset(pJob, 0, size);
7446 else
7447 cbBuf = 0;
7448 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7449 needed += size;
7450 break;
7452 case 2:
7453 size = sizeof(JOB_INFO_2W);
7454 if(cbBuf >= size)
7456 cbBuf -= size;
7457 ptr += size;
7458 memset(pJob, 0, size);
7460 else
7461 cbBuf = 0;
7462 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7463 needed += size;
7464 break;
7466 case 3:
7467 size = sizeof(JOB_INFO_3);
7468 if(cbBuf >= size)
7470 cbBuf -= size;
7471 memset(pJob, 0, size);
7472 ret = TRUE;
7474 else
7475 cbBuf = 0;
7476 needed = size;
7477 break;
7479 default:
7480 SetLastError(ERROR_INVALID_LEVEL);
7481 goto end;
7483 if(pcbNeeded)
7484 *pcbNeeded = needed;
7485 end:
7486 LeaveCriticalSection(&printer_handles_cs);
7487 return ret;
7490 /*****************************************************************************
7491 * GetJobA [WINSPOOL.@]
7494 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7495 DWORD cbBuf, LPDWORD pcbNeeded)
7497 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7500 /*****************************************************************************
7501 * GetJobW [WINSPOOL.@]
7504 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7505 DWORD cbBuf, LPDWORD pcbNeeded)
7507 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7510 /*****************************************************************************
7511 * schedule_pipe
7513 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7515 #ifdef HAVE_FORK
7516 char *unixname, *cmdA;
7517 DWORD len;
7518 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7519 BOOL ret = FALSE;
7520 char buf[1024];
7521 pid_t pid, wret;
7522 int status;
7524 if(!(unixname = wine_get_unix_file_name(filename)))
7525 return FALSE;
7527 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7528 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7529 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7531 TRACE("printing with: %s\n", cmdA);
7533 if((file_fd = open(unixname, O_RDONLY)) == -1)
7534 goto end;
7536 if (pipe(fds))
7538 ERR("pipe() failed!\n");
7539 goto end;
7542 if ((pid = fork()) == 0)
7544 close(0);
7545 dup2(fds[0], 0);
7546 close(fds[1]);
7548 /* reset signals that we previously set to SIG_IGN */
7549 signal(SIGPIPE, SIG_DFL);
7551 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7552 _exit(1);
7554 else if (pid == -1)
7556 ERR("fork() failed!\n");
7557 goto end;
7560 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7561 write(fds[1], buf, no_read);
7563 close(fds[1]);
7564 fds[1] = -1;
7566 /* reap child */
7567 do {
7568 wret = waitpid(pid, &status, 0);
7569 } while (wret < 0 && errno == EINTR);
7570 if (wret < 0)
7572 ERR("waitpid() failed!\n");
7573 goto end;
7575 if (!WIFEXITED(status) || WEXITSTATUS(status))
7577 ERR("child process failed! %d\n", status);
7578 goto end;
7581 ret = TRUE;
7583 end:
7584 if(file_fd != -1) close(file_fd);
7585 if(fds[0] != -1) close(fds[0]);
7586 if(fds[1] != -1) close(fds[1]);
7588 HeapFree(GetProcessHeap(), 0, cmdA);
7589 HeapFree(GetProcessHeap(), 0, unixname);
7590 return ret;
7591 #else
7592 return FALSE;
7593 #endif
7596 /*****************************************************************************
7597 * schedule_lpr
7599 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7601 WCHAR *cmd;
7602 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7603 BOOL r;
7605 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7606 sprintfW(cmd, fmtW, printer_name);
7608 r = schedule_pipe(cmd, filename);
7610 HeapFree(GetProcessHeap(), 0, cmd);
7611 return r;
7614 #ifdef SONAME_LIBCUPS
7615 /*****************************************************************************
7616 * get_cups_jobs_ticket_options
7618 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7619 * The CUPS scheduler only looks for these in Print-File requests, and since
7620 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7621 * parsed.
7623 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7625 FILE *fp = fopen( file, "r" );
7626 char buf[257]; /* DSC max of 256 + '\0' */
7627 const char *ps_adobe = "%!PS-Adobe-";
7628 const char *cups_job = "%cupsJobTicket:";
7630 if (!fp) return num_options;
7631 if (!fgets( buf, sizeof(buf), fp )) goto end;
7632 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7633 while (fgets( buf, sizeof(buf), fp ))
7635 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7636 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7639 end:
7640 fclose( fp );
7641 return num_options;
7643 #endif
7645 /*****************************************************************************
7646 * schedule_cups
7648 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7650 #ifdef SONAME_LIBCUPS
7651 if(pcupsPrintFile)
7653 char *unixname, *queue, *unix_doc_title;
7654 DWORD len;
7655 BOOL ret;
7656 int num_options = 0, i;
7657 cups_option_t *options = NULL;
7659 if(!(unixname = wine_get_unix_file_name(filename)))
7660 return FALSE;
7662 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7663 queue = HeapAlloc(GetProcessHeap(), 0, len);
7664 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7666 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7667 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7668 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7670 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7672 TRACE( "printing via cups with options:\n" );
7673 for (i = 0; i < num_options; i++)
7674 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7676 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7678 pcupsFreeOptions( num_options, options );
7680 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7681 HeapFree(GetProcessHeap(), 0, queue);
7682 HeapFree(GetProcessHeap(), 0, unixname);
7683 return ret;
7685 else
7686 #endif
7688 return schedule_lpr(printer_name, filename);
7692 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7694 LPWSTR filename;
7696 switch(msg)
7698 case WM_INITDIALOG:
7699 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7700 return TRUE;
7702 case WM_COMMAND:
7703 if(HIWORD(wparam) == BN_CLICKED)
7705 if(LOWORD(wparam) == IDOK)
7707 HANDLE hf;
7708 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7709 LPWSTR *output;
7711 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7712 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7714 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7716 WCHAR caption[200], message[200];
7717 int mb_ret;
7719 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7720 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7721 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7722 if(mb_ret == IDCANCEL)
7724 HeapFree(GetProcessHeap(), 0, filename);
7725 return TRUE;
7728 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7729 if(hf == INVALID_HANDLE_VALUE)
7731 WCHAR caption[200], message[200];
7733 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7734 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7735 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7736 HeapFree(GetProcessHeap(), 0, filename);
7737 return TRUE;
7739 CloseHandle(hf);
7740 DeleteFileW(filename);
7741 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7742 *output = filename;
7743 EndDialog(hwnd, IDOK);
7744 return TRUE;
7746 if(LOWORD(wparam) == IDCANCEL)
7748 EndDialog(hwnd, IDCANCEL);
7749 return TRUE;
7752 return FALSE;
7754 return FALSE;
7757 /*****************************************************************************
7758 * get_filename
7760 static BOOL get_filename(LPWSTR *filename)
7762 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7763 file_dlg_proc, (LPARAM)filename) == IDOK;
7766 /*****************************************************************************
7767 * schedule_file
7769 static BOOL schedule_file(LPCWSTR filename)
7771 LPWSTR output = NULL;
7773 if(get_filename(&output))
7775 BOOL r;
7776 TRACE("copy to %s\n", debugstr_w(output));
7777 r = CopyFileW(filename, output, FALSE);
7778 HeapFree(GetProcessHeap(), 0, output);
7779 return r;
7781 return FALSE;
7784 /*****************************************************************************
7785 * schedule_unixfile
7787 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7789 int in_fd, out_fd, no_read;
7790 char buf[1024];
7791 BOOL ret = FALSE;
7792 char *unixname, *outputA;
7793 DWORD len;
7795 if(!(unixname = wine_get_unix_file_name(filename)))
7796 return FALSE;
7798 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7799 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7800 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7802 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7803 in_fd = open(unixname, O_RDONLY);
7804 if(out_fd == -1 || in_fd == -1)
7805 goto end;
7807 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7808 write(out_fd, buf, no_read);
7810 ret = TRUE;
7811 end:
7812 if(in_fd != -1) close(in_fd);
7813 if(out_fd != -1) close(out_fd);
7814 HeapFree(GetProcessHeap(), 0, outputA);
7815 HeapFree(GetProcessHeap(), 0, unixname);
7816 return ret;
7819 /*****************************************************************************
7820 * ScheduleJob [WINSPOOL.@]
7823 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7825 opened_printer_t *printer;
7826 BOOL ret = FALSE;
7827 struct list *cursor, *cursor2;
7829 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7830 EnterCriticalSection(&printer_handles_cs);
7831 printer = get_opened_printer(hPrinter);
7832 if(!printer)
7833 goto end;
7835 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7837 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7838 HANDLE hf;
7840 if(job->job_id != dwJobID) continue;
7842 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7843 if(hf != INVALID_HANDLE_VALUE)
7845 PRINTER_INFO_5W *pi5 = NULL;
7846 LPWSTR portname = job->portname;
7847 DWORD needed;
7848 HKEY hkey;
7849 WCHAR output[1024];
7850 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7851 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7853 if (!portname)
7855 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7856 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7857 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7858 portname = pi5->pPortName;
7860 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7861 debugstr_w(portname));
7863 output[0] = 0;
7865 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7866 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7868 DWORD type, count = sizeof(output);
7869 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7870 RegCloseKey(hkey);
7872 if(output[0] == '|')
7874 ret = schedule_pipe(output + 1, job->filename);
7876 else if(output[0])
7878 ret = schedule_unixfile(output, job->filename);
7880 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7882 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7884 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7886 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7888 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7890 ret = schedule_file(job->filename);
7892 else
7894 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7896 HeapFree(GetProcessHeap(), 0, pi5);
7897 CloseHandle(hf);
7898 DeleteFileW(job->filename);
7900 list_remove(cursor);
7901 HeapFree(GetProcessHeap(), 0, job->document_title);
7902 HeapFree(GetProcessHeap(), 0, job->printer_name);
7903 HeapFree(GetProcessHeap(), 0, job->portname);
7904 HeapFree(GetProcessHeap(), 0, job->filename);
7905 HeapFree(GetProcessHeap(), 0, job->devmode);
7906 HeapFree(GetProcessHeap(), 0, job);
7907 break;
7909 end:
7910 LeaveCriticalSection(&printer_handles_cs);
7911 return ret;
7914 /*****************************************************************************
7915 * StartDocDlgA [WINSPOOL.@]
7917 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7919 UNICODE_STRING usBuffer;
7920 DOCINFOW docW;
7921 LPWSTR retW;
7922 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7923 LPSTR ret = NULL;
7925 docW.cbSize = sizeof(docW);
7926 if (doc->lpszDocName)
7928 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7929 if (!(docW.lpszDocName = docnameW)) return NULL;
7931 if (doc->lpszOutput)
7933 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7934 if (!(docW.lpszOutput = outputW)) return NULL;
7936 if (doc->lpszDatatype)
7938 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7939 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7941 docW.fwType = doc->fwType;
7943 retW = StartDocDlgW(hPrinter, &docW);
7945 if(retW)
7947 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7948 ret = HeapAlloc(GetProcessHeap(), 0, len);
7949 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7950 HeapFree(GetProcessHeap(), 0, retW);
7953 HeapFree(GetProcessHeap(), 0, datatypeW);
7954 HeapFree(GetProcessHeap(), 0, outputW);
7955 HeapFree(GetProcessHeap(), 0, docnameW);
7957 return ret;
7960 /*****************************************************************************
7961 * StartDocDlgW [WINSPOOL.@]
7963 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7964 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7965 * port is "FILE:". Also returns the full path if passed a relative path.
7967 * The caller should free the returned string from the process heap.
7969 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7971 LPWSTR ret = NULL;
7972 DWORD len, attr;
7974 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7976 PRINTER_INFO_5W *pi5;
7977 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7978 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7979 return NULL;
7980 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7981 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7982 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7984 HeapFree(GetProcessHeap(), 0, pi5);
7985 return NULL;
7987 HeapFree(GetProcessHeap(), 0, pi5);
7990 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7992 LPWSTR name;
7994 if (get_filename(&name))
7996 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7998 HeapFree(GetProcessHeap(), 0, name);
7999 return NULL;
8001 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8002 GetFullPathNameW(name, len, ret, NULL);
8003 HeapFree(GetProcessHeap(), 0, name);
8005 return ret;
8008 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8009 return NULL;
8011 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8012 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8014 attr = GetFileAttributesW(ret);
8015 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8017 HeapFree(GetProcessHeap(), 0, ret);
8018 ret = NULL;
8020 return ret;