msvcrt: Added _iswdigit_l implementation.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blobabc8478adce9eb65a90af1eb906b25bca3a1b187
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 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #include <signal.h>
40 #ifdef HAVE_CUPS_CUPS_H
41 # include <cups/cups.h>
42 #endif
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
46 #include "wine/library.h"
47 #include "windef.h"
48 #include "winbase.h"
49 #include "winuser.h"
50 #include "winerror.h"
51 #include "winreg.h"
52 #include "wingdi.h"
53 #include "winspool.h"
54 #include "winternl.h"
55 #include "wine/windef16.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
58 #include "wine/list.h"
59 #include "winnls.h"
61 #include "ddk/winsplp.h"
62 #include "wspool.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
66 /* ############################### */
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
77 /* ############################### */
79 typedef struct {
80 DWORD job_id;
81 HANDLE hf;
82 } started_doc_t;
84 typedef struct {
85 struct list jobs;
86 LONG ref;
87 } jobqueue_t;
89 typedef struct {
90 LPWSTR name;
91 LPWSTR printername;
92 HANDLE backend_printer;
93 jobqueue_t *queue;
94 started_doc_t *doc;
95 } opened_printer_t;
97 typedef struct {
98 struct list entry;
99 DWORD job_id;
100 WCHAR *filename;
101 WCHAR *portname;
102 WCHAR *document_title;
103 WCHAR *printer_name;
104 LPDEVMODEW devmode;
105 } job_t;
108 typedef struct {
109 LPCWSTR envname;
110 LPCWSTR subdir;
111 DWORD driverversion;
112 LPCWSTR versionregpath;
113 LPCWSTR versionsubdir;
114 } printenv_t;
116 /* ############################### */
118 static opened_printer_t **printer_handles;
119 static UINT nb_printer_handles;
120 static LONG next_job_id = 1;
122 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
123 WORD fwCapability, LPSTR lpszOutput,
124 LPDEVMODEA lpdm );
125 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
126 LPSTR lpszDevice, LPSTR lpszPort,
127 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
128 DWORD fwMode );
130 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'c','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
135 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
137 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
138 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
139 'C','o','n','t','r','o','l','\\',
140 'P','r','i','n','t','\\',
141 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
145 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
146 'M','i','c','r','o','s','o','f','t','\\',
147 'W','i','n','d','o','w','s',' ','N','T','\\',
148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
149 'W','i','n','d','o','w','s',0};
151 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'D','e','v','i','c','e','s',0};
157 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
158 'M','i','c','r','o','s','o','f','t','\\',
159 'W','i','n','d','o','w','s',' ','N','T','\\',
160 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
161 'P','o','r','t','s',0};
163 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s',' ','N','T','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'P','r','i','n','t','e','r','P','o','r','t','s',0};
169 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
170 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
171 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
172 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
173 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
174 static const WCHAR subdir_x64W[] = {'x','6','4',0};
175 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
176 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
177 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
178 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
179 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
181 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
182 static const WCHAR backslashW[] = {'\\',0};
183 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
184 'i','o','n',' ','F','i','l','e',0};
185 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
186 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
187 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
188 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
189 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
190 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
191 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
192 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
193 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
194 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
195 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
196 static const WCHAR NameW[] = {'N','a','m','e',0};
197 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
198 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
199 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
200 static const WCHAR PortW[] = {'P','o','r','t',0};
201 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
202 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
203 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
204 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
205 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
206 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
207 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
208 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
209 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
210 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
211 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
212 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
213 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
214 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
215 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
216 static WCHAR rawW[] = {'R','A','W',0};
217 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
218 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
219 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
220 static const WCHAR commaW[] = {',',0};
221 static WCHAR emptyStringW[] = {0};
223 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
225 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
226 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
227 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
229 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
230 'D','o','c','u','m','e','n','t',0};
232 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
233 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
234 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
235 0, sizeof(DRIVER_INFO_8W)};
238 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
239 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
240 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
241 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
242 sizeof(PRINTER_INFO_9W)};
244 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
245 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
246 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
248 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
250 /******************************************************************
251 * validate the user-supplied printing-environment [internal]
253 * PARAMS
254 * env [I] PTR to Environment-String or NULL
256 * RETURNS
257 * Failure: NULL
258 * Success: PTR to printenv_t
260 * NOTES
261 * An empty string is handled the same way as NULL.
262 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
266 static const printenv_t * validate_envW(LPCWSTR env)
268 const printenv_t *result = NULL;
269 unsigned int i;
271 TRACE("testing %s\n", debugstr_w(env));
272 if (env && env[0])
274 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
276 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
278 result = all_printenv[i];
279 break;
283 if (result == NULL) {
284 FIXME("unsupported Environment: %s\n", debugstr_w(env));
285 SetLastError(ERROR_INVALID_ENVIRONMENT);
287 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
289 else
291 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
293 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
295 return result;
299 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
300 if passed a NULL string. This returns NULLs to the result.
302 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
304 if ( (src) )
306 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
307 return usBufferPtr->Buffer;
309 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
310 return NULL;
313 static LPWSTR strdupW(LPCWSTR p)
315 LPWSTR ret;
316 DWORD len;
318 if(!p) return NULL;
319 len = (strlenW(p) + 1) * sizeof(WCHAR);
320 ret = HeapAlloc(GetProcessHeap(), 0, len);
321 memcpy(ret, p, len);
322 return ret;
325 static LPSTR strdupWtoA( LPCWSTR str )
327 LPSTR ret;
328 INT len;
330 if (!str) return NULL;
331 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
332 ret = HeapAlloc( GetProcessHeap(), 0, len );
333 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
334 return ret;
337 /******************************************************************
338 * verify, that the filename is a local file
341 static inline BOOL is_local_file(LPWSTR name)
343 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
346 /* ################################ */
348 static int multi_sz_lenA(const char *str)
350 const char *ptr = str;
351 if(!str) return 0;
354 ptr += lstrlenA(ptr) + 1;
355 } while(*ptr);
357 return ptr - str + 1;
360 static void
361 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
362 char qbuf[200];
364 /* If forcing, or no profile string entry for device yet, set the entry
366 * The always change entry if not WINEPS yet is discussable.
368 if (force ||
369 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
370 !strcmp(qbuf,"*") ||
371 !strstr(qbuf,"WINEPS.DRV")
373 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
374 HKEY hkey;
376 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
377 WriteProfileStringA("windows","device",buf);
378 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
379 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
380 RegCloseKey(hkey);
382 HeapFree(GetProcessHeap(),0,buf);
386 static BOOL add_printer_driver(WCHAR *name)
388 DRIVER_INFO_3W di3;
390 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
391 di3.cVersion = 3;
392 di3.pName = name;
393 di3.pEnvironment = envname_x86W;
394 di3.pDriverPath = driver_nt;
395 di3.pDataFile = generic_ppdW;
396 di3.pConfigFile = driver_nt;
397 di3.pDefaultDataType = rawW;
399 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
400 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
402 di3.cVersion = 0;
403 di3.pEnvironment = envname_win40W;
404 di3.pDriverPath = driver_9x;
405 di3.pConfigFile = driver_9x;
406 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
407 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
409 return TRUE;
412 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
413 return FALSE;
416 #ifdef SONAME_LIBCUPS
417 static typeof(cupsFreeDests) *pcupsFreeDests;
418 static typeof(cupsGetDests) *pcupsGetDests;
419 static typeof(cupsGetPPD) *pcupsGetPPD;
420 static typeof(cupsPrintFile) *pcupsPrintFile;
421 static void *cupshandle;
423 static BOOL CUPS_LoadPrinters(void)
425 int i, nrofdests;
426 BOOL hadprinter = FALSE, haddefault = FALSE;
427 cups_dest_t *dests;
428 PRINTER_INFO_2W pi2;
429 WCHAR *port;
430 HKEY hkeyPrinter, hkeyPrinters;
431 char loaderror[256];
432 WCHAR nameW[MAX_PATH];
434 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
435 if (!cupshandle) {
436 TRACE("%s\n", loaderror);
437 return FALSE;
439 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
441 #define DYNCUPS(x) \
442 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
443 if (!p##x) return FALSE;
445 DYNCUPS(cupsFreeDests);
446 DYNCUPS(cupsGetPPD);
447 DYNCUPS(cupsGetDests);
448 DYNCUPS(cupsPrintFile);
449 #undef DYNCUPS
451 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
452 ERROR_SUCCESS) {
453 ERR("Can't create Printers key\n");
454 return FALSE;
457 nrofdests = pcupsGetDests(&dests);
458 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
459 for (i=0;i<nrofdests;i++) {
460 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
462 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
463 lstrcpyW(port, CUPS_Port);
464 lstrcatW(port, nameW);
466 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
467 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
468 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
469 and continue */
470 TRACE("Printer already exists\n");
471 /* overwrite old LPR:* port */
472 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
473 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
474 RegCloseKey(hkeyPrinter);
475 } else {
476 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
477 ' ','u','s','i','n','g',' ','C','U','P','S',0};
479 add_printer_driver(nameW);
481 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
482 pi2.pPrinterName = nameW;
483 pi2.pDatatype = rawW;
484 pi2.pPrintProcessor = WinPrintW;
485 pi2.pDriverName = nameW;
486 pi2.pComment = comment_cups;
487 pi2.pLocation = emptyStringW;
488 pi2.pPortName = port;
489 pi2.pParameters = emptyStringW;
490 pi2.pShareName = emptyStringW;
491 pi2.pSepFile = emptyStringW;
493 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
494 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
495 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
498 HeapFree(GetProcessHeap(),0,port);
500 hadprinter = TRUE;
501 if (dests[i].is_default) {
502 SetDefaultPrinterW(nameW);
503 haddefault = TRUE;
506 if (hadprinter && !haddefault) {
507 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
508 SetDefaultPrinterW(nameW);
510 pcupsFreeDests(nrofdests, dests);
511 RegCloseKey(hkeyPrinters);
512 return hadprinter;
514 #endif
516 static BOOL
517 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
518 PRINTER_INFO_2A pinfo2a;
519 const char *r;
520 size_t name_len;
521 char *e,*s,*name,*prettyname,*devname;
522 BOOL ret = FALSE, set_default = FALSE;
523 char *port = NULL, *env_default;
524 HKEY hkeyPrinter, hkeyPrinters;
525 WCHAR devnameW[MAX_PATH];
527 while (isspace(*pent)) pent++;
528 r = strchr(pent,':');
529 if (r)
530 name_len = r - pent;
531 else
532 name_len = strlen(pent);
533 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
534 memcpy(name, pent, name_len);
535 name[name_len] = '\0';
536 if (r)
537 pent = r;
538 else
539 pent = "";
541 TRACE("name=%s entry=%s\n",name, pent);
543 if(ispunct(*name)) { /* a tc entry, not a real printer */
544 TRACE("skipping tc entry\n");
545 goto end;
548 if(strstr(pent,":server")) { /* server only version so skip */
549 TRACE("skipping server entry\n");
550 goto end;
553 /* Determine whether this is a postscript printer. */
555 ret = TRUE;
556 env_default = getenv("PRINTER");
557 prettyname = name;
558 /* Get longest name, usually the one at the right for later display. */
559 while((s=strchr(prettyname,'|'))) {
560 *s = '\0';
561 e = s;
562 while(isspace(*--e)) *e = '\0';
563 TRACE("\t%s\n", debugstr_a(prettyname));
564 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
565 for(prettyname = s+1; isspace(*prettyname); prettyname++)
568 e = prettyname + strlen(prettyname);
569 while(isspace(*--e)) *e = '\0';
570 TRACE("\t%s\n", debugstr_a(prettyname));
571 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
573 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
574 * if it is too long, we use it as comment below. */
575 devname = prettyname;
576 if (strlen(devname)>=CCHDEVICENAME-1)
577 devname = name;
578 if (strlen(devname)>=CCHDEVICENAME-1) {
579 ret = FALSE;
580 goto end;
583 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
584 sprintf(port,"LPR:%s",name);
586 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
587 ERROR_SUCCESS) {
588 ERR("Can't create Printers key\n");
589 ret = FALSE;
590 goto end;
593 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
595 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
596 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
597 and continue */
598 TRACE("Printer already exists\n");
599 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
600 RegCloseKey(hkeyPrinter);
601 } else {
602 static CHAR data_type[] = "RAW",
603 print_proc[] = "WinPrint",
604 comment[] = "WINEPS Printer using LPR",
605 params[] = "<parameters?>",
606 share_name[] = "<share name?>",
607 sep_file[] = "<sep file?>";
609 add_printer_driver(devnameW);
611 memset(&pinfo2a,0,sizeof(pinfo2a));
612 pinfo2a.pPrinterName = devname;
613 pinfo2a.pDatatype = data_type;
614 pinfo2a.pPrintProcessor = print_proc;
615 pinfo2a.pDriverName = devname;
616 pinfo2a.pComment = comment;
617 pinfo2a.pLocation = prettyname;
618 pinfo2a.pPortName = port;
619 pinfo2a.pParameters = params;
620 pinfo2a.pShareName = share_name;
621 pinfo2a.pSepFile = sep_file;
623 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
624 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
625 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
628 RegCloseKey(hkeyPrinters);
630 if (isfirst || set_default)
631 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
633 end:
634 HeapFree(GetProcessHeap(), 0, port);
635 HeapFree(GetProcessHeap(), 0, name);
636 return ret;
639 static BOOL
640 PRINTCAP_LoadPrinters(void) {
641 BOOL hadprinter = FALSE;
642 char buf[200];
643 FILE *f;
644 char *pent = NULL;
645 BOOL had_bash = FALSE;
647 f = fopen("/etc/printcap","r");
648 if (!f)
649 return FALSE;
651 while(fgets(buf,sizeof(buf),f)) {
652 char *start, *end;
654 end=strchr(buf,'\n');
655 if (end) *end='\0';
657 start = buf;
658 while(isspace(*start)) start++;
659 if(*start == '#' || *start == '\0')
660 continue;
662 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
663 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
664 HeapFree(GetProcessHeap(),0,pent);
665 pent = NULL;
668 if (end && *--end == '\\') {
669 *end = '\0';
670 had_bash = TRUE;
671 } else
672 had_bash = FALSE;
674 if (pent) {
675 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
676 strcat(pent,start);
677 } else {
678 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
679 strcpy(pent,start);
683 if(pent) {
684 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
685 HeapFree(GetProcessHeap(),0,pent);
687 fclose(f);
688 return hadprinter;
691 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
693 if (value)
694 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
695 (lstrlenW(value) + 1) * sizeof(WCHAR));
696 else
697 return ERROR_FILE_NOT_FOUND;
700 /******************************************************************
701 * get_servername_from_name (internal)
703 * for an external server, a copy of the serverpart from the full name is returned
706 static LPWSTR get_servername_from_name(LPCWSTR name)
708 LPWSTR server;
709 LPWSTR ptr;
710 WCHAR buffer[MAX_PATH];
711 DWORD len;
713 if (name == NULL) return NULL;
714 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
716 server = strdupW(&name[2]); /* skip over both backslash */
717 if (server == NULL) return NULL;
719 /* strip '\' and the printername */
720 ptr = strchrW(server, '\\');
721 if (ptr) ptr[0] = '\0';
723 TRACE("found %s\n", debugstr_w(server));
725 len = sizeof(buffer)/sizeof(buffer[0]);
726 if (GetComputerNameW(buffer, &len)) {
727 if (lstrcmpW(buffer, server) == 0) {
728 /* The requested Servername is our computername */
729 HeapFree(GetProcessHeap(), 0, server);
730 return NULL;
733 return server;
736 /******************************************************************
737 * get_basename_from_name (internal)
739 * skip over the serverpart from the full name
742 static LPCWSTR get_basename_from_name(LPCWSTR name)
744 if (name == NULL) return NULL;
745 if ((name[0] == '\\') && (name[1] == '\\')) {
746 /* skip over the servername and search for the following '\' */
747 name = strchrW(&name[2], '\\');
748 if ((name) && (name[1])) {
749 /* found a separator ('\') followed by a name:
750 skip over the separator and return the rest */
751 name++;
753 else
755 /* no basename present (we found only a servername) */
756 return NULL;
759 return name;
762 /******************************************************************
763 * get_opened_printer_entry
764 * Get the first place empty in the opened printer table
766 * ToDo:
767 * - pDefault is ignored
769 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
771 UINT_PTR handle = nb_printer_handles, i;
772 jobqueue_t *queue = NULL;
773 opened_printer_t *printer = NULL;
774 LPWSTR servername;
775 LPCWSTR printername;
777 if ((backend == NULL) && !load_backend()) return NULL;
779 servername = get_servername_from_name(name);
780 if (servername) {
781 FIXME("server %s not supported\n", debugstr_w(servername));
782 HeapFree(GetProcessHeap(), 0, servername);
783 SetLastError(ERROR_INVALID_PRINTER_NAME);
784 return NULL;
787 printername = get_basename_from_name(name);
788 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
790 /* an empty printername is invalid */
791 if (printername && (!printername[0])) {
792 SetLastError(ERROR_INVALID_PARAMETER);
793 return NULL;
796 EnterCriticalSection(&printer_handles_cs);
798 for (i = 0; i < nb_printer_handles; i++)
800 if (!printer_handles[i])
802 if(handle == nb_printer_handles)
803 handle = i;
805 else
807 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
808 queue = printer_handles[i]->queue;
812 if (handle >= nb_printer_handles)
814 opened_printer_t **new_array;
815 if (printer_handles)
816 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
817 (nb_printer_handles + 16) * sizeof(*new_array) );
818 else
819 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
820 (nb_printer_handles + 16) * sizeof(*new_array) );
822 if (!new_array)
824 handle = 0;
825 goto end;
827 printer_handles = new_array;
828 nb_printer_handles += 16;
831 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
833 handle = 0;
834 goto end;
837 /* get a printer handle from the backend */
838 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
839 handle = 0;
840 goto end;
843 /* clone the base name. This is NULL for the printserver */
844 printer->printername = strdupW(printername);
846 /* clone the full name */
847 printer->name = strdupW(name);
848 if (name && (!printer->name)) {
849 handle = 0;
850 goto end;
853 if(queue)
854 printer->queue = queue;
855 else
857 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
858 if (!printer->queue) {
859 handle = 0;
860 goto end;
862 list_init(&printer->queue->jobs);
863 printer->queue->ref = 0;
865 InterlockedIncrement(&printer->queue->ref);
867 printer_handles[handle] = printer;
868 handle++;
869 end:
870 LeaveCriticalSection(&printer_handles_cs);
871 if (!handle && printer) {
872 /* Something failed: Free all resources */
873 HeapFree(GetProcessHeap(), 0, printer->printername);
874 HeapFree(GetProcessHeap(), 0, printer->name);
875 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
876 HeapFree(GetProcessHeap(), 0, printer);
879 return (HANDLE)handle;
882 /******************************************************************
883 * get_opened_printer
884 * Get the pointer to the opened printer referred by the handle
886 static opened_printer_t *get_opened_printer(HANDLE hprn)
888 UINT_PTR idx = (UINT_PTR)hprn;
889 opened_printer_t *ret = NULL;
891 EnterCriticalSection(&printer_handles_cs);
893 if ((idx > 0) && (idx <= nb_printer_handles)) {
894 ret = printer_handles[idx - 1];
896 LeaveCriticalSection(&printer_handles_cs);
897 return ret;
900 /******************************************************************
901 * get_opened_printer_name
902 * Get the pointer to the opened printer name referred by the handle
904 static LPCWSTR get_opened_printer_name(HANDLE hprn)
906 opened_printer_t *printer = get_opened_printer(hprn);
907 if(!printer) return NULL;
908 return printer->name;
911 /******************************************************************
912 * WINSPOOL_GetOpenedPrinterRegKey
915 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
917 LPCWSTR name = get_opened_printer_name(hPrinter);
918 DWORD ret;
919 HKEY hkeyPrinters;
921 if(!name) return ERROR_INVALID_HANDLE;
923 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
924 ERROR_SUCCESS)
925 return ret;
927 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
929 ERR("Can't find opened printer %s in registry\n",
930 debugstr_w(name));
931 RegCloseKey(hkeyPrinters);
932 return ERROR_INVALID_PRINTER_NAME; /* ? */
934 RegCloseKey(hkeyPrinters);
935 return ERROR_SUCCESS;
938 void WINSPOOL_LoadSystemPrinters(void)
940 HKEY hkey, hkeyPrinters;
941 HANDLE hprn;
942 DWORD needed, num, i;
943 WCHAR PrinterName[256];
944 BOOL done = FALSE;
946 /* This ensures that all printer entries have a valid Name value. If causes
947 problems later if they don't. If one is found to be missed we create one
948 and set it equal to the name of the key */
949 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
950 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
951 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
952 for(i = 0; i < num; i++) {
953 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
954 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
955 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
956 set_reg_szW(hkey, NameW, PrinterName);
958 RegCloseKey(hkey);
963 RegCloseKey(hkeyPrinters);
966 /* We want to avoid calling AddPrinter on printers as much as
967 possible, because on cups printers this will (eventually) lead
968 to a call to cupsGetPPD which takes forever, even with non-cups
969 printers AddPrinter takes a while. So we'll tag all printers that
970 were automatically added last time around, if they still exist
971 we'll leave them be otherwise we'll delete them. */
972 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
973 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
974 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
975 for(i = 0; i < num; i++) {
976 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
977 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
978 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
979 DWORD dw = 1;
980 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
981 RegCloseKey(hkey);
983 ClosePrinter(hprn);
988 HeapFree(GetProcessHeap(), 0, pi);
992 #ifdef SONAME_LIBCUPS
993 done = CUPS_LoadPrinters();
994 #endif
996 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
997 PRINTCAP_LoadPrinters();
999 /* Now enumerate the list again and delete any printers that are still tagged */
1000 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1001 if(needed) {
1002 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1003 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1004 for(i = 0; i < num; i++) {
1005 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1006 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1007 BOOL delete_driver = FALSE;
1008 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1009 DWORD dw, type, size = sizeof(dw);
1010 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1011 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1012 DeletePrinter(hprn);
1013 delete_driver = TRUE;
1015 RegCloseKey(hkey);
1017 ClosePrinter(hprn);
1018 if(delete_driver)
1019 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1024 HeapFree(GetProcessHeap(), 0, pi);
1027 return;
1031 /******************************************************************
1032 * get_job
1034 * Get the pointer to the specified job.
1035 * Should hold the printer_handles_cs before calling.
1037 static job_t *get_job(HANDLE hprn, DWORD JobId)
1039 opened_printer_t *printer = get_opened_printer(hprn);
1040 job_t *job;
1042 if(!printer) return NULL;
1043 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1045 if(job->job_id == JobId)
1046 return job;
1048 return NULL;
1051 /***********************************************************
1052 * DEVMODEcpyAtoW
1054 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1056 BOOL Formname;
1057 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1058 DWORD size;
1060 Formname = (dmA->dmSize > off_formname);
1061 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1062 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1063 dmW->dmDeviceName, CCHDEVICENAME);
1064 if(!Formname) {
1065 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1066 dmA->dmSize - CCHDEVICENAME);
1067 } else {
1068 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1069 off_formname - CCHDEVICENAME);
1070 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1071 dmW->dmFormName, CCHFORMNAME);
1072 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1073 (off_formname + CCHFORMNAME));
1075 dmW->dmSize = size;
1076 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1077 dmA->dmDriverExtra);
1078 return dmW;
1081 /***********************************************************
1082 * DEVMODEdupWtoA
1083 * Creates an ansi copy of supplied devmode
1085 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1087 LPDEVMODEA dmA;
1088 DWORD size;
1090 if (!dmW) return NULL;
1091 size = dmW->dmSize - CCHDEVICENAME -
1092 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1094 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1095 if (!dmA) return NULL;
1097 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1098 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1100 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1101 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1102 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1104 else
1106 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1107 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1108 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1109 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1111 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1114 dmA->dmSize = size;
1115 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1116 return dmA;
1119 /******************************************************************
1120 * convert_printerinfo_W_to_A [internal]
1123 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1124 DWORD level, DWORD outlen, DWORD numentries)
1126 DWORD id = 0;
1127 LPSTR ptr;
1128 INT len;
1130 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1132 len = pi_sizeof[level] * numentries;
1133 ptr = (LPSTR) out + len;
1134 outlen -= len;
1136 /* copy the numbers of all PRINTER_INFO_* first */
1137 memcpy(out, pPrintersW, len);
1139 while (id < numentries) {
1140 switch (level) {
1141 case 1:
1143 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1144 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1146 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1147 if (piW->pDescription) {
1148 piA->pDescription = ptr;
1149 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1150 ptr, outlen, NULL, NULL);
1151 ptr += len;
1152 outlen -= len;
1154 if (piW->pName) {
1155 piA->pName = ptr;
1156 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1157 ptr, outlen, NULL, NULL);
1158 ptr += len;
1159 outlen -= len;
1161 if (piW->pComment) {
1162 piA->pComment = ptr;
1163 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1164 ptr, outlen, NULL, NULL);
1165 ptr += len;
1166 outlen -= len;
1168 break;
1171 case 2:
1173 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1174 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1175 LPDEVMODEA dmA;
1177 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1178 if (piW->pServerName) {
1179 piA->pServerName = ptr;
1180 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1181 ptr, outlen, NULL, NULL);
1182 ptr += len;
1183 outlen -= len;
1185 if (piW->pPrinterName) {
1186 piA->pPrinterName = ptr;
1187 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1188 ptr, outlen, NULL, NULL);
1189 ptr += len;
1190 outlen -= len;
1192 if (piW->pShareName) {
1193 piA->pShareName = ptr;
1194 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1195 ptr, outlen, NULL, NULL);
1196 ptr += len;
1197 outlen -= len;
1199 if (piW->pPortName) {
1200 piA->pPortName = ptr;
1201 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1202 ptr, outlen, NULL, NULL);
1203 ptr += len;
1204 outlen -= len;
1206 if (piW->pDriverName) {
1207 piA->pDriverName = ptr;
1208 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1209 ptr, outlen, NULL, NULL);
1210 ptr += len;
1211 outlen -= len;
1213 if (piW->pComment) {
1214 piA->pComment = ptr;
1215 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1216 ptr, outlen, NULL, NULL);
1217 ptr += len;
1218 outlen -= len;
1220 if (piW->pLocation) {
1221 piA->pLocation = ptr;
1222 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1223 ptr, outlen, NULL, NULL);
1224 ptr += len;
1225 outlen -= len;
1228 dmA = DEVMODEdupWtoA(piW->pDevMode);
1229 if (dmA) {
1230 /* align DEVMODEA to a DWORD boundary */
1231 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1232 ptr += len;
1233 outlen -= len;
1235 piA->pDevMode = (LPDEVMODEA) ptr;
1236 len = dmA->dmSize + dmA->dmDriverExtra;
1237 memcpy(ptr, dmA, len);
1238 HeapFree(GetProcessHeap(), 0, dmA);
1240 ptr += len;
1241 outlen -= len;
1244 if (piW->pSepFile) {
1245 piA->pSepFile = ptr;
1246 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1247 ptr, outlen, NULL, NULL);
1248 ptr += len;
1249 outlen -= len;
1251 if (piW->pPrintProcessor) {
1252 piA->pPrintProcessor = ptr;
1253 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1254 ptr, outlen, NULL, NULL);
1255 ptr += len;
1256 outlen -= len;
1258 if (piW->pDatatype) {
1259 piA->pDatatype = ptr;
1260 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1261 ptr, outlen, NULL, NULL);
1262 ptr += len;
1263 outlen -= len;
1265 if (piW->pParameters) {
1266 piA->pParameters = ptr;
1267 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1268 ptr, outlen, NULL, NULL);
1269 ptr += len;
1270 outlen -= len;
1272 if (piW->pSecurityDescriptor) {
1273 piA->pSecurityDescriptor = NULL;
1274 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1276 break;
1279 case 4:
1281 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1282 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1284 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1286 if (piW->pPrinterName) {
1287 piA->pPrinterName = ptr;
1288 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1289 ptr, outlen, NULL, NULL);
1290 ptr += len;
1291 outlen -= len;
1293 if (piW->pServerName) {
1294 piA->pServerName = ptr;
1295 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1296 ptr, outlen, NULL, NULL);
1297 ptr += len;
1298 outlen -= len;
1300 break;
1303 case 5:
1305 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1306 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1308 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1310 if (piW->pPrinterName) {
1311 piA->pPrinterName = ptr;
1312 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1313 ptr, outlen, NULL, NULL);
1314 ptr += len;
1315 outlen -= len;
1317 if (piW->pPortName) {
1318 piA->pPortName = ptr;
1319 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1320 ptr, outlen, NULL, NULL);
1321 ptr += len;
1322 outlen -= len;
1324 break;
1327 case 6: /* 6A and 6W are the same structure */
1328 break;
1330 case 7:
1332 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1333 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1335 TRACE("(%u) #%u\n", level, id);
1336 if (piW->pszObjectGUID) {
1337 piA->pszObjectGUID = ptr;
1338 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1339 ptr, outlen, NULL, NULL);
1340 ptr += len;
1341 outlen -= len;
1343 break;
1346 case 9:
1348 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1349 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1350 LPDEVMODEA dmA;
1352 TRACE("(%u) #%u\n", level, id);
1353 dmA = DEVMODEdupWtoA(piW->pDevMode);
1354 if (dmA) {
1355 /* align DEVMODEA to a DWORD boundary */
1356 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1357 ptr += len;
1358 outlen -= len;
1360 piA->pDevMode = (LPDEVMODEA) ptr;
1361 len = dmA->dmSize + dmA->dmDriverExtra;
1362 memcpy(ptr, dmA, len);
1363 HeapFree(GetProcessHeap(), 0, dmA);
1365 ptr += len;
1366 outlen -= len;
1369 break;
1372 default:
1373 FIXME("for level %u\n", level);
1375 pPrintersW += pi_sizeof[level];
1376 out += pi_sizeof[level];
1377 id++;
1381 /******************************************************************
1382 * convert_driverinfo_W_to_A [internal]
1385 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1386 DWORD level, DWORD outlen, DWORD numentries)
1388 DWORD id = 0;
1389 LPSTR ptr;
1390 INT len;
1392 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1394 len = di_sizeof[level] * numentries;
1395 ptr = (LPSTR) out + len;
1396 outlen -= len;
1398 /* copy the numbers of all PRINTER_INFO_* first */
1399 memcpy(out, pDriversW, len);
1401 #define COPY_STRING(fld) \
1402 { if (diW->fld){ \
1403 diA->fld = ptr; \
1404 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1405 ptr += len; outlen -= len;\
1407 #define COPY_MULTIZ_STRING(fld) \
1408 { LPWSTR p = diW->fld; if (p){ \
1409 diA->fld = ptr; \
1410 do {\
1411 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1412 ptr += len; outlen -= len; p += len;\
1414 while(len > 1 && outlen > 0); \
1417 while (id < numentries)
1419 switch (level)
1421 case 1:
1423 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1424 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1426 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1428 COPY_STRING(pName);
1429 break;
1431 case 2:
1433 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1434 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1436 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1438 COPY_STRING(pName);
1439 COPY_STRING(pEnvironment);
1440 COPY_STRING(pDriverPath);
1441 COPY_STRING(pDataFile);
1442 COPY_STRING(pConfigFile);
1443 break;
1445 case 3:
1447 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1448 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1450 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1452 COPY_STRING(pName);
1453 COPY_STRING(pEnvironment);
1454 COPY_STRING(pDriverPath);
1455 COPY_STRING(pDataFile);
1456 COPY_STRING(pConfigFile);
1457 COPY_STRING(pHelpFile);
1458 COPY_MULTIZ_STRING(pDependentFiles);
1459 COPY_STRING(pMonitorName);
1460 COPY_STRING(pDefaultDataType);
1461 break;
1463 case 4:
1465 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1466 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1468 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1470 COPY_STRING(pName);
1471 COPY_STRING(pEnvironment);
1472 COPY_STRING(pDriverPath);
1473 COPY_STRING(pDataFile);
1474 COPY_STRING(pConfigFile);
1475 COPY_STRING(pHelpFile);
1476 COPY_MULTIZ_STRING(pDependentFiles);
1477 COPY_STRING(pMonitorName);
1478 COPY_STRING(pDefaultDataType);
1479 COPY_MULTIZ_STRING(pszzPreviousNames);
1480 break;
1482 case 5:
1484 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1485 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1487 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1489 COPY_STRING(pName);
1490 COPY_STRING(pEnvironment);
1491 COPY_STRING(pDriverPath);
1492 COPY_STRING(pDataFile);
1493 COPY_STRING(pConfigFile);
1494 break;
1496 case 6:
1498 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1499 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1501 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1503 COPY_STRING(pName);
1504 COPY_STRING(pEnvironment);
1505 COPY_STRING(pDriverPath);
1506 COPY_STRING(pDataFile);
1507 COPY_STRING(pConfigFile);
1508 COPY_STRING(pHelpFile);
1509 COPY_MULTIZ_STRING(pDependentFiles);
1510 COPY_STRING(pMonitorName);
1511 COPY_STRING(pDefaultDataType);
1512 COPY_MULTIZ_STRING(pszzPreviousNames);
1513 COPY_STRING(pszMfgName);
1514 COPY_STRING(pszOEMUrl);
1515 COPY_STRING(pszHardwareID);
1516 COPY_STRING(pszProvider);
1517 break;
1519 case 8:
1521 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1522 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1524 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1526 COPY_STRING(pName);
1527 COPY_STRING(pEnvironment);
1528 COPY_STRING(pDriverPath);
1529 COPY_STRING(pDataFile);
1530 COPY_STRING(pConfigFile);
1531 COPY_STRING(pHelpFile);
1532 COPY_MULTIZ_STRING(pDependentFiles);
1533 COPY_STRING(pMonitorName);
1534 COPY_STRING(pDefaultDataType);
1535 COPY_MULTIZ_STRING(pszzPreviousNames);
1536 COPY_STRING(pszMfgName);
1537 COPY_STRING(pszOEMUrl);
1538 COPY_STRING(pszHardwareID);
1539 COPY_STRING(pszProvider);
1540 COPY_STRING(pszPrintProcessor);
1541 COPY_STRING(pszVendorSetup);
1542 COPY_MULTIZ_STRING(pszzColorProfiles);
1543 COPY_STRING(pszInfPath);
1544 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1545 break;
1549 default:
1550 FIXME("for level %u\n", level);
1553 pDriversW += di_sizeof[level];
1554 out += di_sizeof[level];
1555 id++;
1558 #undef COPY_STRING
1559 #undef COPY_MULTIZ_STRING
1563 /***********************************************************
1564 * PRINTER_INFO_2AtoW
1565 * Creates a unicode copy of PRINTER_INFO_2A on heap
1567 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1569 LPPRINTER_INFO_2W piW;
1570 UNICODE_STRING usBuffer;
1572 if(!piA) return NULL;
1573 piW = HeapAlloc(heap, 0, sizeof(*piW));
1574 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1576 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1577 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1578 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1579 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1580 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1581 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1582 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1583 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1584 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1585 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1586 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1587 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1588 return piW;
1591 /***********************************************************
1592 * FREE_PRINTER_INFO_2W
1593 * Free PRINTER_INFO_2W and all strings
1595 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1597 if(!piW) return;
1599 HeapFree(heap,0,piW->pServerName);
1600 HeapFree(heap,0,piW->pPrinterName);
1601 HeapFree(heap,0,piW->pShareName);
1602 HeapFree(heap,0,piW->pPortName);
1603 HeapFree(heap,0,piW->pDriverName);
1604 HeapFree(heap,0,piW->pComment);
1605 HeapFree(heap,0,piW->pLocation);
1606 HeapFree(heap,0,piW->pDevMode);
1607 HeapFree(heap,0,piW->pSepFile);
1608 HeapFree(heap,0,piW->pPrintProcessor);
1609 HeapFree(heap,0,piW->pDatatype);
1610 HeapFree(heap,0,piW->pParameters);
1611 HeapFree(heap,0,piW);
1612 return;
1615 /******************************************************************
1616 * DeviceCapabilities [WINSPOOL.@]
1617 * DeviceCapabilitiesA [WINSPOOL.@]
1620 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1621 LPSTR pOutput, LPDEVMODEA lpdm)
1623 INT ret;
1625 if (!GDI_CallDeviceCapabilities16)
1627 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1628 (LPCSTR)104 );
1629 if (!GDI_CallDeviceCapabilities16) return -1;
1631 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1633 /* If DC_PAPERSIZE map POINT16s to POINTs */
1634 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1635 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1636 POINT *pt = (POINT *)pOutput;
1637 INT i;
1638 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1639 for(i = 0; i < ret; i++, pt++)
1641 pt->x = tmp[i].x;
1642 pt->y = tmp[i].y;
1644 HeapFree( GetProcessHeap(), 0, tmp );
1646 return ret;
1650 /*****************************************************************************
1651 * DeviceCapabilitiesW [WINSPOOL.@]
1653 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1656 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1657 WORD fwCapability, LPWSTR pOutput,
1658 const DEVMODEW *pDevMode)
1660 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1661 LPSTR pDeviceA = strdupWtoA(pDevice);
1662 LPSTR pPortA = strdupWtoA(pPort);
1663 INT ret;
1665 if(pOutput && (fwCapability == DC_BINNAMES ||
1666 fwCapability == DC_FILEDEPENDENCIES ||
1667 fwCapability == DC_PAPERNAMES)) {
1668 /* These need A -> W translation */
1669 INT size = 0, i;
1670 LPSTR pOutputA;
1671 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1672 dmA);
1673 if(ret == -1)
1674 return ret;
1675 switch(fwCapability) {
1676 case DC_BINNAMES:
1677 size = 24;
1678 break;
1679 case DC_PAPERNAMES:
1680 case DC_FILEDEPENDENCIES:
1681 size = 64;
1682 break;
1684 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1685 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1686 dmA);
1687 for(i = 0; i < ret; i++)
1688 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1689 pOutput + (i * size), size);
1690 HeapFree(GetProcessHeap(), 0, pOutputA);
1691 } else {
1692 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1693 (LPSTR)pOutput, dmA);
1695 HeapFree(GetProcessHeap(),0,pPortA);
1696 HeapFree(GetProcessHeap(),0,pDeviceA);
1697 HeapFree(GetProcessHeap(),0,dmA);
1698 return ret;
1701 /******************************************************************
1702 * DocumentPropertiesA [WINSPOOL.@]
1704 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1706 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1707 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1708 LPDEVMODEA pDevModeInput,DWORD fMode )
1710 LPSTR lpName = pDeviceName;
1711 static CHAR port[] = "LPT1:";
1712 LONG ret;
1714 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1715 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1718 if(!pDeviceName) {
1719 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1720 if(!lpNameW) {
1721 ERR("no name from hPrinter?\n");
1722 SetLastError(ERROR_INVALID_HANDLE);
1723 return -1;
1725 lpName = strdupWtoA(lpNameW);
1728 if (!GDI_CallExtDeviceMode16)
1730 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1731 (LPCSTR)102 );
1732 if (!GDI_CallExtDeviceMode16) {
1733 ERR("No CallExtDeviceMode16?\n");
1734 return -1;
1737 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1738 pDevModeInput, NULL, fMode);
1740 if(!pDeviceName)
1741 HeapFree(GetProcessHeap(),0,lpName);
1742 return ret;
1746 /*****************************************************************************
1747 * DocumentPropertiesW (WINSPOOL.@)
1749 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1751 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1752 LPWSTR pDeviceName,
1753 LPDEVMODEW pDevModeOutput,
1754 LPDEVMODEW pDevModeInput, DWORD fMode)
1757 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1758 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1759 LPDEVMODEA pDevModeOutputA = NULL;
1760 LONG ret;
1762 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1763 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1764 fMode);
1765 if(pDevModeOutput) {
1766 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1767 if(ret < 0) return ret;
1768 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1770 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1771 pDevModeInputA, fMode);
1772 if(pDevModeOutput) {
1773 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1774 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1776 if(fMode == 0 && ret > 0)
1777 ret += (CCHDEVICENAME + CCHFORMNAME);
1778 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1779 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1780 return ret;
1783 /*****************************************************************************
1784 * IsValidDevmodeA [WINSPOOL.@]
1786 * Validate a DEVMODE structure and fix errors if possible.
1789 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1791 FIXME("(%p,%ld): stub\n", pDevMode, size);
1793 if(!pDevMode)
1794 return FALSE;
1796 return TRUE;
1799 /*****************************************************************************
1800 * IsValidDevmodeW [WINSPOOL.@]
1802 * Validate a DEVMODE structure and fix errors if possible.
1805 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1807 FIXME("(%p,%ld): stub\n", pDevMode, size);
1809 if(!pDevMode)
1810 return FALSE;
1812 return TRUE;
1815 /******************************************************************
1816 * OpenPrinterA [WINSPOOL.@]
1818 * See OpenPrinterW.
1821 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1822 LPPRINTER_DEFAULTSA pDefault)
1824 UNICODE_STRING lpPrinterNameW;
1825 UNICODE_STRING usBuffer;
1826 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1827 PWSTR pwstrPrinterNameW;
1828 BOOL ret;
1830 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1832 if(pDefault) {
1833 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1834 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1835 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1836 pDefaultW = &DefaultW;
1838 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1839 if(pDefault) {
1840 RtlFreeUnicodeString(&usBuffer);
1841 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1843 RtlFreeUnicodeString(&lpPrinterNameW);
1844 return ret;
1847 /******************************************************************
1848 * OpenPrinterW [WINSPOOL.@]
1850 * Open a Printer / Printserver or a Printer-Object
1852 * PARAMS
1853 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1854 * phPrinter [O] The resulting Handle is stored here
1855 * pDefault [I] PTR to Default Printer Settings or NULL
1857 * RETURNS
1858 * Success: TRUE
1859 * Failure: FALSE
1861 * NOTES
1862 * lpPrinterName is one of:
1863 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1864 *| Printer: "PrinterName"
1865 *| Printer-Object: "PrinterName,Job xxx"
1866 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1867 *| XcvPort: "Servername,XcvPort PortName"
1869 * BUGS
1870 *| Printer-Object not supported
1871 *| pDefaults is ignored
1874 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1877 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1878 if (pDefault) {
1879 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1880 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1883 if(!phPrinter) {
1884 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1885 SetLastError(ERROR_INVALID_PARAMETER);
1886 return FALSE;
1889 /* Get the unique handle of the printer or Printserver */
1890 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1891 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1892 return (*phPrinter != 0);
1895 /******************************************************************
1896 * AddMonitorA [WINSPOOL.@]
1898 * See AddMonitorW.
1901 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1903 LPWSTR nameW = NULL;
1904 INT len;
1905 BOOL res;
1906 LPMONITOR_INFO_2A mi2a;
1907 MONITOR_INFO_2W mi2w;
1909 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1910 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1911 debugstr_a(mi2a ? mi2a->pName : NULL),
1912 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1913 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1915 if (Level != 2) {
1916 SetLastError(ERROR_INVALID_LEVEL);
1917 return FALSE;
1920 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1921 if (mi2a == NULL) {
1922 return FALSE;
1925 if (pName) {
1926 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1927 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1928 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1931 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1932 if (mi2a->pName) {
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1934 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1937 if (mi2a->pEnvironment) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1939 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1942 if (mi2a->pDLLName) {
1943 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1944 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1945 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1948 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1950 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1951 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1952 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1954 HeapFree(GetProcessHeap(), 0, nameW);
1955 return (res);
1958 /******************************************************************************
1959 * AddMonitorW [WINSPOOL.@]
1961 * Install a Printmonitor
1963 * PARAMS
1964 * pName [I] Servername or NULL (local Computer)
1965 * Level [I] Structure-Level (Must be 2)
1966 * pMonitors [I] PTR to MONITOR_INFO_2
1968 * RETURNS
1969 * Success: TRUE
1970 * Failure: FALSE
1972 * NOTES
1973 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1976 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1978 LPMONITOR_INFO_2W mi2w;
1980 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1981 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1982 debugstr_w(mi2w ? mi2w->pName : NULL),
1983 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1984 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1986 if ((backend == NULL) && !load_backend()) return FALSE;
1988 if (Level != 2) {
1989 SetLastError(ERROR_INVALID_LEVEL);
1990 return FALSE;
1993 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1994 if (mi2w == NULL) {
1995 return FALSE;
1998 return backend->fpAddMonitor(pName, Level, pMonitors);
2001 /******************************************************************
2002 * DeletePrinterDriverA [WINSPOOL.@]
2005 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2007 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2010 /******************************************************************
2011 * DeletePrinterDriverW [WINSPOOL.@]
2014 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2016 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2019 /******************************************************************
2020 * DeleteMonitorA [WINSPOOL.@]
2022 * See DeleteMonitorW.
2025 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2027 LPWSTR nameW = NULL;
2028 LPWSTR EnvironmentW = NULL;
2029 LPWSTR MonitorNameW = NULL;
2030 BOOL res;
2031 INT len;
2033 if (pName) {
2034 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2035 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2036 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2039 if (pEnvironment) {
2040 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2041 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2044 if (pMonitorName) {
2045 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2046 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2047 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2050 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2052 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2053 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2054 HeapFree(GetProcessHeap(), 0, nameW);
2055 return (res);
2058 /******************************************************************
2059 * DeleteMonitorW [WINSPOOL.@]
2061 * Delete a specific Printmonitor from a Printing-Environment
2063 * PARAMS
2064 * pName [I] Servername or NULL (local Computer)
2065 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2066 * pMonitorName [I] Name of the Monitor, that should be deleted
2068 * RETURNS
2069 * Success: TRUE
2070 * Failure: FALSE
2072 * NOTES
2073 * pEnvironment is ignored in Windows for the local Computer.
2076 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2079 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2080 debugstr_w(pMonitorName));
2082 if ((backend == NULL) && !load_backend()) return FALSE;
2084 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2088 /******************************************************************
2089 * DeletePortA [WINSPOOL.@]
2091 * See DeletePortW.
2094 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2096 LPWSTR nameW = NULL;
2097 LPWSTR portW = NULL;
2098 INT len;
2099 DWORD res;
2101 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2103 /* convert servername to unicode */
2104 if (pName) {
2105 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2106 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2107 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2110 /* convert portname to unicode */
2111 if (pPortName) {
2112 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2113 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2114 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2117 res = DeletePortW(nameW, hWnd, portW);
2118 HeapFree(GetProcessHeap(), 0, nameW);
2119 HeapFree(GetProcessHeap(), 0, portW);
2120 return res;
2123 /******************************************************************
2124 * DeletePortW [WINSPOOL.@]
2126 * Delete a specific Port
2128 * PARAMS
2129 * pName [I] Servername or NULL (local Computer)
2130 * hWnd [I] Handle to parent Window for the Dialog-Box
2131 * pPortName [I] Name of the Port, that should be deleted
2133 * RETURNS
2134 * Success: TRUE
2135 * Failure: FALSE
2138 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2140 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2142 if ((backend == NULL) && !load_backend()) return FALSE;
2144 if (!pPortName) {
2145 SetLastError(RPC_X_NULL_REF_POINTER);
2146 return FALSE;
2149 return backend->fpDeletePort(pName, hWnd, pPortName);
2152 /******************************************************************************
2153 * SetPrinterW [WINSPOOL.@]
2155 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2157 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2158 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2159 return FALSE;
2162 /******************************************************************************
2163 * WritePrinter [WINSPOOL.@]
2165 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2167 opened_printer_t *printer;
2168 BOOL ret = FALSE;
2170 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2172 EnterCriticalSection(&printer_handles_cs);
2173 printer = get_opened_printer(hPrinter);
2174 if(!printer)
2176 SetLastError(ERROR_INVALID_HANDLE);
2177 goto end;
2180 if(!printer->doc)
2182 SetLastError(ERROR_SPL_NO_STARTDOC);
2183 goto end;
2186 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2187 end:
2188 LeaveCriticalSection(&printer_handles_cs);
2189 return ret;
2192 /*****************************************************************************
2193 * AddFormA [WINSPOOL.@]
2195 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2197 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2198 return 1;
2201 /*****************************************************************************
2202 * AddFormW [WINSPOOL.@]
2204 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2206 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2207 return 1;
2210 /*****************************************************************************
2211 * AddJobA [WINSPOOL.@]
2213 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2215 BOOL ret;
2216 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2217 DWORD needed;
2219 if(Level != 1) {
2220 SetLastError(ERROR_INVALID_LEVEL);
2221 return FALSE;
2224 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2226 if(ret) {
2227 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2228 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2229 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2230 if(*pcbNeeded > cbBuf) {
2231 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2232 ret = FALSE;
2233 } else {
2234 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2235 addjobA->JobId = addjobW->JobId;
2236 addjobA->Path = (char *)(addjobA + 1);
2237 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2240 return ret;
2243 /*****************************************************************************
2244 * AddJobW [WINSPOOL.@]
2246 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2248 opened_printer_t *printer;
2249 job_t *job;
2250 BOOL ret = FALSE;
2251 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2252 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2253 WCHAR path[MAX_PATH], filename[MAX_PATH];
2254 DWORD len;
2255 ADDJOB_INFO_1W *addjob;
2257 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2259 EnterCriticalSection(&printer_handles_cs);
2261 printer = get_opened_printer(hPrinter);
2263 if(!printer) {
2264 SetLastError(ERROR_INVALID_HANDLE);
2265 goto end;
2268 if(Level != 1) {
2269 SetLastError(ERROR_INVALID_LEVEL);
2270 goto end;
2273 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2274 if(!job)
2275 goto end;
2277 job->job_id = InterlockedIncrement(&next_job_id);
2279 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2280 if(path[len - 1] != '\\')
2281 path[len++] = '\\';
2282 memcpy(path + len, spool_path, sizeof(spool_path));
2283 sprintfW(filename, fmtW, path, job->job_id);
2285 len = strlenW(filename);
2286 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2287 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2288 job->document_title = strdupW(default_doc_title);
2289 job->printer_name = strdupW(printer->name);
2290 job->devmode = NULL;
2291 list_add_tail(&printer->queue->jobs, &job->entry);
2293 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2294 if(*pcbNeeded <= cbBuf) {
2295 addjob = (ADDJOB_INFO_1W*)pData;
2296 addjob->JobId = job->job_id;
2297 addjob->Path = (WCHAR *)(addjob + 1);
2298 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2299 ret = TRUE;
2300 } else
2301 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2303 end:
2304 LeaveCriticalSection(&printer_handles_cs);
2305 return ret;
2308 /*****************************************************************************
2309 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2311 * Return the PATH for the Print-Processors
2313 * See GetPrintProcessorDirectoryW.
2317 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2318 DWORD level, LPBYTE Info,
2319 DWORD cbBuf, LPDWORD pcbNeeded)
2321 LPWSTR serverW = NULL;
2322 LPWSTR envW = NULL;
2323 BOOL ret;
2324 INT len;
2326 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2327 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2330 if (server) {
2331 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2332 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2333 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2336 if (env) {
2337 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2338 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2339 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2342 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2343 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2345 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2346 cbBuf, pcbNeeded);
2348 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2349 cbBuf, NULL, NULL) > 0;
2352 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2353 HeapFree(GetProcessHeap(), 0, envW);
2354 HeapFree(GetProcessHeap(), 0, serverW);
2355 return ret;
2358 /*****************************************************************************
2359 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2361 * Return the PATH for the Print-Processors
2363 * PARAMS
2364 * server [I] Servername (NT only) or NULL (local Computer)
2365 * env [I] Printing-Environment (see below) or NULL (Default)
2366 * level [I] Structure-Level (must be 1)
2367 * Info [O] PTR to Buffer that receives the Result
2368 * cbBuf [I] Size of Buffer at "Info"
2369 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2370 * required for the Buffer at "Info"
2372 * RETURNS
2373 * Success: TRUE and in pcbNeeded the Bytes used in Info
2374 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2375 * if cbBuf is too small
2377 * Native Values returned in Info on Success:
2378 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2379 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2380 *| win9x(Windows 4.0): "%winsysdir%"
2382 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2384 * BUGS
2385 * Only NULL or "" is supported for server
2388 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2389 DWORD level, LPBYTE Info,
2390 DWORD cbBuf, LPDWORD pcbNeeded)
2393 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2394 Info, cbBuf, pcbNeeded);
2396 if ((backend == NULL) && !load_backend()) return FALSE;
2398 if (level != 1) {
2399 /* (Level != 1) is ignored in win9x */
2400 SetLastError(ERROR_INVALID_LEVEL);
2401 return FALSE;
2404 if (pcbNeeded == NULL) {
2405 /* (pcbNeeded == NULL) is ignored in win9x */
2406 SetLastError(RPC_X_NULL_REF_POINTER);
2407 return FALSE;
2410 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2413 /*****************************************************************************
2414 * WINSPOOL_OpenDriverReg [internal]
2416 * opens the registry for the printer drivers depending on the given input
2417 * variable pEnvironment
2419 * RETURNS:
2420 * the opened hkey on success
2421 * NULL on error
2423 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2425 HKEY retval = NULL;
2426 LPWSTR buffer;
2427 const printenv_t * env;
2429 TRACE("(%s)\n", debugstr_w(pEnvironment));
2431 env = validate_envW(pEnvironment);
2432 if (!env) return NULL;
2434 buffer = HeapAlloc( GetProcessHeap(), 0,
2435 (strlenW(DriversW) + strlenW(env->envname) +
2436 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2437 if(buffer) {
2438 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2439 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2440 HeapFree(GetProcessHeap(), 0, buffer);
2442 return retval;
2445 /*****************************************************************************
2446 * set_devices_and_printerports [internal]
2448 * set the [Devices] and [PrinterPorts] entries for a printer.
2451 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2453 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2454 WCHAR *devline;
2455 HKEY hkey;
2457 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2459 /* FIXME: the driver must change to "winspool" */
2460 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2461 if (devline) {
2462 lstrcpyW(devline, driver_nt);
2463 lstrcatW(devline, commaW);
2464 lstrcatW(devline, pi->pPortName);
2466 TRACE("using %s\n", debugstr_w(devline));
2467 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2468 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2469 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2470 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2471 RegCloseKey(hkey);
2474 lstrcatW(devline, timeout_15_45);
2475 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2476 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2477 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2478 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2479 RegCloseKey(hkey);
2481 HeapFree(GetProcessHeap(), 0, devline);
2485 /*****************************************************************************
2486 * AddPrinterW [WINSPOOL.@]
2488 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2490 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2491 LPDEVMODEA dmA;
2492 LPDEVMODEW dmW;
2493 HANDLE retval;
2494 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2495 LONG size;
2496 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2497 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2498 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2499 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2500 statusW[] = {'S','t','a','t','u','s',0},
2501 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2503 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2505 if(pName != NULL) {
2506 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2507 SetLastError(ERROR_INVALID_PARAMETER);
2508 return 0;
2510 if(Level != 2) {
2511 ERR("Level = %d, unsupported!\n", Level);
2512 SetLastError(ERROR_INVALID_LEVEL);
2513 return 0;
2515 if(!pPrinter) {
2516 SetLastError(ERROR_INVALID_PARAMETER);
2517 return 0;
2519 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2520 ERROR_SUCCESS) {
2521 ERR("Can't create Printers key\n");
2522 return 0;
2524 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2525 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2526 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2527 RegCloseKey(hkeyPrinter);
2528 RegCloseKey(hkeyPrinters);
2529 return 0;
2531 RegCloseKey(hkeyPrinter);
2533 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2534 if(!hkeyDrivers) {
2535 ERR("Can't create Drivers key\n");
2536 RegCloseKey(hkeyPrinters);
2537 return 0;
2539 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2540 ERROR_SUCCESS) {
2541 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2542 RegCloseKey(hkeyPrinters);
2543 RegCloseKey(hkeyDrivers);
2544 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2545 return 0;
2547 RegCloseKey(hkeyDriver);
2548 RegCloseKey(hkeyDrivers);
2550 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2551 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2552 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2553 RegCloseKey(hkeyPrinters);
2554 return 0;
2557 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2558 ERROR_SUCCESS) {
2559 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2560 SetLastError(ERROR_INVALID_PRINTER_NAME);
2561 RegCloseKey(hkeyPrinters);
2562 return 0;
2565 set_devices_and_printerports(pi);
2566 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2567 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2568 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2570 /* See if we can load the driver. We may need the devmode structure anyway
2572 * FIXME:
2573 * Note that DocumentPropertiesW will briefly try to open the printer we
2574 * just create to find a DEVMODEA struct (it will use the WINEPS default
2575 * one in case it is not there, so we are ok).
2577 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2579 if(size < 0) {
2580 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2581 size = sizeof(DEVMODEW);
2583 if(pi->pDevMode)
2584 dmW = pi->pDevMode;
2585 else
2587 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2588 dmW->dmSize = size;
2589 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2591 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2592 HeapFree(GetProcessHeap(),0,dmW);
2593 dmW=NULL;
2595 else
2597 /* set devmode to printer name */
2598 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2602 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2603 and we support these drivers. NT writes DEVMODEW so somehow
2604 we'll need to distinguish between these when we support NT
2605 drivers */
2606 if (dmW)
2608 dmA = DEVMODEdupWtoA(dmW);
2609 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2610 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2611 HeapFree(GetProcessHeap(), 0, dmA);
2612 if(!pi->pDevMode)
2613 HeapFree(GetProcessHeap(), 0, dmW);
2615 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2616 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2617 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2618 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2620 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2621 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2622 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2623 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2624 (LPBYTE)&pi->Priority, sizeof(DWORD));
2625 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2626 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2627 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2628 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2629 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2630 (LPBYTE)&pi->Status, sizeof(DWORD));
2631 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2632 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2634 RegCloseKey(hkeyPrinter);
2635 RegCloseKey(hkeyPrinters);
2636 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2637 ERR("OpenPrinter failing\n");
2638 return 0;
2640 return retval;
2643 /*****************************************************************************
2644 * AddPrinterA [WINSPOOL.@]
2646 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2648 UNICODE_STRING pNameW;
2649 PWSTR pwstrNameW;
2650 PRINTER_INFO_2W *piW;
2651 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2652 HANDLE ret;
2654 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2655 if(Level != 2) {
2656 ERR("Level = %d, unsupported!\n", Level);
2657 SetLastError(ERROR_INVALID_LEVEL);
2658 return 0;
2660 pwstrNameW = asciitounicode(&pNameW,pName);
2661 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2663 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2665 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2666 RtlFreeUnicodeString(&pNameW);
2667 return ret;
2671 /*****************************************************************************
2672 * ClosePrinter [WINSPOOL.@]
2674 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2676 UINT_PTR i = (UINT_PTR)hPrinter;
2677 opened_printer_t *printer = NULL;
2678 BOOL ret = FALSE;
2680 TRACE("(%p)\n", hPrinter);
2682 EnterCriticalSection(&printer_handles_cs);
2684 if ((i > 0) && (i <= nb_printer_handles))
2685 printer = printer_handles[i - 1];
2688 if(printer)
2690 struct list *cursor, *cursor2;
2692 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2694 if (printer->backend_printer) {
2695 backend->fpClosePrinter(printer->backend_printer);
2698 if(printer->doc)
2699 EndDocPrinter(hPrinter);
2701 if(InterlockedDecrement(&printer->queue->ref) == 0)
2703 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2705 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2706 ScheduleJob(hPrinter, job->job_id);
2708 HeapFree(GetProcessHeap(), 0, printer->queue);
2711 HeapFree(GetProcessHeap(), 0, printer->printername);
2712 HeapFree(GetProcessHeap(), 0, printer->name);
2713 HeapFree(GetProcessHeap(), 0, printer);
2714 printer_handles[i - 1] = NULL;
2715 ret = TRUE;
2717 LeaveCriticalSection(&printer_handles_cs);
2718 return ret;
2721 /*****************************************************************************
2722 * DeleteFormA [WINSPOOL.@]
2724 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2726 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2727 return 1;
2730 /*****************************************************************************
2731 * DeleteFormW [WINSPOOL.@]
2733 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2735 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2736 return 1;
2739 /*****************************************************************************
2740 * DeletePrinter [WINSPOOL.@]
2742 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2744 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2745 HKEY hkeyPrinters, hkey;
2747 if(!lpNameW) {
2748 SetLastError(ERROR_INVALID_HANDLE);
2749 return FALSE;
2751 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2752 RegDeleteTreeW(hkeyPrinters, lpNameW);
2753 RegCloseKey(hkeyPrinters);
2755 WriteProfileStringW(devicesW, lpNameW, NULL);
2756 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2758 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2759 RegDeleteValueW(hkey, lpNameW);
2760 RegCloseKey(hkey);
2763 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2764 RegDeleteValueW(hkey, lpNameW);
2765 RegCloseKey(hkey);
2767 return TRUE;
2770 /*****************************************************************************
2771 * SetPrinterA [WINSPOOL.@]
2773 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2774 DWORD Command)
2776 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2777 return FALSE;
2780 /*****************************************************************************
2781 * SetJobA [WINSPOOL.@]
2783 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2784 LPBYTE pJob, DWORD Command)
2786 BOOL ret;
2787 LPBYTE JobW;
2788 UNICODE_STRING usBuffer;
2790 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2792 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2793 are all ignored by SetJob, so we don't bother copying them */
2794 switch(Level)
2796 case 0:
2797 JobW = NULL;
2798 break;
2799 case 1:
2801 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2802 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2804 JobW = (LPBYTE)info1W;
2805 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2806 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2807 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2808 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2809 info1W->Status = info1A->Status;
2810 info1W->Priority = info1A->Priority;
2811 info1W->Position = info1A->Position;
2812 info1W->PagesPrinted = info1A->PagesPrinted;
2813 break;
2815 case 2:
2817 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2818 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2820 JobW = (LPBYTE)info2W;
2821 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2822 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2823 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2824 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2825 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2826 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2827 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2828 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2829 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2830 info2W->Status = info2A->Status;
2831 info2W->Priority = info2A->Priority;
2832 info2W->Position = info2A->Position;
2833 info2W->StartTime = info2A->StartTime;
2834 info2W->UntilTime = info2A->UntilTime;
2835 info2W->PagesPrinted = info2A->PagesPrinted;
2836 break;
2838 case 3:
2839 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2840 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2841 break;
2842 default:
2843 SetLastError(ERROR_INVALID_LEVEL);
2844 return FALSE;
2847 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2849 switch(Level)
2851 case 1:
2853 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2854 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2855 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2856 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2857 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2858 break;
2860 case 2:
2862 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2863 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2864 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2865 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2866 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2867 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2868 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2869 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2870 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2871 break;
2874 HeapFree(GetProcessHeap(), 0, JobW);
2876 return ret;
2879 /*****************************************************************************
2880 * SetJobW [WINSPOOL.@]
2882 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2883 LPBYTE pJob, DWORD Command)
2885 BOOL ret = FALSE;
2886 job_t *job;
2887 DWORD size;
2889 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2890 FIXME("Ignoring everything other than document title\n");
2892 EnterCriticalSection(&printer_handles_cs);
2893 job = get_job(hPrinter, JobId);
2894 if(!job)
2895 goto end;
2897 switch(Level)
2899 case 0:
2900 break;
2901 case 1:
2903 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2904 HeapFree(GetProcessHeap(), 0, job->document_title);
2905 job->document_title = strdupW(info1->pDocument);
2906 break;
2908 case 2:
2910 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2911 HeapFree(GetProcessHeap(), 0, job->document_title);
2912 job->document_title = strdupW(info2->pDocument);
2913 HeapFree(GetProcessHeap(), 0, job->devmode);
2914 if (info2->pDevMode)
2916 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2917 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2918 memcpy(job->devmode, info2->pDevMode, size);
2920 else
2921 job->devmode = NULL;
2922 break;
2924 case 3:
2925 break;
2926 default:
2927 SetLastError(ERROR_INVALID_LEVEL);
2928 goto end;
2930 ret = TRUE;
2931 end:
2932 LeaveCriticalSection(&printer_handles_cs);
2933 return ret;
2936 /*****************************************************************************
2937 * EndDocPrinter [WINSPOOL.@]
2939 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2941 opened_printer_t *printer;
2942 BOOL ret = FALSE;
2943 TRACE("(%p)\n", hPrinter);
2945 EnterCriticalSection(&printer_handles_cs);
2947 printer = get_opened_printer(hPrinter);
2948 if(!printer)
2950 SetLastError(ERROR_INVALID_HANDLE);
2951 goto end;
2954 if(!printer->doc)
2956 SetLastError(ERROR_SPL_NO_STARTDOC);
2957 goto end;
2960 CloseHandle(printer->doc->hf);
2961 ScheduleJob(hPrinter, printer->doc->job_id);
2962 HeapFree(GetProcessHeap(), 0, printer->doc);
2963 printer->doc = NULL;
2964 ret = TRUE;
2965 end:
2966 LeaveCriticalSection(&printer_handles_cs);
2967 return ret;
2970 /*****************************************************************************
2971 * EndPagePrinter [WINSPOOL.@]
2973 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2975 FIXME("(%p): stub\n", hPrinter);
2976 return TRUE;
2979 /*****************************************************************************
2980 * StartDocPrinterA [WINSPOOL.@]
2982 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2984 UNICODE_STRING usBuffer;
2985 DOC_INFO_2W doc2W;
2986 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2987 DWORD ret;
2989 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2990 or one (DOC_INFO_3) extra DWORDs */
2992 switch(Level) {
2993 case 2:
2994 doc2W.JobId = doc2->JobId;
2995 /* fall through */
2996 case 3:
2997 doc2W.dwMode = doc2->dwMode;
2998 /* fall through */
2999 case 1:
3000 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3001 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3002 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3003 break;
3005 default:
3006 SetLastError(ERROR_INVALID_LEVEL);
3007 return FALSE;
3010 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3012 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3013 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3014 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3016 return ret;
3019 /*****************************************************************************
3020 * StartDocPrinterW [WINSPOOL.@]
3022 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3024 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3025 opened_printer_t *printer;
3026 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3027 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3028 JOB_INFO_1W job_info;
3029 DWORD needed, ret = 0;
3030 HANDLE hf;
3031 WCHAR *filename;
3032 job_t *job;
3034 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3035 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3036 debugstr_w(doc->pDatatype));
3038 if(Level < 1 || Level > 3)
3040 SetLastError(ERROR_INVALID_LEVEL);
3041 return 0;
3044 EnterCriticalSection(&printer_handles_cs);
3045 printer = get_opened_printer(hPrinter);
3046 if(!printer)
3048 SetLastError(ERROR_INVALID_HANDLE);
3049 goto end;
3052 if(printer->doc)
3054 SetLastError(ERROR_INVALID_PRINTER_STATE);
3055 goto end;
3058 /* Even if we're printing to a file we still add a print job, we'll
3059 just ignore the spool file name */
3061 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3063 ERR("AddJob failed gle %u\n", GetLastError());
3064 goto end;
3067 /* use pOutputFile only, when it is a real filename */
3068 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3069 filename = doc->pOutputFile;
3070 else
3071 filename = addjob->Path;
3073 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3074 if(hf == INVALID_HANDLE_VALUE)
3075 goto end;
3077 memset(&job_info, 0, sizeof(job_info));
3078 job_info.pDocument = doc->pDocName;
3079 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3081 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3082 printer->doc->hf = hf;
3083 ret = printer->doc->job_id = addjob->JobId;
3084 job = get_job(hPrinter, ret);
3085 job->portname = strdupW(doc->pOutputFile);
3087 end:
3088 LeaveCriticalSection(&printer_handles_cs);
3090 return ret;
3093 /*****************************************************************************
3094 * StartPagePrinter [WINSPOOL.@]
3096 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3098 FIXME("(%p): stub\n", hPrinter);
3099 return TRUE;
3102 /*****************************************************************************
3103 * GetFormA [WINSPOOL.@]
3105 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3106 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3108 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3109 Level,pForm,cbBuf,pcbNeeded);
3110 return FALSE;
3113 /*****************************************************************************
3114 * GetFormW [WINSPOOL.@]
3116 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3117 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3119 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3120 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3121 return FALSE;
3124 /*****************************************************************************
3125 * SetFormA [WINSPOOL.@]
3127 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3128 LPBYTE pForm)
3130 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3131 return FALSE;
3134 /*****************************************************************************
3135 * SetFormW [WINSPOOL.@]
3137 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3138 LPBYTE pForm)
3140 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3141 return FALSE;
3144 /*****************************************************************************
3145 * ReadPrinter [WINSPOOL.@]
3147 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3148 LPDWORD pNoBytesRead)
3150 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3151 return FALSE;
3154 /*****************************************************************************
3155 * ResetPrinterA [WINSPOOL.@]
3157 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3159 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3160 return FALSE;
3163 /*****************************************************************************
3164 * ResetPrinterW [WINSPOOL.@]
3166 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3168 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3169 return FALSE;
3172 /*****************************************************************************
3173 * WINSPOOL_GetDWORDFromReg
3175 * Return DWORD associated with ValueName from hkey.
3177 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3179 DWORD sz = sizeof(DWORD), type, value = 0;
3180 LONG ret;
3182 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3184 if(ret != ERROR_SUCCESS) {
3185 WARN("Got ret = %d on name %s\n", ret, ValueName);
3186 return 0;
3188 if(type != REG_DWORD) {
3189 ERR("Got type %d\n", type);
3190 return 0;
3192 return value;
3196 /*****************************************************************************
3197 * get_filename_from_reg [internal]
3199 * Get ValueName from hkey storing result in out
3200 * when the Value in the registry has only a filename, use driverdir as prefix
3201 * outlen is space left in out
3202 * String is stored either as unicode or ascii
3206 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3207 LPBYTE out, DWORD outlen, LPDWORD needed)
3209 WCHAR filename[MAX_PATH];
3210 DWORD size;
3211 DWORD type;
3212 LONG ret;
3213 LPWSTR buffer = filename;
3214 LPWSTR ptr;
3216 *needed = 0;
3217 size = sizeof(filename);
3218 buffer[0] = '\0';
3219 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3220 if (ret == ERROR_MORE_DATA) {
3221 TRACE("need dynamic buffer: %u\n", size);
3222 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3223 if (!buffer) {
3224 /* No Memory is bad */
3225 return FALSE;
3227 buffer[0] = '\0';
3228 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3231 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3232 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3233 return FALSE;
3236 ptr = buffer;
3237 while (ptr) {
3238 /* do we have a full path ? */
3239 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3240 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3242 if (!ret) {
3243 /* we must build the full Path */
3244 *needed += dirlen;
3245 if ((out) && (outlen > dirlen)) {
3246 lstrcpyW((LPWSTR)out, driverdir);
3247 out += dirlen;
3248 outlen -= dirlen;
3250 else
3251 out = NULL;
3254 /* write the filename */
3255 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3256 if ((out) && (outlen >= size)) {
3257 lstrcpyW((LPWSTR)out, ptr);
3258 out += size;
3259 outlen -= size;
3261 else
3262 out = NULL;
3263 *needed += size;
3264 ptr += lstrlenW(ptr)+1;
3265 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3268 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3270 /* write the multisz-termination */
3271 if (type == REG_MULTI_SZ) {
3272 size = sizeof(WCHAR);
3274 *needed += size;
3275 if (out && (outlen >= size)) {
3276 memset (out, 0, size);
3279 return TRUE;
3282 /*****************************************************************************
3283 * WINSPOOL_GetStringFromReg
3285 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3286 * String is stored as unicode.
3288 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3289 DWORD buflen, DWORD *needed)
3291 DWORD sz = buflen, type;
3292 LONG ret;
3294 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3295 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3296 WARN("Got ret = %d\n", ret);
3297 *needed = 0;
3298 return FALSE;
3300 /* add space for terminating '\0' */
3301 sz += sizeof(WCHAR);
3302 *needed = sz;
3304 if (ptr)
3305 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3307 return TRUE;
3310 /*****************************************************************************
3311 * WINSPOOL_GetDefaultDevMode
3313 * Get a default DevMode values for wineps.
3314 * FIXME - use ppd.
3317 static void WINSPOOL_GetDefaultDevMode(
3318 LPBYTE ptr,
3319 DWORD buflen, DWORD *needed)
3321 DEVMODEW dm;
3322 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3324 /* fill default DEVMODE - should be read from ppd... */
3325 ZeroMemory( &dm, sizeof(dm) );
3326 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3327 dm.dmSpecVersion = DM_SPECVERSION;
3328 dm.dmDriverVersion = 1;
3329 dm.dmSize = sizeof(DEVMODEW);
3330 dm.dmDriverExtra = 0;
3331 dm.dmFields =
3332 DM_ORIENTATION | DM_PAPERSIZE |
3333 DM_PAPERLENGTH | DM_PAPERWIDTH |
3334 DM_SCALE |
3335 DM_COPIES |
3336 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3337 DM_YRESOLUTION | DM_TTOPTION;
3339 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3340 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3341 dm.u1.s1.dmPaperLength = 2970;
3342 dm.u1.s1.dmPaperWidth = 2100;
3344 dm.u1.s1.dmScale = 100;
3345 dm.u1.s1.dmCopies = 1;
3346 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3347 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3348 /* dm.dmColor */
3349 /* dm.dmDuplex */
3350 dm.dmYResolution = 300; /* 300dpi */
3351 dm.dmTTOption = DMTT_BITMAP;
3352 /* dm.dmCollate */
3353 /* dm.dmFormName */
3354 /* dm.dmLogPixels */
3355 /* dm.dmBitsPerPel */
3356 /* dm.dmPelsWidth */
3357 /* dm.dmPelsHeight */
3358 /* dm.u2.dmDisplayFlags */
3359 /* dm.dmDisplayFrequency */
3360 /* dm.dmICMMethod */
3361 /* dm.dmICMIntent */
3362 /* dm.dmMediaType */
3363 /* dm.dmDitherType */
3364 /* dm.dmReserved1 */
3365 /* dm.dmReserved2 */
3366 /* dm.dmPanningWidth */
3367 /* dm.dmPanningHeight */
3369 if(buflen >= sizeof(DEVMODEW))
3370 memcpy(ptr, &dm, sizeof(DEVMODEW));
3371 *needed = sizeof(DEVMODEW);
3374 /*****************************************************************************
3375 * WINSPOOL_GetDevModeFromReg
3377 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3378 * DevMode is stored either as unicode or ascii.
3380 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3381 LPBYTE ptr,
3382 DWORD buflen, DWORD *needed)
3384 DWORD sz = buflen, type;
3385 LONG ret;
3387 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3388 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3389 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3390 if (sz < sizeof(DEVMODEA))
3392 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3393 return FALSE;
3395 /* ensures that dmSize is not erratically bogus if registry is invalid */
3396 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3397 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3398 sz += (CCHDEVICENAME + CCHFORMNAME);
3399 if (ptr && (buflen >= sz)) {
3400 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3401 memcpy(ptr, dmW, sz);
3402 HeapFree(GetProcessHeap(),0,dmW);
3404 *needed = sz;
3405 return TRUE;
3408 /*********************************************************************
3409 * WINSPOOL_GetPrinter_1
3411 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3413 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3414 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3416 DWORD size, left = cbBuf;
3417 BOOL space = (cbBuf > 0);
3418 LPBYTE ptr = buf;
3420 *pcbNeeded = 0;
3422 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3423 if(space && size <= left) {
3424 pi1->pName = (LPWSTR)ptr;
3425 ptr += size;
3426 left -= size;
3427 } else
3428 space = FALSE;
3429 *pcbNeeded += size;
3432 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3433 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3434 if(space && size <= left) {
3435 pi1->pDescription = (LPWSTR)ptr;
3436 ptr += size;
3437 left -= size;
3438 } else
3439 space = FALSE;
3440 *pcbNeeded += size;
3443 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3444 if(space && size <= left) {
3445 pi1->pComment = (LPWSTR)ptr;
3446 ptr += size;
3447 left -= size;
3448 } else
3449 space = FALSE;
3450 *pcbNeeded += size;
3453 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3455 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3456 memset(pi1, 0, sizeof(*pi1));
3458 return space;
3460 /*********************************************************************
3461 * WINSPOOL_GetPrinter_2
3463 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3465 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3466 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3468 DWORD size, left = cbBuf;
3469 BOOL space = (cbBuf > 0);
3470 LPBYTE ptr = buf;
3472 *pcbNeeded = 0;
3474 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3475 if(space && size <= left) {
3476 pi2->pPrinterName = (LPWSTR)ptr;
3477 ptr += size;
3478 left -= size;
3479 } else
3480 space = FALSE;
3481 *pcbNeeded += size;
3483 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3484 if(space && size <= left) {
3485 pi2->pShareName = (LPWSTR)ptr;
3486 ptr += size;
3487 left -= size;
3488 } else
3489 space = FALSE;
3490 *pcbNeeded += size;
3492 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3493 if(space && size <= left) {
3494 pi2->pPortName = (LPWSTR)ptr;
3495 ptr += size;
3496 left -= size;
3497 } else
3498 space = FALSE;
3499 *pcbNeeded += size;
3501 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3502 if(space && size <= left) {
3503 pi2->pDriverName = (LPWSTR)ptr;
3504 ptr += size;
3505 left -= size;
3506 } else
3507 space = FALSE;
3508 *pcbNeeded += size;
3510 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3511 if(space && size <= left) {
3512 pi2->pComment = (LPWSTR)ptr;
3513 ptr += size;
3514 left -= size;
3515 } else
3516 space = FALSE;
3517 *pcbNeeded += size;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3520 if(space && size <= left) {
3521 pi2->pLocation = (LPWSTR)ptr;
3522 ptr += size;
3523 left -= size;
3524 } else
3525 space = FALSE;
3526 *pcbNeeded += size;
3528 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3529 if(space && size <= left) {
3530 pi2->pDevMode = (LPDEVMODEW)ptr;
3531 ptr += size;
3532 left -= size;
3533 } else
3534 space = FALSE;
3535 *pcbNeeded += size;
3537 else
3539 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3540 if(space && size <= left) {
3541 pi2->pDevMode = (LPDEVMODEW)ptr;
3542 ptr += size;
3543 left -= size;
3544 } else
3545 space = FALSE;
3546 *pcbNeeded += size;
3548 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3549 if(space && size <= left) {
3550 pi2->pSepFile = (LPWSTR)ptr;
3551 ptr += size;
3552 left -= size;
3553 } else
3554 space = FALSE;
3555 *pcbNeeded += size;
3557 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3558 if(space && size <= left) {
3559 pi2->pPrintProcessor = (LPWSTR)ptr;
3560 ptr += size;
3561 left -= size;
3562 } else
3563 space = FALSE;
3564 *pcbNeeded += size;
3566 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3567 if(space && size <= left) {
3568 pi2->pDatatype = (LPWSTR)ptr;
3569 ptr += size;
3570 left -= size;
3571 } else
3572 space = FALSE;
3573 *pcbNeeded += size;
3575 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3576 if(space && size <= left) {
3577 pi2->pParameters = (LPWSTR)ptr;
3578 ptr += size;
3579 left -= size;
3580 } else
3581 space = FALSE;
3582 *pcbNeeded += size;
3584 if(pi2) {
3585 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3586 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3587 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3588 "Default Priority");
3589 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3590 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3593 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3594 memset(pi2, 0, sizeof(*pi2));
3596 return space;
3599 /*********************************************************************
3600 * WINSPOOL_GetPrinter_4
3602 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3604 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3605 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3607 DWORD size, left = cbBuf;
3608 BOOL space = (cbBuf > 0);
3609 LPBYTE ptr = buf;
3611 *pcbNeeded = 0;
3613 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3614 if(space && size <= left) {
3615 pi4->pPrinterName = (LPWSTR)ptr;
3616 ptr += size;
3617 left -= size;
3618 } else
3619 space = FALSE;
3620 *pcbNeeded += size;
3622 if(pi4) {
3623 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3626 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3627 memset(pi4, 0, sizeof(*pi4));
3629 return space;
3632 /*********************************************************************
3633 * WINSPOOL_GetPrinter_5
3635 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3637 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3638 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3640 DWORD size, left = cbBuf;
3641 BOOL space = (cbBuf > 0);
3642 LPBYTE ptr = buf;
3644 *pcbNeeded = 0;
3646 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3647 if(space && size <= left) {
3648 pi5->pPrinterName = (LPWSTR)ptr;
3649 ptr += size;
3650 left -= size;
3651 } else
3652 space = FALSE;
3653 *pcbNeeded += size;
3655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3656 if(space && size <= left) {
3657 pi5->pPortName = (LPWSTR)ptr;
3658 ptr += size;
3659 left -= size;
3660 } else
3661 space = FALSE;
3662 *pcbNeeded += size;
3664 if(pi5) {
3665 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3666 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3667 "dnsTimeout");
3668 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3669 "txTimeout");
3672 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3673 memset(pi5, 0, sizeof(*pi5));
3675 return space;
3678 /*********************************************************************
3679 * WINSPOOL_GetPrinter_7
3681 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3683 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3684 DWORD cbBuf, LPDWORD pcbNeeded)
3686 DWORD size, left = cbBuf;
3687 BOOL space = (cbBuf > 0);
3688 LPBYTE ptr = buf;
3690 *pcbNeeded = 0;
3692 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3694 ptr = NULL;
3695 size = sizeof(pi7->pszObjectGUID);
3697 if (space && size <= left) {
3698 pi7->pszObjectGUID = (LPWSTR)ptr;
3699 ptr += size;
3700 left -= size;
3701 } else
3702 space = FALSE;
3703 *pcbNeeded += size;
3704 if (pi7) {
3705 /* We do not have a Directory Service */
3706 pi7->dwAction = DSPRINT_UNPUBLISH;
3709 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3710 memset(pi7, 0, sizeof(*pi7));
3712 return space;
3715 /*********************************************************************
3716 * WINSPOOL_GetPrinter_9
3718 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3720 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3721 DWORD cbBuf, LPDWORD pcbNeeded)
3723 DWORD size;
3724 BOOL space = (cbBuf > 0);
3726 *pcbNeeded = 0;
3728 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3729 if(space && size <= cbBuf) {
3730 pi9->pDevMode = (LPDEVMODEW)buf;
3731 } else
3732 space = FALSE;
3733 *pcbNeeded += size;
3735 else
3737 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3738 if(space && size <= cbBuf) {
3739 pi9->pDevMode = (LPDEVMODEW)buf;
3740 } else
3741 space = FALSE;
3742 *pcbNeeded += size;
3745 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3746 memset(pi9, 0, sizeof(*pi9));
3748 return space;
3751 /*****************************************************************************
3752 * GetPrinterW [WINSPOOL.@]
3754 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3755 DWORD cbBuf, LPDWORD pcbNeeded)
3757 LPCWSTR name;
3758 DWORD size, needed = 0;
3759 LPBYTE ptr = NULL;
3760 HKEY hkeyPrinter, hkeyPrinters;
3761 BOOL ret;
3763 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3765 if (!(name = get_opened_printer_name(hPrinter))) {
3766 SetLastError(ERROR_INVALID_HANDLE);
3767 return FALSE;
3770 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3771 ERROR_SUCCESS) {
3772 ERR("Can't create Printers key\n");
3773 return FALSE;
3775 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3777 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3778 RegCloseKey(hkeyPrinters);
3779 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3780 return FALSE;
3783 switch(Level) {
3784 case 2:
3786 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3788 size = sizeof(PRINTER_INFO_2W);
3789 if(size <= cbBuf) {
3790 ptr = pPrinter + size;
3791 cbBuf -= size;
3792 memset(pPrinter, 0, size);
3793 } else {
3794 pi2 = NULL;
3795 cbBuf = 0;
3797 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3798 needed += size;
3799 break;
3802 case 4:
3804 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3806 size = sizeof(PRINTER_INFO_4W);
3807 if(size <= cbBuf) {
3808 ptr = pPrinter + size;
3809 cbBuf -= size;
3810 memset(pPrinter, 0, size);
3811 } else {
3812 pi4 = NULL;
3813 cbBuf = 0;
3815 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3816 needed += size;
3817 break;
3821 case 5:
3823 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3825 size = sizeof(PRINTER_INFO_5W);
3826 if(size <= cbBuf) {
3827 ptr = pPrinter + size;
3828 cbBuf -= size;
3829 memset(pPrinter, 0, size);
3830 } else {
3831 pi5 = NULL;
3832 cbBuf = 0;
3835 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3836 needed += size;
3837 break;
3841 case 6:
3843 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3845 size = sizeof(PRINTER_INFO_6);
3846 if (size <= cbBuf) {
3847 /* FIXME: We do not update the status yet */
3848 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3849 ret = TRUE;
3850 } else {
3851 ret = FALSE;
3854 needed += size;
3855 break;
3858 case 7:
3860 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3862 size = sizeof(PRINTER_INFO_7W);
3863 if (size <= cbBuf) {
3864 ptr = pPrinter + size;
3865 cbBuf -= size;
3866 memset(pPrinter, 0, size);
3867 } else {
3868 pi7 = NULL;
3869 cbBuf = 0;
3872 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3873 needed += size;
3874 break;
3878 case 9:
3880 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3882 size = sizeof(PRINTER_INFO_9W);
3883 if(size <= cbBuf) {
3884 ptr = pPrinter + size;
3885 cbBuf -= size;
3886 memset(pPrinter, 0, size);
3887 } else {
3888 pi9 = NULL;
3889 cbBuf = 0;
3892 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3893 needed += size;
3894 break;
3898 default:
3899 FIXME("Unimplemented level %d\n", Level);
3900 SetLastError(ERROR_INVALID_LEVEL);
3901 RegCloseKey(hkeyPrinters);
3902 RegCloseKey(hkeyPrinter);
3903 return FALSE;
3906 RegCloseKey(hkeyPrinter);
3907 RegCloseKey(hkeyPrinters);
3909 TRACE("returning %d needed = %d\n", ret, needed);
3910 if(pcbNeeded) *pcbNeeded = needed;
3911 if(!ret)
3912 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3913 return ret;
3916 /*****************************************************************************
3917 * GetPrinterA [WINSPOOL.@]
3919 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3920 DWORD cbBuf, LPDWORD pcbNeeded)
3922 BOOL ret;
3923 LPBYTE buf = NULL;
3925 if (cbBuf)
3926 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3928 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3929 if (ret)
3930 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3931 HeapFree(GetProcessHeap(), 0, buf);
3933 return ret;
3936 /*****************************************************************************
3937 * WINSPOOL_EnumPrintersW
3939 * Implementation of EnumPrintersW
3941 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3942 DWORD dwLevel, LPBYTE lpbPrinters,
3943 DWORD cbBuf, LPDWORD lpdwNeeded,
3944 LPDWORD lpdwReturned)
3947 HKEY hkeyPrinters, hkeyPrinter;
3948 WCHAR PrinterName[255];
3949 DWORD needed = 0, number = 0;
3950 DWORD used, i, left;
3951 PBYTE pi, buf;
3953 if(lpbPrinters)
3954 memset(lpbPrinters, 0, cbBuf);
3955 if(lpdwReturned)
3956 *lpdwReturned = 0;
3957 if(lpdwNeeded)
3958 *lpdwNeeded = 0;
3960 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3961 if(dwType == PRINTER_ENUM_DEFAULT)
3962 return TRUE;
3964 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3965 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3966 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3967 if (!dwType) {
3968 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3969 return TRUE;
3974 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3975 FIXME("dwType = %08x\n", dwType);
3976 SetLastError(ERROR_INVALID_FLAGS);
3977 return FALSE;
3980 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3981 ERROR_SUCCESS) {
3982 ERR("Can't create Printers key\n");
3983 return FALSE;
3986 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3987 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3988 RegCloseKey(hkeyPrinters);
3989 ERR("Can't query Printers key\n");
3990 return FALSE;
3992 TRACE("Found %d printers\n", number);
3994 switch(dwLevel) {
3995 case 1:
3996 used = number * sizeof(PRINTER_INFO_1W);
3997 break;
3998 case 2:
3999 used = number * sizeof(PRINTER_INFO_2W);
4000 break;
4001 case 4:
4002 used = number * sizeof(PRINTER_INFO_4W);
4003 break;
4004 case 5:
4005 used = number * sizeof(PRINTER_INFO_5W);
4006 break;
4008 default:
4009 SetLastError(ERROR_INVALID_LEVEL);
4010 RegCloseKey(hkeyPrinters);
4011 return FALSE;
4013 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4015 for(i = 0; i < number; i++) {
4016 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4017 ERROR_SUCCESS) {
4018 ERR("Can't enum key number %d\n", i);
4019 RegCloseKey(hkeyPrinters);
4020 return FALSE;
4022 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4023 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4024 ERROR_SUCCESS) {
4025 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4026 RegCloseKey(hkeyPrinters);
4027 return FALSE;
4030 if(cbBuf > used) {
4031 buf = lpbPrinters + used;
4032 left = cbBuf - used;
4033 } else {
4034 buf = NULL;
4035 left = 0;
4038 switch(dwLevel) {
4039 case 1:
4040 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4041 left, &needed);
4042 used += needed;
4043 if(pi) pi += sizeof(PRINTER_INFO_1W);
4044 break;
4045 case 2:
4046 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4047 left, &needed);
4048 used += needed;
4049 if(pi) pi += sizeof(PRINTER_INFO_2W);
4050 break;
4051 case 4:
4052 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4053 left, &needed);
4054 used += needed;
4055 if(pi) pi += sizeof(PRINTER_INFO_4W);
4056 break;
4057 case 5:
4058 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4059 left, &needed);
4060 used += needed;
4061 if(pi) pi += sizeof(PRINTER_INFO_5W);
4062 break;
4063 default:
4064 ERR("Shouldn't be here!\n");
4065 RegCloseKey(hkeyPrinter);
4066 RegCloseKey(hkeyPrinters);
4067 return FALSE;
4069 RegCloseKey(hkeyPrinter);
4071 RegCloseKey(hkeyPrinters);
4073 if(lpdwNeeded)
4074 *lpdwNeeded = used;
4076 if(used > cbBuf) {
4077 if(lpbPrinters)
4078 memset(lpbPrinters, 0, cbBuf);
4079 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4080 return FALSE;
4082 if(lpdwReturned)
4083 *lpdwReturned = number;
4084 SetLastError(ERROR_SUCCESS);
4085 return TRUE;
4089 /******************************************************************
4090 * EnumPrintersW [WINSPOOL.@]
4092 * Enumerates the available printers, print servers and print
4093 * providers, depending on the specified flags, name and level.
4095 * RETURNS:
4097 * If level is set to 1:
4098 * Returns an array of PRINTER_INFO_1 data structures in the
4099 * lpbPrinters buffer.
4101 * If level is set to 2:
4102 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4103 * Returns an array of PRINTER_INFO_2 data structures in the
4104 * lpbPrinters buffer. Note that according to MSDN also an
4105 * OpenPrinter should be performed on every remote printer.
4107 * If level is set to 4 (officially WinNT only):
4108 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4109 * Fast: Only the registry is queried to retrieve printer names,
4110 * no connection to the driver is made.
4111 * Returns an array of PRINTER_INFO_4 data structures in the
4112 * lpbPrinters buffer.
4114 * If level is set to 5 (officially WinNT4/Win9x only):
4115 * Fast: Only the registry is queried to retrieve printer names,
4116 * no connection to the driver is made.
4117 * Returns an array of PRINTER_INFO_5 data structures in the
4118 * lpbPrinters buffer.
4120 * If level set to 3 or 6+:
4121 * returns zero (failure!)
4123 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4124 * for information.
4126 * BUGS:
4127 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4128 * - Only levels 2, 4 and 5 are implemented at the moment.
4129 * - 16-bit printer drivers are not enumerated.
4130 * - Returned amount of bytes used/needed does not match the real Windoze
4131 * implementation (as in this implementation, all strings are part
4132 * of the buffer, whereas Win32 keeps them somewhere else)
4133 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4135 * NOTE:
4136 * - In a regular Wine installation, no registry settings for printers
4137 * exist, which makes this function return an empty list.
4139 BOOL WINAPI EnumPrintersW(
4140 DWORD dwType, /* [in] Types of print objects to enumerate */
4141 LPWSTR lpszName, /* [in] name of objects to enumerate */
4142 DWORD dwLevel, /* [in] type of printer info structure */
4143 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4144 DWORD cbBuf, /* [in] max size of buffer in bytes */
4145 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4146 LPDWORD lpdwReturned /* [out] number of entries returned */
4149 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4150 lpdwNeeded, lpdwReturned);
4153 /******************************************************************
4154 * EnumPrintersA [WINSPOOL.@]
4156 * See EnumPrintersW
4159 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4160 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4162 BOOL ret;
4163 UNICODE_STRING pNameU;
4164 LPWSTR pNameW;
4165 LPBYTE pPrintersW;
4167 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4168 pPrinters, cbBuf, pcbNeeded, pcReturned);
4170 pNameW = asciitounicode(&pNameU, pName);
4172 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4173 MS Office need this */
4174 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4176 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4178 RtlFreeUnicodeString(&pNameU);
4179 if (ret) {
4180 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4182 HeapFree(GetProcessHeap(), 0, pPrintersW);
4183 return ret;
4186 /*****************************************************************************
4187 * WINSPOOL_GetDriverInfoFromReg [internal]
4189 * Enters the information from the registry into the DRIVER_INFO struct
4191 * RETURNS
4192 * zero if the printer driver does not exist in the registry
4193 * (only if Level > 1) otherwise nonzero
4195 static BOOL WINSPOOL_GetDriverInfoFromReg(
4196 HKEY hkeyDrivers,
4197 LPWSTR DriverName,
4198 const printenv_t * env,
4199 DWORD Level,
4200 LPBYTE ptr, /* DRIVER_INFO */
4201 LPBYTE pDriverStrings, /* strings buffer */
4202 DWORD cbBuf, /* size of string buffer */
4203 LPDWORD pcbNeeded) /* space needed for str. */
4205 DWORD size, tmp;
4206 HKEY hkeyDriver;
4207 WCHAR driverdir[MAX_PATH];
4208 DWORD dirlen;
4209 LPBYTE strPtr = pDriverStrings;
4210 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4212 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4213 debugstr_w(DriverName), env,
4214 Level, di, pDriverStrings, cbBuf);
4216 if (di) ZeroMemory(di, di_sizeof[Level]);
4218 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4219 if (*pcbNeeded <= cbBuf)
4220 strcpyW((LPWSTR)strPtr, DriverName);
4222 /* pName for level 1 has a different offset! */
4223 if (Level == 1) {
4224 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4225 return TRUE;
4228 /* .cVersion and .pName for level > 1 */
4229 if (di) {
4230 di->cVersion = env->driverversion;
4231 di->pName = (LPWSTR) strPtr;
4232 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4235 /* Reserve Space for the largest subdir and a Backslash*/
4236 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4237 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4238 /* Should never Fail */
4239 return FALSE;
4241 lstrcatW(driverdir, env->versionsubdir);
4242 lstrcatW(driverdir, backslashW);
4244 /* dirlen must not include the terminating zero */
4245 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4247 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4248 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4249 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4250 return FALSE;
4253 /* pEnvironment */
4254 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4256 *pcbNeeded += size;
4257 if (*pcbNeeded <= cbBuf) {
4258 lstrcpyW((LPWSTR)strPtr, env->envname);
4259 if (di) di->pEnvironment = (LPWSTR)strPtr;
4260 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4263 /* .pDriverPath is the Graphics rendering engine.
4264 The full Path is required to avoid a crash in some apps */
4265 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4266 *pcbNeeded += size;
4267 if (*pcbNeeded <= cbBuf)
4268 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4270 if (di) di->pDriverPath = (LPWSTR)strPtr;
4271 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4274 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4275 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4276 *pcbNeeded += size;
4277 if (*pcbNeeded <= cbBuf)
4278 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4280 if (di) di->pDataFile = (LPWSTR)strPtr;
4281 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4284 /* .pConfigFile is the Driver user Interface */
4285 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4286 *pcbNeeded += size;
4287 if (*pcbNeeded <= cbBuf)
4288 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4290 if (di) di->pConfigFile = (LPWSTR)strPtr;
4291 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4294 if (Level == 2 ) {
4295 RegCloseKey(hkeyDriver);
4296 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4297 return TRUE;
4300 if (Level == 5 ) {
4301 RegCloseKey(hkeyDriver);
4302 FIXME("level 5: incomplete\n");
4303 return TRUE;
4306 /* .pHelpFile */
4307 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4308 *pcbNeeded += size;
4309 if (*pcbNeeded <= cbBuf)
4310 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4312 if (di) di->pHelpFile = (LPWSTR)strPtr;
4313 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4316 /* .pDependentFiles */
4317 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4318 *pcbNeeded += size;
4319 if (*pcbNeeded <= cbBuf)
4320 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4322 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4323 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4325 else if (GetVersion() & 0x80000000) {
4326 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4327 size = 2 * sizeof(WCHAR);
4328 *pcbNeeded += size;
4329 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4331 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4332 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4335 /* .pMonitorName is the optional Language Monitor */
4336 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4337 *pcbNeeded += size;
4338 if (*pcbNeeded <= cbBuf)
4339 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4341 if (di) di->pMonitorName = (LPWSTR)strPtr;
4342 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4345 /* .pDefaultDataType */
4346 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4347 *pcbNeeded += size;
4348 if(*pcbNeeded <= cbBuf)
4349 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4351 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4352 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4355 if (Level == 3 ) {
4356 RegCloseKey(hkeyDriver);
4357 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4358 return TRUE;
4361 /* .pszzPreviousNames */
4362 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4363 *pcbNeeded += size;
4364 if(*pcbNeeded <= cbBuf)
4365 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4367 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4368 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4371 if (Level == 4 ) {
4372 RegCloseKey(hkeyDriver);
4373 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4374 return TRUE;
4377 /* support is missing, but not important enough for a FIXME */
4378 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4380 /* .pszMfgName */
4381 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4382 *pcbNeeded += size;
4383 if(*pcbNeeded <= cbBuf)
4384 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4386 if (di) di->pszMfgName = (LPWSTR)strPtr;
4387 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4390 /* .pszOEMUrl */
4391 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4392 *pcbNeeded += size;
4393 if(*pcbNeeded <= cbBuf)
4394 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4396 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4397 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4400 /* .pszHardwareID */
4401 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4402 *pcbNeeded += size;
4403 if(*pcbNeeded <= cbBuf)
4404 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4406 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4407 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4410 /* .pszProvider */
4411 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4412 *pcbNeeded += size;
4413 if(*pcbNeeded <= cbBuf)
4414 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4416 if (di) di->pszProvider = (LPWSTR)strPtr;
4417 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4420 if (Level == 6 ) {
4421 RegCloseKey(hkeyDriver);
4422 return TRUE;
4425 /* support is missing, but not important enough for a FIXME */
4426 TRACE("level 8: incomplete\n");
4428 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4429 RegCloseKey(hkeyDriver);
4430 return TRUE;
4433 /*****************************************************************************
4434 * GetPrinterDriverW [WINSPOOL.@]
4436 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4437 DWORD Level, LPBYTE pDriverInfo,
4438 DWORD cbBuf, LPDWORD pcbNeeded)
4440 LPCWSTR name;
4441 WCHAR DriverName[100];
4442 DWORD ret, type, size, needed = 0;
4443 LPBYTE ptr = NULL;
4444 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4445 const printenv_t * env;
4447 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4448 Level,pDriverInfo,cbBuf, pcbNeeded);
4450 if (cbBuf > 0)
4451 ZeroMemory(pDriverInfo, cbBuf);
4453 if (!(name = get_opened_printer_name(hPrinter))) {
4454 SetLastError(ERROR_INVALID_HANDLE);
4455 return FALSE;
4458 if (Level < 1 || Level == 7 || Level > 8) {
4459 SetLastError(ERROR_INVALID_LEVEL);
4460 return FALSE;
4463 env = validate_envW(pEnvironment);
4464 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4466 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4467 ERROR_SUCCESS) {
4468 ERR("Can't create Printers key\n");
4469 return FALSE;
4471 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4472 != ERROR_SUCCESS) {
4473 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4474 RegCloseKey(hkeyPrinters);
4475 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4476 return FALSE;
4478 size = sizeof(DriverName);
4479 DriverName[0] = 0;
4480 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4481 (LPBYTE)DriverName, &size);
4482 RegCloseKey(hkeyPrinter);
4483 RegCloseKey(hkeyPrinters);
4484 if(ret != ERROR_SUCCESS) {
4485 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4486 return FALSE;
4489 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4490 if(!hkeyDrivers) {
4491 ERR("Can't create Drivers key\n");
4492 return FALSE;
4495 size = di_sizeof[Level];
4496 if ((size <= cbBuf) && pDriverInfo)
4497 ptr = pDriverInfo + size;
4499 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4500 env, Level, pDriverInfo, ptr,
4501 (cbBuf < size) ? 0 : cbBuf - size,
4502 &needed)) {
4503 RegCloseKey(hkeyDrivers);
4504 return FALSE;
4507 RegCloseKey(hkeyDrivers);
4509 if(pcbNeeded) *pcbNeeded = size + needed;
4510 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4511 if(cbBuf >= size + needed) return TRUE;
4512 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4513 return FALSE;
4516 /*****************************************************************************
4517 * GetPrinterDriverA [WINSPOOL.@]
4519 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4520 DWORD Level, LPBYTE pDriverInfo,
4521 DWORD cbBuf, LPDWORD pcbNeeded)
4523 BOOL ret;
4524 UNICODE_STRING pEnvW;
4525 PWSTR pwstrEnvW;
4526 LPBYTE buf = NULL;
4528 if (cbBuf)
4530 ZeroMemory(pDriverInfo, cbBuf);
4531 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4534 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4535 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4536 cbBuf, pcbNeeded);
4537 if (ret)
4538 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4540 HeapFree(GetProcessHeap(), 0, buf);
4542 RtlFreeUnicodeString(&pEnvW);
4543 return ret;
4546 /*****************************************************************************
4547 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4549 * Return the PATH for the Printer-Drivers (UNICODE)
4551 * PARAMS
4552 * pName [I] Servername (NT only) or NULL (local Computer)
4553 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4554 * Level [I] Structure-Level (must be 1)
4555 * pDriverDirectory [O] PTR to Buffer that receives the Result
4556 * cbBuf [I] Size of Buffer at pDriverDirectory
4557 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4558 * required for pDriverDirectory
4560 * RETURNS
4561 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4562 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4563 * if cbBuf is too small
4565 * Native Values returned in pDriverDirectory on Success:
4566 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4567 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4568 *| win9x(Windows 4.0): "%winsysdir%"
4570 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4572 * FIXME
4573 *- Only NULL or "" is supported for pName
4576 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4577 DWORD Level, LPBYTE pDriverDirectory,
4578 DWORD cbBuf, LPDWORD pcbNeeded)
4580 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4581 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4583 if ((backend == NULL) && !load_backend()) return FALSE;
4585 if (Level != 1) {
4586 /* (Level != 1) is ignored in win9x */
4587 SetLastError(ERROR_INVALID_LEVEL);
4588 return FALSE;
4590 if (pcbNeeded == NULL) {
4591 /* (pcbNeeded == NULL) is ignored in win9x */
4592 SetLastError(RPC_X_NULL_REF_POINTER);
4593 return FALSE;
4596 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4597 pDriverDirectory, cbBuf, pcbNeeded);
4602 /*****************************************************************************
4603 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4605 * Return the PATH for the Printer-Drivers (ANSI)
4607 * See GetPrinterDriverDirectoryW.
4609 * NOTES
4610 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4613 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4614 DWORD Level, LPBYTE pDriverDirectory,
4615 DWORD cbBuf, LPDWORD pcbNeeded)
4617 UNICODE_STRING nameW, environmentW;
4618 BOOL ret;
4619 DWORD pcbNeededW;
4620 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4621 WCHAR *driverDirectoryW = NULL;
4623 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4624 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4626 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4628 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4629 else nameW.Buffer = NULL;
4630 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4631 else environmentW.Buffer = NULL;
4633 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4634 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4635 if (ret) {
4636 DWORD needed;
4637 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4638 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4639 if(pcbNeeded)
4640 *pcbNeeded = needed;
4641 ret = (needed <= cbBuf) ? TRUE : FALSE;
4642 } else
4643 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4645 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4647 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4648 RtlFreeUnicodeString(&environmentW);
4649 RtlFreeUnicodeString(&nameW);
4651 return ret;
4654 /*****************************************************************************
4655 * AddPrinterDriverA [WINSPOOL.@]
4657 * See AddPrinterDriverW.
4660 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4662 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4663 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4666 /******************************************************************************
4667 * AddPrinterDriverW (WINSPOOL.@)
4669 * Install a Printer Driver
4671 * PARAMS
4672 * pName [I] Servername or NULL (local Computer)
4673 * level [I] Level for the supplied DRIVER_INFO_*W struct
4674 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4676 * RESULTS
4677 * Success: TRUE
4678 * Failure: FALSE
4681 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4683 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4684 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4687 /*****************************************************************************
4688 * AddPrintProcessorA [WINSPOOL.@]
4690 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4691 LPSTR pPrintProcessorName)
4693 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4694 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4695 return FALSE;
4698 /*****************************************************************************
4699 * AddPrintProcessorW [WINSPOOL.@]
4701 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4702 LPWSTR pPrintProcessorName)
4704 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4705 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4706 return TRUE;
4709 /*****************************************************************************
4710 * AddPrintProvidorA [WINSPOOL.@]
4712 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4714 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4715 return FALSE;
4718 /*****************************************************************************
4719 * AddPrintProvidorW [WINSPOOL.@]
4721 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4723 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4724 return FALSE;
4727 /*****************************************************************************
4728 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4730 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4731 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4733 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4734 pDevModeOutput, pDevModeInput);
4735 return 0;
4738 /*****************************************************************************
4739 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4741 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4742 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4744 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4745 pDevModeOutput, pDevModeInput);
4746 return 0;
4749 /*****************************************************************************
4750 * PrinterProperties [WINSPOOL.@]
4752 * Displays a dialog to set the properties of the printer.
4754 * RETURNS
4755 * nonzero on success or zero on failure
4757 * BUGS
4758 * implemented as stub only
4760 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4761 HANDLE hPrinter /* [in] handle to printer object */
4763 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4764 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4765 return FALSE;
4768 /*****************************************************************************
4769 * EnumJobsA [WINSPOOL.@]
4772 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4773 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4774 LPDWORD pcReturned)
4776 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4777 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4779 if(pcbNeeded) *pcbNeeded = 0;
4780 if(pcReturned) *pcReturned = 0;
4781 return FALSE;
4785 /*****************************************************************************
4786 * EnumJobsW [WINSPOOL.@]
4789 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4790 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4791 LPDWORD pcReturned)
4793 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4794 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4796 if(pcbNeeded) *pcbNeeded = 0;
4797 if(pcReturned) *pcReturned = 0;
4798 return FALSE;
4801 /*****************************************************************************
4802 * WINSPOOL_EnumPrinterDrivers [internal]
4804 * Delivers information about all printer drivers installed on the
4805 * localhost or a given server
4807 * RETURNS
4808 * nonzero on success or zero on failure. If the buffer for the returned
4809 * information is too small the function will return an error
4811 * BUGS
4812 * - only implemented for localhost, foreign hosts will return an error
4814 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4815 DWORD Level, LPBYTE pDriverInfo,
4816 DWORD driver_index,
4817 DWORD cbBuf, LPDWORD pcbNeeded,
4818 LPDWORD pcFound, DWORD data_offset)
4820 { HKEY hkeyDrivers;
4821 DWORD i, size = 0;
4822 const printenv_t * env;
4824 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4825 debugstr_w(pName), debugstr_w(pEnvironment),
4826 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4828 env = validate_envW(pEnvironment);
4829 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4831 *pcFound = 0;
4833 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4834 if(!hkeyDrivers) {
4835 ERR("Can't open Drivers key\n");
4836 return FALSE;
4839 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4840 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4841 RegCloseKey(hkeyDrivers);
4842 ERR("Can't query Drivers key\n");
4843 return FALSE;
4845 TRACE("Found %d Drivers\n", *pcFound);
4847 /* get size of single struct
4848 * unicode and ascii structure have the same size
4850 size = di_sizeof[Level];
4852 if (data_offset == 0)
4853 data_offset = size * (*pcFound);
4854 *pcbNeeded = data_offset;
4856 for( i = 0; i < *pcFound; i++) {
4857 WCHAR DriverNameW[255];
4858 PBYTE table_ptr = NULL;
4859 PBYTE data_ptr = NULL;
4860 DWORD needed = 0;
4862 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4863 != ERROR_SUCCESS) {
4864 ERR("Can't enum key number %d\n", i);
4865 RegCloseKey(hkeyDrivers);
4866 return FALSE;
4869 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4870 table_ptr = pDriverInfo + (driver_index + i) * size;
4871 if (pDriverInfo && *pcbNeeded <= cbBuf)
4872 data_ptr = pDriverInfo + *pcbNeeded;
4874 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4875 env, Level, table_ptr, data_ptr,
4876 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4877 &needed)) {
4878 RegCloseKey(hkeyDrivers);
4879 return FALSE;
4882 *pcbNeeded += needed;
4885 RegCloseKey(hkeyDrivers);
4887 if(cbBuf < *pcbNeeded){
4888 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4889 return FALSE;
4892 return TRUE;
4895 /*****************************************************************************
4896 * EnumPrinterDriversW [WINSPOOL.@]
4898 * see function EnumPrinterDrivers for RETURNS, BUGS
4900 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4901 LPBYTE pDriverInfo, DWORD cbBuf,
4902 LPDWORD pcbNeeded, LPDWORD pcReturned)
4904 static const WCHAR allW[] = {'a','l','l',0};
4905 BOOL ret;
4906 DWORD found;
4908 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4910 SetLastError(RPC_X_NULL_REF_POINTER);
4911 return FALSE;
4914 /* check for local drivers */
4915 if((pName) && (pName[0])) {
4916 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4917 SetLastError(ERROR_ACCESS_DENIED);
4918 return FALSE;
4921 /* check input parameter */
4922 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4923 SetLastError(ERROR_INVALID_LEVEL);
4924 return FALSE;
4927 if(pDriverInfo && cbBuf > 0)
4928 memset( pDriverInfo, 0, cbBuf);
4930 /* Exception: pull all printers */
4931 if (pEnvironment && !strcmpW(pEnvironment, allW))
4933 DWORD i, needed, bufsize = cbBuf;
4934 DWORD total_needed = 0;
4935 DWORD total_found = 0;
4936 DWORD data_offset;
4938 /* Precompute the overall total; we need this to know
4939 where pointers end and data begins (i.e. data_offset) */
4940 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4942 needed = found = 0;
4943 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4944 NULL, 0, 0, &needed, &found, 0);
4945 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4946 total_needed += needed;
4947 total_found += found;
4950 data_offset = di_sizeof[Level] * total_found;
4952 *pcReturned = 0;
4953 *pcbNeeded = 0;
4954 total_found = 0;
4955 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4957 needed = found = 0;
4958 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4959 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4960 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4961 else if (ret)
4962 *pcReturned += found;
4963 *pcbNeeded = needed;
4964 data_offset = needed;
4965 total_found += found;
4967 return ret;
4970 /* Normal behavior */
4971 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4972 0, cbBuf, pcbNeeded, &found, 0);
4973 if (ret)
4974 *pcReturned = found;
4976 return ret;
4979 /*****************************************************************************
4980 * EnumPrinterDriversA [WINSPOOL.@]
4982 * see function EnumPrinterDrivers for RETURNS, BUGS
4984 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4985 LPBYTE pDriverInfo, DWORD cbBuf,
4986 LPDWORD pcbNeeded, LPDWORD pcReturned)
4988 BOOL ret;
4989 UNICODE_STRING pNameW, pEnvironmentW;
4990 PWSTR pwstrNameW, pwstrEnvironmentW;
4991 LPBYTE buf = NULL;
4993 if (cbBuf)
4994 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4996 pwstrNameW = asciitounicode(&pNameW, pName);
4997 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4999 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5000 buf, cbBuf, pcbNeeded, pcReturned);
5001 if (ret)
5002 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5004 HeapFree(GetProcessHeap(), 0, buf);
5006 RtlFreeUnicodeString(&pNameW);
5007 RtlFreeUnicodeString(&pEnvironmentW);
5009 return ret;
5012 /******************************************************************************
5013 * EnumPortsA (WINSPOOL.@)
5015 * See EnumPortsW.
5018 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5019 LPDWORD pcbNeeded, LPDWORD pcReturned)
5021 BOOL res;
5022 LPBYTE bufferW = NULL;
5023 LPWSTR nameW = NULL;
5024 DWORD needed = 0;
5025 DWORD numentries = 0;
5026 INT len;
5028 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5029 cbBuf, pcbNeeded, pcReturned);
5031 /* convert servername to unicode */
5032 if (pName) {
5033 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5034 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5035 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5037 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5038 needed = cbBuf * sizeof(WCHAR);
5039 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5040 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5042 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5043 if (pcbNeeded) needed = *pcbNeeded;
5044 /* HeapReAlloc return NULL, when bufferW was NULL */
5045 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5046 HeapAlloc(GetProcessHeap(), 0, needed);
5048 /* Try again with the large Buffer */
5049 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5051 needed = pcbNeeded ? *pcbNeeded : 0;
5052 numentries = pcReturned ? *pcReturned : 0;
5055 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5056 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5058 if (res) {
5059 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5060 DWORD entrysize = 0;
5061 DWORD index;
5062 LPSTR ptr;
5063 LPPORT_INFO_2W pi2w;
5064 LPPORT_INFO_2A pi2a;
5066 needed = 0;
5067 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5069 /* First pass: calculate the size for all Entries */
5070 pi2w = (LPPORT_INFO_2W) bufferW;
5071 pi2a = (LPPORT_INFO_2A) pPorts;
5072 index = 0;
5073 while (index < numentries) {
5074 index++;
5075 needed += entrysize; /* PORT_INFO_?A */
5076 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5078 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5079 NULL, 0, NULL, NULL);
5080 if (Level > 1) {
5081 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5082 NULL, 0, NULL, NULL);
5083 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5084 NULL, 0, NULL, NULL);
5086 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5087 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5088 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5091 /* check for errors and quit on failure */
5092 if (cbBuf < needed) {
5093 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5094 res = FALSE;
5095 goto cleanup;
5097 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5098 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5099 cbBuf -= len ; /* free Bytes in the user-Buffer */
5100 pi2w = (LPPORT_INFO_2W) bufferW;
5101 pi2a = (LPPORT_INFO_2A) pPorts;
5102 index = 0;
5103 /* Second Pass: Fill the User Buffer (if we have one) */
5104 while ((index < numentries) && pPorts) {
5105 index++;
5106 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5107 pi2a->pPortName = ptr;
5108 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5109 ptr, cbBuf , NULL, NULL);
5110 ptr += len;
5111 cbBuf -= len;
5112 if (Level > 1) {
5113 pi2a->pMonitorName = ptr;
5114 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5115 ptr, cbBuf, NULL, NULL);
5116 ptr += len;
5117 cbBuf -= len;
5119 pi2a->pDescription = ptr;
5120 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5121 ptr, cbBuf, NULL, NULL);
5122 ptr += len;
5123 cbBuf -= len;
5125 pi2a->fPortType = pi2w->fPortType;
5126 pi2a->Reserved = 0; /* documented: "must be zero" */
5129 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5130 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5131 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5135 cleanup:
5136 if (pcbNeeded) *pcbNeeded = needed;
5137 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5139 HeapFree(GetProcessHeap(), 0, nameW);
5140 HeapFree(GetProcessHeap(), 0, bufferW);
5142 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5143 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5145 return (res);
5149 /******************************************************************************
5150 * EnumPortsW (WINSPOOL.@)
5152 * Enumerate available Ports
5154 * PARAMS
5155 * pName [I] Servername or NULL (local Computer)
5156 * Level [I] Structure-Level (1 or 2)
5157 * pPorts [O] PTR to Buffer that receives the Result
5158 * cbBuf [I] Size of Buffer at pPorts
5159 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5160 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5162 * RETURNS
5163 * Success: TRUE
5164 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5167 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5170 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5171 cbBuf, pcbNeeded, pcReturned);
5173 if ((backend == NULL) && !load_backend()) return FALSE;
5175 /* Level is not checked in win9x */
5176 if (!Level || (Level > 2)) {
5177 WARN("level (%d) is ignored in win9x\n", Level);
5178 SetLastError(ERROR_INVALID_LEVEL);
5179 return FALSE;
5181 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5182 SetLastError(RPC_X_NULL_REF_POINTER);
5183 return FALSE;
5186 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5189 /******************************************************************************
5190 * GetDefaultPrinterW (WINSPOOL.@)
5192 * FIXME
5193 * This function must read the value from data 'device' of key
5194 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5196 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5198 BOOL retval = TRUE;
5199 DWORD insize, len;
5200 WCHAR *buffer, *ptr;
5202 if (!namesize)
5204 SetLastError(ERROR_INVALID_PARAMETER);
5205 return FALSE;
5208 /* make the buffer big enough for the stuff from the profile/registry,
5209 * the content must fit into the local buffer to compute the correct
5210 * size even if the extern buffer is too small or not given.
5211 * (20 for ,driver,port) */
5212 insize = *namesize;
5213 len = max(100, (insize + 20));
5214 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5216 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5218 SetLastError (ERROR_FILE_NOT_FOUND);
5219 retval = FALSE;
5220 goto end;
5222 TRACE("%s\n", debugstr_w(buffer));
5224 if ((ptr = strchrW(buffer, ',')) == NULL)
5226 SetLastError(ERROR_INVALID_NAME);
5227 retval = FALSE;
5228 goto end;
5231 *ptr = 0;
5232 *namesize = strlenW(buffer) + 1;
5233 if(!name || (*namesize > insize))
5235 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5236 retval = FALSE;
5237 goto end;
5239 strcpyW(name, buffer);
5241 end:
5242 HeapFree( GetProcessHeap(), 0, buffer);
5243 return retval;
5247 /******************************************************************************
5248 * GetDefaultPrinterA (WINSPOOL.@)
5250 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5252 BOOL retval = TRUE;
5253 DWORD insize = 0;
5254 WCHAR *bufferW = NULL;
5256 if (!namesize)
5258 SetLastError(ERROR_INVALID_PARAMETER);
5259 return FALSE;
5262 if(name && *namesize) {
5263 insize = *namesize;
5264 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5267 if(!GetDefaultPrinterW( bufferW, namesize)) {
5268 retval = FALSE;
5269 goto end;
5272 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5273 NULL, NULL);
5274 if (!*namesize)
5276 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5277 retval = FALSE;
5279 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5281 end:
5282 HeapFree( GetProcessHeap(), 0, bufferW);
5283 return retval;
5287 /******************************************************************************
5288 * SetDefaultPrinterW (WINSPOOL.204)
5290 * Set the Name of the Default Printer
5292 * PARAMS
5293 * pszPrinter [I] Name of the Printer or NULL
5295 * RETURNS
5296 * Success: True
5297 * Failure: FALSE
5299 * NOTES
5300 * When the Parameter is NULL or points to an Empty String and
5301 * a Default Printer was already present, then this Function changes nothing.
5302 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5303 * the First enumerated local Printer is used.
5306 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5308 WCHAR default_printer[MAX_PATH];
5309 LPWSTR buffer = NULL;
5310 HKEY hreg;
5311 DWORD size;
5312 DWORD namelen;
5313 LONG lres;
5315 TRACE("(%s)\n", debugstr_w(pszPrinter));
5316 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5318 default_printer[0] = '\0';
5319 size = sizeof(default_printer)/sizeof(WCHAR);
5321 /* if we have a default Printer, do nothing. */
5322 if (GetDefaultPrinterW(default_printer, &size))
5323 return TRUE;
5325 pszPrinter = NULL;
5326 /* we have no default Printer: search local Printers and use the first */
5327 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5329 default_printer[0] = '\0';
5330 size = sizeof(default_printer)/sizeof(WCHAR);
5331 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5333 pszPrinter = default_printer;
5334 TRACE("using %s\n", debugstr_w(pszPrinter));
5336 RegCloseKey(hreg);
5339 if (pszPrinter == NULL) {
5340 TRACE("no local printer found\n");
5341 SetLastError(ERROR_FILE_NOT_FOUND);
5342 return FALSE;
5346 /* "pszPrinter" is never empty or NULL here. */
5347 namelen = lstrlenW(pszPrinter);
5348 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5349 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5350 if (!buffer ||
5351 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5352 HeapFree(GetProcessHeap(), 0, buffer);
5353 SetLastError(ERROR_FILE_NOT_FOUND);
5354 return FALSE;
5357 /* read the devices entry for the printer (driver,port) to build the string for the
5358 default device entry (printer,driver,port) */
5359 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5360 buffer[namelen] = ',';
5361 namelen++; /* move index to the start of the driver */
5363 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5364 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5365 if (!lres) {
5366 TRACE("set device to %s\n", debugstr_w(buffer));
5368 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5369 TRACE("failed to set the device entry: %d\n", GetLastError());
5370 lres = ERROR_INVALID_PRINTER_NAME;
5373 /* remove the next section, when INIFileMapping is implemented */
5375 HKEY hdev;
5376 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5377 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5378 RegCloseKey(hdev);
5382 else
5384 if (lres != ERROR_FILE_NOT_FOUND)
5385 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5387 SetLastError(ERROR_INVALID_PRINTER_NAME);
5390 RegCloseKey(hreg);
5391 HeapFree(GetProcessHeap(), 0, buffer);
5392 return (lres == ERROR_SUCCESS);
5395 /******************************************************************************
5396 * SetDefaultPrinterA (WINSPOOL.202)
5398 * See SetDefaultPrinterW.
5401 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5403 LPWSTR bufferW = NULL;
5404 BOOL res;
5406 TRACE("(%s)\n", debugstr_a(pszPrinter));
5407 if(pszPrinter) {
5408 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5409 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5410 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5412 res = SetDefaultPrinterW(bufferW);
5413 HeapFree(GetProcessHeap(), 0, bufferW);
5414 return res;
5417 /******************************************************************************
5418 * SetPrinterDataExA (WINSPOOL.@)
5420 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5421 LPCSTR pValueName, DWORD Type,
5422 LPBYTE pData, DWORD cbData)
5424 HKEY hkeyPrinter, hkeySubkey;
5425 DWORD ret;
5427 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5428 debugstr_a(pValueName), Type, pData, cbData);
5430 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5431 != ERROR_SUCCESS)
5432 return ret;
5434 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5435 != ERROR_SUCCESS) {
5436 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5437 RegCloseKey(hkeyPrinter);
5438 return ret;
5440 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5441 RegCloseKey(hkeySubkey);
5442 RegCloseKey(hkeyPrinter);
5443 return ret;
5446 /******************************************************************************
5447 * SetPrinterDataExW (WINSPOOL.@)
5449 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5450 LPCWSTR pValueName, DWORD Type,
5451 LPBYTE pData, DWORD cbData)
5453 HKEY hkeyPrinter, hkeySubkey;
5454 DWORD ret;
5456 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5457 debugstr_w(pValueName), Type, pData, cbData);
5459 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5460 != ERROR_SUCCESS)
5461 return ret;
5463 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5464 != ERROR_SUCCESS) {
5465 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5466 RegCloseKey(hkeyPrinter);
5467 return ret;
5469 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5470 RegCloseKey(hkeySubkey);
5471 RegCloseKey(hkeyPrinter);
5472 return ret;
5475 /******************************************************************************
5476 * SetPrinterDataA (WINSPOOL.@)
5478 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5479 LPBYTE pData, DWORD cbData)
5481 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5482 pData, cbData);
5485 /******************************************************************************
5486 * SetPrinterDataW (WINSPOOL.@)
5488 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5489 LPBYTE pData, DWORD cbData)
5491 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5492 pData, cbData);
5495 /******************************************************************************
5496 * GetPrinterDataExA (WINSPOOL.@)
5498 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5499 LPCSTR pValueName, LPDWORD pType,
5500 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5502 opened_printer_t *printer;
5503 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5504 DWORD ret;
5506 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5507 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5509 printer = get_opened_printer(hPrinter);
5510 if(!printer) return ERROR_INVALID_HANDLE;
5512 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5513 if (ret) return ret;
5515 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5517 if (printer->name) {
5519 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5520 if (ret) {
5521 RegCloseKey(hkeyPrinters);
5522 return ret;
5524 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5525 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5526 RegCloseKey(hkeyPrinter);
5527 RegCloseKey(hkeyPrinters);
5528 return ret;
5531 *pcbNeeded = nSize;
5532 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5533 0, pType, pData, pcbNeeded);
5535 if (!ret && !pData) ret = ERROR_MORE_DATA;
5537 RegCloseKey(hkeySubkey);
5538 RegCloseKey(hkeyPrinter);
5539 RegCloseKey(hkeyPrinters);
5541 TRACE("--> %d\n", ret);
5542 return ret;
5545 /******************************************************************************
5546 * GetPrinterDataExW (WINSPOOL.@)
5548 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5549 LPCWSTR pValueName, LPDWORD pType,
5550 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5552 opened_printer_t *printer;
5553 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5554 DWORD ret;
5556 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5557 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5559 printer = get_opened_printer(hPrinter);
5560 if(!printer) return ERROR_INVALID_HANDLE;
5562 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5563 if (ret) return ret;
5565 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5567 if (printer->name) {
5569 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5570 if (ret) {
5571 RegCloseKey(hkeyPrinters);
5572 return ret;
5574 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5575 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5576 RegCloseKey(hkeyPrinter);
5577 RegCloseKey(hkeyPrinters);
5578 return ret;
5581 *pcbNeeded = nSize;
5582 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5583 0, pType, pData, pcbNeeded);
5585 if (!ret && !pData) ret = ERROR_MORE_DATA;
5587 RegCloseKey(hkeySubkey);
5588 RegCloseKey(hkeyPrinter);
5589 RegCloseKey(hkeyPrinters);
5591 TRACE("--> %d\n", ret);
5592 return ret;
5595 /******************************************************************************
5596 * GetPrinterDataA (WINSPOOL.@)
5598 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5599 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5601 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5602 pData, nSize, pcbNeeded);
5605 /******************************************************************************
5606 * GetPrinterDataW (WINSPOOL.@)
5608 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5609 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5611 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5612 pData, nSize, pcbNeeded);
5615 /*******************************************************************************
5616 * EnumPrinterDataExW [WINSPOOL.@]
5618 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5619 LPBYTE pEnumValues, DWORD cbEnumValues,
5620 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5622 HKEY hkPrinter, hkSubKey;
5623 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5624 cbValueNameLen, cbMaxValueLen, cbValueLen,
5625 cbBufSize, dwType;
5626 LPWSTR lpValueName;
5627 HANDLE hHeap;
5628 PBYTE lpValue;
5629 PPRINTER_ENUM_VALUESW ppev;
5631 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5633 if (pKeyName == NULL || *pKeyName == 0)
5634 return ERROR_INVALID_PARAMETER;
5636 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5637 if (ret != ERROR_SUCCESS)
5639 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5640 hPrinter, ret);
5641 return ret;
5644 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5645 if (ret != ERROR_SUCCESS)
5647 r = RegCloseKey (hkPrinter);
5648 if (r != ERROR_SUCCESS)
5649 WARN ("RegCloseKey returned %i\n", r);
5650 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5651 debugstr_w (pKeyName), ret);
5652 return ret;
5655 ret = RegCloseKey (hkPrinter);
5656 if (ret != ERROR_SUCCESS)
5658 ERR ("RegCloseKey returned %i\n", ret);
5659 r = RegCloseKey (hkSubKey);
5660 if (r != ERROR_SUCCESS)
5661 WARN ("RegCloseKey returned %i\n", r);
5662 return ret;
5665 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5666 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5667 if (ret != ERROR_SUCCESS)
5669 r = RegCloseKey (hkSubKey);
5670 if (r != ERROR_SUCCESS)
5671 WARN ("RegCloseKey returned %i\n", r);
5672 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5673 return ret;
5676 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5677 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5679 if (cValues == 0) /* empty key */
5681 r = RegCloseKey (hkSubKey);
5682 if (r != ERROR_SUCCESS)
5683 WARN ("RegCloseKey returned %i\n", r);
5684 *pcbEnumValues = *pnEnumValues = 0;
5685 return ERROR_SUCCESS;
5688 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5690 hHeap = GetProcessHeap ();
5691 if (hHeap == NULL)
5693 ERR ("GetProcessHeap failed\n");
5694 r = RegCloseKey (hkSubKey);
5695 if (r != ERROR_SUCCESS)
5696 WARN ("RegCloseKey returned %i\n", r);
5697 return ERROR_OUTOFMEMORY;
5700 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5701 if (lpValueName == NULL)
5703 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5704 r = RegCloseKey (hkSubKey);
5705 if (r != ERROR_SUCCESS)
5706 WARN ("RegCloseKey returned %i\n", r);
5707 return ERROR_OUTOFMEMORY;
5710 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5711 if (lpValue == NULL)
5713 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5714 if (HeapFree (hHeap, 0, lpValueName) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 r = RegCloseKey (hkSubKey);
5717 if (r != ERROR_SUCCESS)
5718 WARN ("RegCloseKey returned %i\n", r);
5719 return ERROR_OUTOFMEMORY;
5722 TRACE ("pass 1: calculating buffer required for all names and values\n");
5724 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5726 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5728 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5730 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5731 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5732 NULL, NULL, lpValue, &cbValueLen);
5733 if (ret != ERROR_SUCCESS)
5735 if (HeapFree (hHeap, 0, lpValue) == 0)
5736 WARN ("HeapFree failed with code %i\n", GetLastError ());
5737 if (HeapFree (hHeap, 0, lpValueName) == 0)
5738 WARN ("HeapFree failed with code %i\n", GetLastError ());
5739 r = RegCloseKey (hkSubKey);
5740 if (r != ERROR_SUCCESS)
5741 WARN ("RegCloseKey returned %i\n", r);
5742 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5743 return ret;
5746 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5747 debugstr_w (lpValueName), dwIndex,
5748 cbValueNameLen + 1, cbValueLen);
5750 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5751 cbBufSize += cbValueLen;
5754 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5756 *pcbEnumValues = cbBufSize;
5757 *pnEnumValues = cValues;
5759 if (cbEnumValues < cbBufSize) /* buffer too small */
5761 if (HeapFree (hHeap, 0, lpValue) == 0)
5762 WARN ("HeapFree failed with code %i\n", GetLastError ());
5763 if (HeapFree (hHeap, 0, lpValueName) == 0)
5764 WARN ("HeapFree failed with code %i\n", GetLastError ());
5765 r = RegCloseKey (hkSubKey);
5766 if (r != ERROR_SUCCESS)
5767 WARN ("RegCloseKey returned %i\n", r);
5768 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5769 return ERROR_MORE_DATA;
5772 TRACE ("pass 2: copying all names and values to buffer\n");
5774 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5775 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5777 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5779 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5780 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5781 NULL, &dwType, lpValue, &cbValueLen);
5782 if (ret != ERROR_SUCCESS)
5784 if (HeapFree (hHeap, 0, lpValue) == 0)
5785 WARN ("HeapFree failed with code %i\n", GetLastError ());
5786 if (HeapFree (hHeap, 0, lpValueName) == 0)
5787 WARN ("HeapFree failed with code %i\n", GetLastError ());
5788 r = RegCloseKey (hkSubKey);
5789 if (r != ERROR_SUCCESS)
5790 WARN ("RegCloseKey returned %i\n", r);
5791 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5792 return ret;
5795 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5796 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5797 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5798 pEnumValues += cbValueNameLen;
5800 /* return # of *bytes* (including trailing \0), not # of chars */
5801 ppev[dwIndex].cbValueName = cbValueNameLen;
5803 ppev[dwIndex].dwType = dwType;
5805 memcpy (pEnumValues, lpValue, cbValueLen);
5806 ppev[dwIndex].pData = pEnumValues;
5807 pEnumValues += cbValueLen;
5809 ppev[dwIndex].cbData = cbValueLen;
5811 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5812 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5815 if (HeapFree (hHeap, 0, lpValue) == 0)
5817 ret = GetLastError ();
5818 ERR ("HeapFree failed with code %i\n", ret);
5819 if (HeapFree (hHeap, 0, lpValueName) == 0)
5820 WARN ("HeapFree failed with code %i\n", GetLastError ());
5821 r = RegCloseKey (hkSubKey);
5822 if (r != ERROR_SUCCESS)
5823 WARN ("RegCloseKey returned %i\n", r);
5824 return ret;
5827 if (HeapFree (hHeap, 0, lpValueName) == 0)
5829 ret = GetLastError ();
5830 ERR ("HeapFree failed with code %i\n", ret);
5831 r = RegCloseKey (hkSubKey);
5832 if (r != ERROR_SUCCESS)
5833 WARN ("RegCloseKey returned %i\n", r);
5834 return ret;
5837 ret = RegCloseKey (hkSubKey);
5838 if (ret != ERROR_SUCCESS)
5840 ERR ("RegCloseKey returned %i\n", ret);
5841 return ret;
5844 return ERROR_SUCCESS;
5847 /*******************************************************************************
5848 * EnumPrinterDataExA [WINSPOOL.@]
5850 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5851 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5852 * what Windows 2000 SP1 does.
5855 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5856 LPBYTE pEnumValues, DWORD cbEnumValues,
5857 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5859 INT len;
5860 LPWSTR pKeyNameW;
5861 DWORD ret, dwIndex, dwBufSize;
5862 HANDLE hHeap;
5863 LPSTR pBuffer;
5865 TRACE ("%p %s\n", hPrinter, pKeyName);
5867 if (pKeyName == NULL || *pKeyName == 0)
5868 return ERROR_INVALID_PARAMETER;
5870 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5871 if (len == 0)
5873 ret = GetLastError ();
5874 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5875 return ret;
5878 hHeap = GetProcessHeap ();
5879 if (hHeap == NULL)
5881 ERR ("GetProcessHeap failed\n");
5882 return ERROR_OUTOFMEMORY;
5885 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5886 if (pKeyNameW == NULL)
5888 ERR ("Failed to allocate %i bytes from process heap\n",
5889 (LONG)(len * sizeof (WCHAR)));
5890 return ERROR_OUTOFMEMORY;
5893 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5895 ret = GetLastError ();
5896 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5897 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5898 WARN ("HeapFree failed with code %i\n", GetLastError ());
5899 return ret;
5902 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5903 pcbEnumValues, pnEnumValues);
5904 if (ret != ERROR_SUCCESS)
5906 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5907 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5909 return ret;
5912 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5914 ret = GetLastError ();
5915 ERR ("HeapFree failed with code %i\n", ret);
5916 return ret;
5919 if (*pnEnumValues == 0) /* empty key */
5920 return ERROR_SUCCESS;
5922 dwBufSize = 0;
5923 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5925 PPRINTER_ENUM_VALUESW ppev =
5926 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5928 if (dwBufSize < ppev->cbValueName)
5929 dwBufSize = ppev->cbValueName;
5931 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5932 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5933 dwBufSize = ppev->cbData;
5936 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5938 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5939 if (pBuffer == NULL)
5941 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5942 return ERROR_OUTOFMEMORY;
5945 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5947 PPRINTER_ENUM_VALUESW ppev =
5948 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5950 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5951 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5952 NULL);
5953 if (len == 0)
5955 ret = GetLastError ();
5956 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5957 if (HeapFree (hHeap, 0, pBuffer) == 0)
5958 WARN ("HeapFree failed with code %i\n", GetLastError ());
5959 return ret;
5962 memcpy (ppev->pValueName, pBuffer, len);
5964 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5966 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5967 ppev->dwType != REG_MULTI_SZ)
5968 continue;
5970 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5971 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5972 if (len == 0)
5974 ret = GetLastError ();
5975 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5976 if (HeapFree (hHeap, 0, pBuffer) == 0)
5977 WARN ("HeapFree failed with code %i\n", GetLastError ());
5978 return ret;
5981 memcpy (ppev->pData, pBuffer, len);
5983 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5984 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5987 if (HeapFree (hHeap, 0, pBuffer) == 0)
5989 ret = GetLastError ();
5990 ERR ("HeapFree failed with code %i\n", ret);
5991 return ret;
5994 return ERROR_SUCCESS;
5997 /******************************************************************************
5998 * AbortPrinter (WINSPOOL.@)
6000 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6002 FIXME("(%p), stub!\n", hPrinter);
6003 return TRUE;
6006 /******************************************************************************
6007 * AddPortA (WINSPOOL.@)
6009 * See AddPortW.
6012 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6014 LPWSTR nameW = NULL;
6015 LPWSTR monitorW = NULL;
6016 DWORD len;
6017 BOOL res;
6019 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6021 if (pName) {
6022 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6023 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6024 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6027 if (pMonitorName) {
6028 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6029 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6030 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6032 res = AddPortW(nameW, hWnd, monitorW);
6033 HeapFree(GetProcessHeap(), 0, nameW);
6034 HeapFree(GetProcessHeap(), 0, monitorW);
6035 return res;
6038 /******************************************************************************
6039 * AddPortW (WINSPOOL.@)
6041 * Add a Port for a specific Monitor
6043 * PARAMS
6044 * pName [I] Servername or NULL (local Computer)
6045 * hWnd [I] Handle to parent Window for the Dialog-Box
6046 * pMonitorName [I] Name of the Monitor that manage the Port
6048 * RETURNS
6049 * Success: TRUE
6050 * Failure: FALSE
6053 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6055 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6057 if ((backend == NULL) && !load_backend()) return FALSE;
6059 if (!pMonitorName) {
6060 SetLastError(RPC_X_NULL_REF_POINTER);
6061 return FALSE;
6064 return backend->fpAddPort(pName, hWnd, pMonitorName);
6067 /******************************************************************************
6068 * AddPortExA (WINSPOOL.@)
6070 * See AddPortExW.
6073 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6075 PORT_INFO_2W pi2W;
6076 PORT_INFO_2A * pi2A;
6077 LPWSTR nameW = NULL;
6078 LPWSTR monitorW = NULL;
6079 DWORD len;
6080 BOOL res;
6082 pi2A = (PORT_INFO_2A *) pBuffer;
6084 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6085 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6087 if ((level < 1) || (level > 2)) {
6088 SetLastError(ERROR_INVALID_LEVEL);
6089 return FALSE;
6092 if (!pi2A) {
6093 SetLastError(ERROR_INVALID_PARAMETER);
6094 return FALSE;
6097 if (pName) {
6098 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6099 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6100 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6103 if (pMonitorName) {
6104 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6105 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6106 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6109 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6111 if (pi2A->pPortName) {
6112 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6113 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6114 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6117 if (level > 1) {
6118 if (pi2A->pMonitorName) {
6119 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6120 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6121 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6124 if (pi2A->pDescription) {
6125 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6126 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6127 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6129 pi2W.fPortType = pi2A->fPortType;
6130 pi2W.Reserved = pi2A->Reserved;
6133 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6135 HeapFree(GetProcessHeap(), 0, nameW);
6136 HeapFree(GetProcessHeap(), 0, monitorW);
6137 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6138 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6139 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6140 return res;
6144 /******************************************************************************
6145 * AddPortExW (WINSPOOL.@)
6147 * Add a Port for a specific Monitor, without presenting a user interface
6149 * PARAMS
6150 * pName [I] Servername or NULL (local Computer)
6151 * level [I] Structure-Level (1 or 2) for pBuffer
6152 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6153 * pMonitorName [I] Name of the Monitor that manage the Port
6155 * RETURNS
6156 * Success: TRUE
6157 * Failure: FALSE
6160 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6162 PORT_INFO_2W * pi2;
6164 pi2 = (PORT_INFO_2W *) pBuffer;
6166 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6167 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6168 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6169 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6171 if ((backend == NULL) && !load_backend()) return FALSE;
6173 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6174 SetLastError(ERROR_INVALID_PARAMETER);
6175 return FALSE;
6178 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6181 /******************************************************************************
6182 * AddPrinterConnectionA (WINSPOOL.@)
6184 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6186 FIXME("%s\n", debugstr_a(pName));
6187 return FALSE;
6190 /******************************************************************************
6191 * AddPrinterConnectionW (WINSPOOL.@)
6193 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6195 FIXME("%s\n", debugstr_w(pName));
6196 return FALSE;
6199 /******************************************************************************
6200 * AddPrinterDriverExW (WINSPOOL.@)
6202 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6204 * PARAMS
6205 * pName [I] Servername or NULL (local Computer)
6206 * level [I] Level for the supplied DRIVER_INFO_*W struct
6207 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6208 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6210 * RESULTS
6211 * Success: TRUE
6212 * Failure: FALSE
6215 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6217 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6219 if ((backend == NULL) && !load_backend()) return FALSE;
6221 if (level < 2 || level == 5 || level == 7 || level > 8) {
6222 SetLastError(ERROR_INVALID_LEVEL);
6223 return FALSE;
6226 if (!pDriverInfo) {
6227 SetLastError(ERROR_INVALID_PARAMETER);
6228 return FALSE;
6231 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6234 /******************************************************************************
6235 * AddPrinterDriverExA (WINSPOOL.@)
6237 * See AddPrinterDriverExW.
6240 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6242 DRIVER_INFO_8A *diA;
6243 DRIVER_INFO_8W diW;
6244 LPWSTR nameW = NULL;
6245 DWORD lenA;
6246 DWORD len;
6247 DWORD res = FALSE;
6249 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6251 diA = (DRIVER_INFO_8A *) pDriverInfo;
6252 ZeroMemory(&diW, sizeof(diW));
6254 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6255 SetLastError(ERROR_INVALID_LEVEL);
6256 return FALSE;
6259 if (diA == NULL) {
6260 SetLastError(ERROR_INVALID_PARAMETER);
6261 return FALSE;
6264 /* convert servername to unicode */
6265 if (pName) {
6266 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6267 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6268 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6271 /* common fields */
6272 diW.cVersion = diA->cVersion;
6274 if (diA->pName) {
6275 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6276 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6277 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6280 if (diA->pEnvironment) {
6281 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6282 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6283 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6286 if (diA->pDriverPath) {
6287 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6288 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6289 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6292 if (diA->pDataFile) {
6293 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6294 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6295 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6298 if (diA->pConfigFile) {
6299 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6300 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6301 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6304 if ((Level > 2) && diA->pDependentFiles) {
6305 lenA = multi_sz_lenA(diA->pDependentFiles);
6306 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6307 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6308 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6311 if ((Level > 2) && diA->pMonitorName) {
6312 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6313 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6314 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6317 if ((Level > 3) && diA->pDefaultDataType) {
6318 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6319 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6320 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6323 if ((Level > 3) && diA->pszzPreviousNames) {
6324 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6325 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6326 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6327 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6330 if ((Level > 5) && diA->pszMfgName) {
6331 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6332 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6333 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6336 if ((Level > 5) && diA->pszOEMUrl) {
6337 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6338 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6339 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6342 if ((Level > 5) && diA->pszHardwareID) {
6343 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6344 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6345 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6348 if ((Level > 5) && diA->pszProvider) {
6349 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6350 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6351 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6354 if (Level > 7) {
6355 FIXME("level %u is incomplete\n", Level);
6358 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6359 TRACE("got %u with %u\n", res, GetLastError());
6360 HeapFree(GetProcessHeap(), 0, nameW);
6361 HeapFree(GetProcessHeap(), 0, diW.pName);
6362 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6363 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6364 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6365 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6366 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6367 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6368 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6369 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6370 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6371 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6372 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6373 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6375 TRACE("=> %u with %u\n", res, GetLastError());
6376 return res;
6379 /******************************************************************************
6380 * ConfigurePortA (WINSPOOL.@)
6382 * See ConfigurePortW.
6385 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6387 LPWSTR nameW = NULL;
6388 LPWSTR portW = NULL;
6389 INT len;
6390 DWORD res;
6392 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6394 /* convert servername to unicode */
6395 if (pName) {
6396 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6397 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6398 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6401 /* convert portname to unicode */
6402 if (pPortName) {
6403 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6404 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6405 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6408 res = ConfigurePortW(nameW, hWnd, portW);
6409 HeapFree(GetProcessHeap(), 0, nameW);
6410 HeapFree(GetProcessHeap(), 0, portW);
6411 return res;
6414 /******************************************************************************
6415 * ConfigurePortW (WINSPOOL.@)
6417 * Display the Configuration-Dialog for a specific Port
6419 * PARAMS
6420 * pName [I] Servername or NULL (local Computer)
6421 * hWnd [I] Handle to parent Window for the Dialog-Box
6422 * pPortName [I] Name of the Port, that should be configured
6424 * RETURNS
6425 * Success: TRUE
6426 * Failure: FALSE
6429 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6432 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6434 if ((backend == NULL) && !load_backend()) return FALSE;
6436 if (!pPortName) {
6437 SetLastError(RPC_X_NULL_REF_POINTER);
6438 return FALSE;
6441 return backend->fpConfigurePort(pName, hWnd, pPortName);
6444 /******************************************************************************
6445 * ConnectToPrinterDlg (WINSPOOL.@)
6447 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6449 FIXME("%p %x\n", hWnd, Flags);
6450 return NULL;
6453 /******************************************************************************
6454 * DeletePrinterConnectionA (WINSPOOL.@)
6456 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6458 FIXME("%s\n", debugstr_a(pName));
6459 return TRUE;
6462 /******************************************************************************
6463 * DeletePrinterConnectionW (WINSPOOL.@)
6465 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6467 FIXME("%s\n", debugstr_w(pName));
6468 return TRUE;
6471 /******************************************************************************
6472 * DeletePrinterDriverExW (WINSPOOL.@)
6474 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6475 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6477 HKEY hkey_drivers;
6478 BOOL ret = FALSE;
6480 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6481 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6483 if(pName && pName[0])
6485 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6486 SetLastError(ERROR_INVALID_PARAMETER);
6487 return FALSE;
6490 if(dwDeleteFlag)
6492 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6493 SetLastError(ERROR_INVALID_PARAMETER);
6494 return FALSE;
6497 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6499 if(!hkey_drivers)
6501 ERR("Can't open drivers key\n");
6502 return FALSE;
6505 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6506 ret = TRUE;
6508 RegCloseKey(hkey_drivers);
6510 return ret;
6513 /******************************************************************************
6514 * DeletePrinterDriverExA (WINSPOOL.@)
6516 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6517 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6519 UNICODE_STRING NameW, EnvW, DriverW;
6520 BOOL ret;
6522 asciitounicode(&NameW, pName);
6523 asciitounicode(&EnvW, pEnvironment);
6524 asciitounicode(&DriverW, pDriverName);
6526 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6528 RtlFreeUnicodeString(&DriverW);
6529 RtlFreeUnicodeString(&EnvW);
6530 RtlFreeUnicodeString(&NameW);
6532 return ret;
6535 /******************************************************************************
6536 * DeletePrinterDataExW (WINSPOOL.@)
6538 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6539 LPCWSTR pValueName)
6541 FIXME("%p %s %s\n", hPrinter,
6542 debugstr_w(pKeyName), debugstr_w(pValueName));
6543 return ERROR_INVALID_PARAMETER;
6546 /******************************************************************************
6547 * DeletePrinterDataExA (WINSPOOL.@)
6549 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6550 LPCSTR pValueName)
6552 FIXME("%p %s %s\n", hPrinter,
6553 debugstr_a(pKeyName), debugstr_a(pValueName));
6554 return ERROR_INVALID_PARAMETER;
6557 /******************************************************************************
6558 * DeletePrintProcessorA (WINSPOOL.@)
6560 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6562 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6563 debugstr_a(pPrintProcessorName));
6564 return TRUE;
6567 /******************************************************************************
6568 * DeletePrintProcessorW (WINSPOOL.@)
6570 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6572 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6573 debugstr_w(pPrintProcessorName));
6574 return TRUE;
6577 /******************************************************************************
6578 * DeletePrintProvidorA (WINSPOOL.@)
6580 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6582 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6583 debugstr_a(pPrintProviderName));
6584 return TRUE;
6587 /******************************************************************************
6588 * DeletePrintProvidorW (WINSPOOL.@)
6590 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6592 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6593 debugstr_w(pPrintProviderName));
6594 return TRUE;
6597 /******************************************************************************
6598 * EnumFormsA (WINSPOOL.@)
6600 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6601 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6603 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6604 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6605 return FALSE;
6608 /******************************************************************************
6609 * EnumFormsW (WINSPOOL.@)
6611 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6612 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6614 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6615 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6616 return FALSE;
6619 /*****************************************************************************
6620 * EnumMonitorsA [WINSPOOL.@]
6622 * See EnumMonitorsW.
6625 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6626 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6628 BOOL res;
6629 LPBYTE bufferW = NULL;
6630 LPWSTR nameW = NULL;
6631 DWORD needed = 0;
6632 DWORD numentries = 0;
6633 INT len;
6635 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6636 cbBuf, pcbNeeded, pcReturned);
6638 /* convert servername to unicode */
6639 if (pName) {
6640 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6641 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6642 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6644 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6645 needed = cbBuf * sizeof(WCHAR);
6646 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6647 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6649 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6650 if (pcbNeeded) needed = *pcbNeeded;
6651 /* HeapReAlloc return NULL, when bufferW was NULL */
6652 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6653 HeapAlloc(GetProcessHeap(), 0, needed);
6655 /* Try again with the large Buffer */
6656 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6658 numentries = pcReturned ? *pcReturned : 0;
6659 needed = 0;
6661 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6662 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6664 if (res) {
6665 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6666 DWORD entrysize = 0;
6667 DWORD index;
6668 LPSTR ptr;
6669 LPMONITOR_INFO_2W mi2w;
6670 LPMONITOR_INFO_2A mi2a;
6672 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6673 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6675 /* First pass: calculate the size for all Entries */
6676 mi2w = (LPMONITOR_INFO_2W) bufferW;
6677 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6678 index = 0;
6679 while (index < numentries) {
6680 index++;
6681 needed += entrysize; /* MONITOR_INFO_?A */
6682 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6684 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6685 NULL, 0, NULL, NULL);
6686 if (Level > 1) {
6687 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6688 NULL, 0, NULL, NULL);
6689 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6690 NULL, 0, NULL, NULL);
6692 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6693 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6694 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6697 /* check for errors and quit on failure */
6698 if (cbBuf < needed) {
6699 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6700 res = FALSE;
6701 goto emA_cleanup;
6703 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6704 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6705 cbBuf -= len ; /* free Bytes in the user-Buffer */
6706 mi2w = (LPMONITOR_INFO_2W) bufferW;
6707 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6708 index = 0;
6709 /* Second Pass: Fill the User Buffer (if we have one) */
6710 while ((index < numentries) && pMonitors) {
6711 index++;
6712 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6713 mi2a->pName = ptr;
6714 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6715 ptr, cbBuf , NULL, NULL);
6716 ptr += len;
6717 cbBuf -= len;
6718 if (Level > 1) {
6719 mi2a->pEnvironment = ptr;
6720 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6721 ptr, cbBuf, NULL, NULL);
6722 ptr += len;
6723 cbBuf -= len;
6725 mi2a->pDLLName = ptr;
6726 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6727 ptr, cbBuf, NULL, NULL);
6728 ptr += len;
6729 cbBuf -= len;
6731 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6732 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6733 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6736 emA_cleanup:
6737 if (pcbNeeded) *pcbNeeded = needed;
6738 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6740 HeapFree(GetProcessHeap(), 0, nameW);
6741 HeapFree(GetProcessHeap(), 0, bufferW);
6743 TRACE("returning %d with %d (%d byte for %d entries)\n",
6744 (res), GetLastError(), needed, numentries);
6746 return (res);
6750 /*****************************************************************************
6751 * EnumMonitorsW [WINSPOOL.@]
6753 * Enumerate available Port-Monitors
6755 * PARAMS
6756 * pName [I] Servername or NULL (local Computer)
6757 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6758 * pMonitors [O] PTR to Buffer that receives the Result
6759 * cbBuf [I] Size of Buffer at pMonitors
6760 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6761 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6763 * RETURNS
6764 * Success: TRUE
6765 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6768 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6769 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6772 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6773 cbBuf, pcbNeeded, pcReturned);
6775 if ((backend == NULL) && !load_backend()) return FALSE;
6777 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6778 SetLastError(RPC_X_NULL_REF_POINTER);
6779 return FALSE;
6782 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6785 /******************************************************************************
6786 * SpoolerInit (WINSPOOL.@)
6788 * Initialize the Spooler
6790 * RETURNS
6791 * Success: TRUE
6792 * Failure: FALSE
6794 * NOTES
6795 * The function fails on windows, when the spooler service is not running
6798 BOOL WINAPI SpoolerInit(void)
6801 if ((backend == NULL) && !load_backend()) return FALSE;
6802 return TRUE;
6805 /******************************************************************************
6806 * XcvDataW (WINSPOOL.@)
6808 * Execute commands in the Printmonitor DLL
6810 * PARAMS
6811 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6812 * pszDataName [i] Name of the command to execute
6813 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6814 * cbInputData [i] Size in Bytes of Buffer at pInputData
6815 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6816 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6817 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6818 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6820 * RETURNS
6821 * Success: TRUE
6822 * Failure: FALSE
6824 * NOTES
6825 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6826 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6828 * Minimal List of commands, that a Printmonitor DLL should support:
6830 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6831 *| "AddPort" : Add a Port
6832 *| "DeletePort": Delete a Port
6834 * Many Printmonitors support additional commands. Examples for localspl.dll:
6835 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6836 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6839 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6840 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6841 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6843 opened_printer_t *printer;
6845 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6846 pInputData, cbInputData, pOutputData,
6847 cbOutputData, pcbOutputNeeded, pdwStatus);
6849 if ((backend == NULL) && !load_backend()) return FALSE;
6851 printer = get_opened_printer(hXcv);
6852 if (!printer || (!printer->backend_printer)) {
6853 SetLastError(ERROR_INVALID_HANDLE);
6854 return FALSE;
6857 if (!pcbOutputNeeded) {
6858 SetLastError(ERROR_INVALID_PARAMETER);
6859 return FALSE;
6862 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6863 SetLastError(RPC_X_NULL_REF_POINTER);
6864 return FALSE;
6867 *pcbOutputNeeded = 0;
6869 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6870 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6874 /*****************************************************************************
6875 * EnumPrinterDataA [WINSPOOL.@]
6878 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6879 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6880 DWORD cbData, LPDWORD pcbData )
6882 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6883 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6884 return ERROR_NO_MORE_ITEMS;
6887 /*****************************************************************************
6888 * EnumPrinterDataW [WINSPOOL.@]
6891 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6892 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6893 DWORD cbData, LPDWORD pcbData )
6895 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6896 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6897 return ERROR_NO_MORE_ITEMS;
6900 /*****************************************************************************
6901 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6904 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6905 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6906 LPDWORD pcbNeeded, LPDWORD pcReturned)
6908 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6909 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6910 pcbNeeded, pcReturned);
6911 return FALSE;
6914 /*****************************************************************************
6915 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6918 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6919 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6920 LPDWORD pcbNeeded, LPDWORD pcReturned)
6922 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6923 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6924 pcbNeeded, pcReturned);
6925 return FALSE;
6928 /*****************************************************************************
6929 * EnumPrintProcessorsA [WINSPOOL.@]
6931 * See EnumPrintProcessorsW.
6934 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6935 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6937 BOOL res;
6938 LPBYTE bufferW = NULL;
6939 LPWSTR nameW = NULL;
6940 LPWSTR envW = NULL;
6941 DWORD needed = 0;
6942 DWORD numentries = 0;
6943 INT len;
6945 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6946 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6948 /* convert names to unicode */
6949 if (pName) {
6950 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6951 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6952 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6954 if (pEnvironment) {
6955 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6956 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6957 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6960 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6961 needed = cbBuf * sizeof(WCHAR);
6962 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6963 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6965 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6966 if (pcbNeeded) needed = *pcbNeeded;
6967 /* HeapReAlloc return NULL, when bufferW was NULL */
6968 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6969 HeapAlloc(GetProcessHeap(), 0, needed);
6971 /* Try again with the large Buffer */
6972 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6974 numentries = pcReturned ? *pcReturned : 0;
6975 needed = 0;
6977 if (res) {
6978 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6979 DWORD index;
6980 LPSTR ptr;
6981 PPRINTPROCESSOR_INFO_1W ppiw;
6982 PPRINTPROCESSOR_INFO_1A ppia;
6984 /* First pass: calculate the size for all Entries */
6985 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6986 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6987 index = 0;
6988 while (index < numentries) {
6989 index++;
6990 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6991 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6993 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6994 NULL, 0, NULL, NULL);
6996 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6997 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7000 /* check for errors and quit on failure */
7001 if (cbBuf < needed) {
7002 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7003 res = FALSE;
7004 goto epp_cleanup;
7007 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7008 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7009 cbBuf -= len ; /* free Bytes in the user-Buffer */
7010 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7011 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7012 index = 0;
7013 /* Second Pass: Fill the User Buffer (if we have one) */
7014 while ((index < numentries) && pPPInfo) {
7015 index++;
7016 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7017 ppia->pName = ptr;
7018 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7019 ptr, cbBuf , NULL, NULL);
7020 ptr += len;
7021 cbBuf -= len;
7023 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7024 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7028 epp_cleanup:
7029 if (pcbNeeded) *pcbNeeded = needed;
7030 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7032 HeapFree(GetProcessHeap(), 0, nameW);
7033 HeapFree(GetProcessHeap(), 0, envW);
7034 HeapFree(GetProcessHeap(), 0, bufferW);
7036 TRACE("returning %d with %d (%d byte for %d entries)\n",
7037 (res), GetLastError(), needed, numentries);
7039 return (res);
7042 /*****************************************************************************
7043 * EnumPrintProcessorsW [WINSPOOL.@]
7045 * Enumerate available Print Processors
7047 * PARAMS
7048 * pName [I] Servername or NULL (local Computer)
7049 * pEnvironment [I] Printing-Environment or NULL (Default)
7050 * Level [I] Structure-Level (Only 1 is allowed)
7051 * pPPInfo [O] PTR to Buffer that receives the Result
7052 * cbBuf [I] Size of Buffer at pPPInfo
7053 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7054 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7056 * RETURNS
7057 * Success: TRUE
7058 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7061 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7062 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7065 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7066 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7068 if ((backend == NULL) && !load_backend()) return FALSE;
7070 if (!pcbNeeded || !pcReturned) {
7071 SetLastError(RPC_X_NULL_REF_POINTER);
7072 return FALSE;
7075 if (!pPPInfo && (cbBuf > 0)) {
7076 SetLastError(ERROR_INVALID_USER_BUFFER);
7077 return FALSE;
7080 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7081 cbBuf, pcbNeeded, pcReturned);
7084 /*****************************************************************************
7085 * ExtDeviceMode [WINSPOOL.@]
7088 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7089 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7090 DWORD fMode)
7092 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7093 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7094 debugstr_a(pProfile), fMode);
7095 return -1;
7098 /*****************************************************************************
7099 * FindClosePrinterChangeNotification [WINSPOOL.@]
7102 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7104 FIXME("Stub: %p\n", hChange);
7105 return TRUE;
7108 /*****************************************************************************
7109 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7112 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7113 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7115 FIXME("Stub: %p %x %x %p\n",
7116 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7117 return INVALID_HANDLE_VALUE;
7120 /*****************************************************************************
7121 * FindNextPrinterChangeNotification [WINSPOOL.@]
7124 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7125 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7127 FIXME("Stub: %p %p %p %p\n",
7128 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7129 return FALSE;
7132 /*****************************************************************************
7133 * FreePrinterNotifyInfo [WINSPOOL.@]
7136 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7138 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7139 return TRUE;
7142 /*****************************************************************************
7143 * string_to_buf
7145 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7146 * ansi depending on the unicode parameter.
7148 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7150 if(!str)
7152 *size = 0;
7153 return TRUE;
7156 if(unicode)
7158 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7159 if(*size <= cb)
7161 memcpy(ptr, str, *size);
7162 return TRUE;
7164 return FALSE;
7166 else
7168 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7169 if(*size <= cb)
7171 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7172 return TRUE;
7174 return FALSE;
7178 /*****************************************************************************
7179 * get_job_info_1
7181 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7182 LPDWORD pcbNeeded, BOOL unicode)
7184 DWORD size, left = cbBuf;
7185 BOOL space = (cbBuf > 0);
7186 LPBYTE ptr = buf;
7188 *pcbNeeded = 0;
7190 if(space)
7192 ji1->JobId = job->job_id;
7195 string_to_buf(job->document_title, ptr, left, &size, unicode);
7196 if(space && size <= left)
7198 ji1->pDocument = (LPWSTR)ptr;
7199 ptr += size;
7200 left -= size;
7202 else
7203 space = FALSE;
7204 *pcbNeeded += size;
7206 if (job->printer_name)
7208 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7209 if(space && size <= left)
7211 ji1->pPrinterName = (LPWSTR)ptr;
7212 ptr += size;
7213 left -= size;
7215 else
7216 space = FALSE;
7217 *pcbNeeded += size;
7220 return space;
7223 /*****************************************************************************
7224 * get_job_info_2
7226 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7227 LPDWORD pcbNeeded, BOOL unicode)
7229 DWORD size, left = cbBuf;
7230 DWORD shift;
7231 BOOL space = (cbBuf > 0);
7232 LPBYTE ptr = buf;
7233 LPDEVMODEA dmA = NULL;
7234 LPDEVMODEW devmode;
7236 *pcbNeeded = 0;
7238 if(space)
7240 ji2->JobId = job->job_id;
7243 string_to_buf(job->document_title, ptr, left, &size, unicode);
7244 if(space && size <= left)
7246 ji2->pDocument = (LPWSTR)ptr;
7247 ptr += size;
7248 left -= size;
7250 else
7251 space = FALSE;
7252 *pcbNeeded += size;
7254 if (job->printer_name)
7256 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7257 if(space && size <= left)
7259 ji2->pPrinterName = (LPWSTR)ptr;
7260 ptr += size;
7261 left -= size;
7263 else
7264 space = FALSE;
7265 *pcbNeeded += size;
7268 if (job->devmode)
7270 if (!unicode)
7272 dmA = DEVMODEdupWtoA(job->devmode);
7273 devmode = (LPDEVMODEW) dmA;
7274 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7276 else
7278 devmode = job->devmode;
7279 size = devmode->dmSize + devmode->dmDriverExtra;
7282 if (!devmode)
7283 FIXME("Can't convert DEVMODE W to A\n");
7284 else
7286 /* align DEVMODE to a DWORD boundary */
7287 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7288 size += shift;
7290 if (size <= left)
7292 ptr += shift;
7293 memcpy(ptr, devmode, size-shift);
7294 ji2->pDevMode = (LPDEVMODEW)ptr;
7295 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7296 ptr += size;
7297 left -= size;
7299 else
7300 space = FALSE;
7301 *pcbNeeded +=size;
7305 return space;
7308 /*****************************************************************************
7309 * get_job_info
7311 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7312 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7314 BOOL ret = FALSE;
7315 DWORD needed = 0, size;
7316 job_t *job;
7317 LPBYTE ptr = pJob;
7319 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7321 EnterCriticalSection(&printer_handles_cs);
7322 job = get_job(hPrinter, JobId);
7323 if(!job)
7324 goto end;
7326 switch(Level)
7328 case 1:
7329 size = sizeof(JOB_INFO_1W);
7330 if(cbBuf >= size)
7332 cbBuf -= size;
7333 ptr += size;
7334 memset(pJob, 0, size);
7336 else
7337 cbBuf = 0;
7338 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7339 needed += size;
7340 break;
7342 case 2:
7343 size = sizeof(JOB_INFO_2W);
7344 if(cbBuf >= size)
7346 cbBuf -= size;
7347 ptr += size;
7348 memset(pJob, 0, size);
7350 else
7351 cbBuf = 0;
7352 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7353 needed += size;
7354 break;
7356 case 3:
7357 size = sizeof(JOB_INFO_3);
7358 if(cbBuf >= size)
7360 cbBuf -= size;
7361 memset(pJob, 0, size);
7362 ret = TRUE;
7364 else
7365 cbBuf = 0;
7366 needed = size;
7367 break;
7369 default:
7370 SetLastError(ERROR_INVALID_LEVEL);
7371 goto end;
7373 if(pcbNeeded)
7374 *pcbNeeded = needed;
7375 end:
7376 LeaveCriticalSection(&printer_handles_cs);
7377 return ret;
7380 /*****************************************************************************
7381 * GetJobA [WINSPOOL.@]
7384 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7385 DWORD cbBuf, LPDWORD pcbNeeded)
7387 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7390 /*****************************************************************************
7391 * GetJobW [WINSPOOL.@]
7394 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7395 DWORD cbBuf, LPDWORD pcbNeeded)
7397 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7400 /*****************************************************************************
7401 * schedule_pipe
7403 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7405 #ifdef HAVE_FORK
7406 char *unixname, *cmdA;
7407 DWORD len;
7408 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7409 BOOL ret = FALSE;
7410 char buf[1024];
7412 if(!(unixname = wine_get_unix_file_name(filename)))
7413 return FALSE;
7415 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7416 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7417 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7419 TRACE("printing with: %s\n", cmdA);
7421 if((file_fd = open(unixname, O_RDONLY)) == -1)
7422 goto end;
7424 if (pipe(fds))
7426 ERR("pipe() failed!\n");
7427 goto end;
7430 if (fork() == 0)
7432 close(0);
7433 dup2(fds[0], 0);
7434 close(fds[1]);
7436 /* reset signals that we previously set to SIG_IGN */
7437 signal(SIGPIPE, SIG_DFL);
7438 signal(SIGCHLD, SIG_DFL);
7440 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7441 _exit(1);
7444 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7445 write(fds[1], buf, no_read);
7447 ret = TRUE;
7449 end:
7450 if(file_fd != -1) close(file_fd);
7451 if(fds[0] != -1) close(fds[0]);
7452 if(fds[1] != -1) close(fds[1]);
7454 HeapFree(GetProcessHeap(), 0, cmdA);
7455 HeapFree(GetProcessHeap(), 0, unixname);
7456 return ret;
7457 #else
7458 return FALSE;
7459 #endif
7462 /*****************************************************************************
7463 * schedule_lpr
7465 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7467 WCHAR *cmd;
7468 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7469 BOOL r;
7471 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7472 sprintfW(cmd, fmtW, printer_name);
7474 r = schedule_pipe(cmd, filename);
7476 HeapFree(GetProcessHeap(), 0, cmd);
7477 return r;
7480 /*****************************************************************************
7481 * schedule_cups
7483 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7485 #ifdef SONAME_LIBCUPS
7486 if(pcupsPrintFile)
7488 char *unixname, *queue, *unix_doc_title;
7489 DWORD len;
7490 BOOL ret;
7492 if(!(unixname = wine_get_unix_file_name(filename)))
7493 return FALSE;
7495 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7496 queue = HeapAlloc(GetProcessHeap(), 0, len);
7497 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7499 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7500 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7501 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7503 TRACE("printing via cups\n");
7504 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7505 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7506 HeapFree(GetProcessHeap(), 0, queue);
7507 HeapFree(GetProcessHeap(), 0, unixname);
7508 return ret;
7510 else
7511 #endif
7513 return schedule_lpr(printer_name, filename);
7517 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7519 LPWSTR filename;
7521 switch(msg)
7523 case WM_INITDIALOG:
7524 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7525 return TRUE;
7527 case WM_COMMAND:
7528 if(HIWORD(wparam) == BN_CLICKED)
7530 if(LOWORD(wparam) == IDOK)
7532 HANDLE hf;
7533 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7534 LPWSTR *output;
7536 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7537 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7539 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7541 WCHAR caption[200], message[200];
7542 int mb_ret;
7544 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7545 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7546 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7547 if(mb_ret == IDCANCEL)
7549 HeapFree(GetProcessHeap(), 0, filename);
7550 return TRUE;
7553 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7554 if(hf == INVALID_HANDLE_VALUE)
7556 WCHAR caption[200], message[200];
7558 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7559 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7560 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7561 HeapFree(GetProcessHeap(), 0, filename);
7562 return TRUE;
7564 CloseHandle(hf);
7565 DeleteFileW(filename);
7566 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7567 *output = filename;
7568 EndDialog(hwnd, IDOK);
7569 return TRUE;
7571 if(LOWORD(wparam) == IDCANCEL)
7573 EndDialog(hwnd, IDCANCEL);
7574 return TRUE;
7577 return FALSE;
7579 return FALSE;
7582 /*****************************************************************************
7583 * get_filename
7585 static BOOL get_filename(LPWSTR *filename)
7587 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7588 file_dlg_proc, (LPARAM)filename) == IDOK;
7591 /*****************************************************************************
7592 * schedule_file
7594 static BOOL schedule_file(LPCWSTR filename)
7596 LPWSTR output = NULL;
7598 if(get_filename(&output))
7600 BOOL r;
7601 TRACE("copy to %s\n", debugstr_w(output));
7602 r = CopyFileW(filename, output, FALSE);
7603 HeapFree(GetProcessHeap(), 0, output);
7604 return r;
7606 return FALSE;
7609 /*****************************************************************************
7610 * schedule_unixfile
7612 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7614 int in_fd, out_fd, no_read;
7615 char buf[1024];
7616 BOOL ret = FALSE;
7617 char *unixname, *outputA;
7618 DWORD len;
7620 if(!(unixname = wine_get_unix_file_name(filename)))
7621 return FALSE;
7623 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7624 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7625 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7627 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7628 in_fd = open(unixname, O_RDONLY);
7629 if(out_fd == -1 || in_fd == -1)
7630 goto end;
7632 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7633 write(out_fd, buf, no_read);
7635 ret = TRUE;
7636 end:
7637 if(in_fd != -1) close(in_fd);
7638 if(out_fd != -1) close(out_fd);
7639 HeapFree(GetProcessHeap(), 0, outputA);
7640 HeapFree(GetProcessHeap(), 0, unixname);
7641 return ret;
7644 /*****************************************************************************
7645 * ScheduleJob [WINSPOOL.@]
7648 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7650 opened_printer_t *printer;
7651 BOOL ret = FALSE;
7652 struct list *cursor, *cursor2;
7654 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7655 EnterCriticalSection(&printer_handles_cs);
7656 printer = get_opened_printer(hPrinter);
7657 if(!printer)
7658 goto end;
7660 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7662 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7663 HANDLE hf;
7665 if(job->job_id != dwJobID) continue;
7667 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7668 if(hf != INVALID_HANDLE_VALUE)
7670 PRINTER_INFO_5W *pi5 = NULL;
7671 LPWSTR portname = job->portname;
7672 DWORD needed;
7673 HKEY hkey;
7674 WCHAR output[1024];
7675 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7676 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7678 if (!portname)
7680 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7681 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7682 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7683 portname = pi5->pPortName;
7685 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7686 debugstr_w(portname));
7688 output[0] = 0;
7690 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7691 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7693 DWORD type, count = sizeof(output);
7694 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7695 RegCloseKey(hkey);
7697 if(output[0] == '|')
7699 ret = schedule_pipe(output + 1, job->filename);
7701 else if(output[0])
7703 ret = schedule_unixfile(output, job->filename);
7705 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7707 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7709 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7711 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7713 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7715 ret = schedule_file(job->filename);
7717 else
7719 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7721 HeapFree(GetProcessHeap(), 0, pi5);
7722 CloseHandle(hf);
7723 DeleteFileW(job->filename);
7725 list_remove(cursor);
7726 HeapFree(GetProcessHeap(), 0, job->document_title);
7727 HeapFree(GetProcessHeap(), 0, job->printer_name);
7728 HeapFree(GetProcessHeap(), 0, job->portname);
7729 HeapFree(GetProcessHeap(), 0, job->filename);
7730 HeapFree(GetProcessHeap(), 0, job->devmode);
7731 HeapFree(GetProcessHeap(), 0, job);
7732 break;
7734 end:
7735 LeaveCriticalSection(&printer_handles_cs);
7736 return ret;
7739 /*****************************************************************************
7740 * StartDocDlgA [WINSPOOL.@]
7742 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7744 UNICODE_STRING usBuffer;
7745 DOCINFOW docW;
7746 LPWSTR retW;
7747 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7748 LPSTR ret = NULL;
7750 docW.cbSize = sizeof(docW);
7751 if (doc->lpszDocName)
7753 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7754 if (!(docW.lpszDocName = docnameW)) return NULL;
7756 if (doc->lpszOutput)
7758 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7759 if (!(docW.lpszOutput = outputW)) return NULL;
7761 if (doc->lpszDatatype)
7763 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7764 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7766 docW.fwType = doc->fwType;
7768 retW = StartDocDlgW(hPrinter, &docW);
7770 if(retW)
7772 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7773 ret = HeapAlloc(GetProcessHeap(), 0, len);
7774 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7775 HeapFree(GetProcessHeap(), 0, retW);
7778 HeapFree(GetProcessHeap(), 0, datatypeW);
7779 HeapFree(GetProcessHeap(), 0, outputW);
7780 HeapFree(GetProcessHeap(), 0, docnameW);
7782 return ret;
7785 /*****************************************************************************
7786 * StartDocDlgW [WINSPOOL.@]
7788 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7789 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7790 * port is "FILE:". Also returns the full path if passed a relative path.
7792 * The caller should free the returned string from the process heap.
7794 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7796 LPWSTR ret = NULL;
7797 DWORD len, attr;
7799 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7801 PRINTER_INFO_5W *pi5;
7802 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7803 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7804 return NULL;
7805 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7806 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7807 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7809 HeapFree(GetProcessHeap(), 0, pi5);
7810 return NULL;
7812 HeapFree(GetProcessHeap(), 0, pi5);
7815 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7817 LPWSTR name;
7819 if (get_filename(&name))
7821 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7823 HeapFree(GetProcessHeap(), 0, name);
7824 return NULL;
7826 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7827 GetFullPathNameW(name, len, ret, NULL);
7828 HeapFree(GetProcessHeap(), 0, name);
7830 return ret;
7833 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7834 return NULL;
7836 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7837 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7839 attr = GetFileAttributesW(ret);
7840 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7842 HeapFree(GetProcessHeap(), 0, ret);
7843 ret = NULL;
7845 return ret;