Release 1.4-rc6.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob9bb891585140af17fac64780379fff51ef0a16cd
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winuser.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "wingdi.h"
57 #include "winspool.h"
58 #include "winternl.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
63 #include "winnls.h"
65 #include "ddk/winsplp.h"
66 #include "wspool.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
81 /* ############################### */
83 typedef struct {
84 DWORD job_id;
85 HANDLE hf;
86 } started_doc_t;
88 typedef struct {
89 struct list jobs;
90 LONG ref;
91 } jobqueue_t;
93 typedef struct {
94 LPWSTR name;
95 LPWSTR printername;
96 HANDLE backend_printer;
97 jobqueue_t *queue;
98 started_doc_t *doc;
99 } opened_printer_t;
101 typedef struct {
102 struct list entry;
103 DWORD job_id;
104 WCHAR *filename;
105 WCHAR *portname;
106 WCHAR *document_title;
107 WCHAR *printer_name;
108 LPDEVMODEW devmode;
109 } job_t;
112 typedef struct {
113 LPCWSTR envname;
114 LPCWSTR subdir;
115 DWORD driverversion;
116 LPCWSTR versionregpath;
117 LPCWSTR versionsubdir;
118 } printenv_t;
120 /* ############################### */
122 static opened_printer_t **printer_handles;
123 static UINT nb_printer_handles;
124 static LONG next_job_id = 1;
126 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
127 WORD fwCapability, LPSTR lpszOutput,
128 LPDEVMODEA lpdm );
129 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
130 LPSTR lpszDevice, LPSTR lpszPort,
131 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
132 DWORD fwMode );
134 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
135 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
136 'c','o','n','t','r','o','l','\\',
137 'P','r','i','n','t','\\',
138 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
139 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
141 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
142 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
143 'C','o','n','t','r','o','l','\\',
144 'P','r','i','n','t','\\',
145 'P','r','i','n','t','e','r','s',0};
147 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
149 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
150 'M','i','c','r','o','s','o','f','t','\\',
151 'W','i','n','d','o','w','s',' ','N','T','\\',
152 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
153 'W','i','n','d','o','w','s',0};
155 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
156 'M','i','c','r','o','s','o','f','t','\\',
157 'W','i','n','d','o','w','s',' ','N','T','\\',
158 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
159 'D','e','v','i','c','e','s',0};
161 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
162 'M','i','c','r','o','s','o','f','t','\\',
163 'W','i','n','d','o','w','s',' ','N','T','\\',
164 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
165 'P','o','r','t','s',0};
167 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
168 'M','i','c','r','o','s','o','f','t','\\',
169 'W','i','n','d','o','w','s',' ','N','T','\\',
170 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
171 'P','r','i','n','t','e','r','P','o','r','t','s',0};
173 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
174 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
175 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
176 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
177 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
178 static const WCHAR subdir_x64W[] = {'x','6','4',0};
179 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
180 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
181 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
182 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
183 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
185 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
186 static const WCHAR backslashW[] = {'\\',0};
187 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
188 'i','o','n',' ','F','i','l','e',0};
189 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
190 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
191 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
192 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
193 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
194 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
195 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
196 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
197 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
198 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
199 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
200 static const WCHAR NameW[] = {'N','a','m','e',0};
201 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
202 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
203 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
204 static const WCHAR PortW[] = {'P','o','r','t',0};
205 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
206 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
207 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
208 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
209 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
210 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
211 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
212 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
213 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
214 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
215 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
216 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
217 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
218 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
219 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
220 static WCHAR rawW[] = {'R','A','W',0};
221 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
222 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
223 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
224 static const WCHAR commaW[] = {',',0};
225 static WCHAR emptyStringW[] = {0};
227 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
229 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
230 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
231 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
233 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
234 'D','o','c','u','m','e','n','t',0};
236 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
237 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
238 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
239 0, sizeof(DRIVER_INFO_8W)};
242 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
243 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
244 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
245 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
246 sizeof(PRINTER_INFO_9W)};
248 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
249 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
252 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
254 /******************************************************************
255 * validate the user-supplied printing-environment [internal]
257 * PARAMS
258 * env [I] PTR to Environment-String or NULL
260 * RETURNS
261 * Failure: NULL
262 * Success: PTR to printenv_t
264 * NOTES
265 * An empty string is handled the same way as NULL.
266 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
270 static const printenv_t * validate_envW(LPCWSTR env)
272 const printenv_t *result = NULL;
273 unsigned int i;
275 TRACE("testing %s\n", debugstr_w(env));
276 if (env && env[0])
278 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
280 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
282 result = all_printenv[i];
283 break;
287 if (result == NULL) {
288 FIXME("unsupported Environment: %s\n", debugstr_w(env));
289 SetLastError(ERROR_INVALID_ENVIRONMENT);
291 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
293 else
295 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
297 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
299 return result;
303 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
304 if passed a NULL string. This returns NULLs to the result.
306 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
308 if ( (src) )
310 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
311 return usBufferPtr->Buffer;
313 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
314 return NULL;
317 static LPWSTR strdupW(LPCWSTR p)
319 LPWSTR ret;
320 DWORD len;
322 if(!p) return NULL;
323 len = (strlenW(p) + 1) * sizeof(WCHAR);
324 ret = HeapAlloc(GetProcessHeap(), 0, len);
325 memcpy(ret, p, len);
326 return ret;
329 static LPSTR strdupWtoA( LPCWSTR str )
331 LPSTR ret;
332 INT len;
334 if (!str) return NULL;
335 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
336 ret = HeapAlloc( GetProcessHeap(), 0, len );
337 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
338 return ret;
341 /******************************************************************
342 * verify, that the filename is a local file
345 static inline BOOL is_local_file(LPWSTR name)
347 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
350 /* ################################ */
352 static int multi_sz_lenA(const char *str)
354 const char *ptr = str;
355 if(!str) return 0;
358 ptr += lstrlenA(ptr) + 1;
359 } while(*ptr);
361 return ptr - str + 1;
364 static void
365 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
366 char qbuf[200];
368 /* If forcing, or no profile string entry for device yet, set the entry
370 * The always change entry if not WINEPS yet is discussable.
372 if (force ||
373 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
374 !strcmp(qbuf,"*") ||
375 !strstr(qbuf,"WINEPS.DRV")
377 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
378 HKEY hkey;
380 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
381 WriteProfileStringA("windows","device",buf);
382 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
383 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
384 RegCloseKey(hkey);
386 HeapFree(GetProcessHeap(),0,buf);
390 static BOOL add_printer_driver(WCHAR *name)
392 DRIVER_INFO_3W di3;
394 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
395 di3.cVersion = 3;
396 di3.pName = name;
397 di3.pEnvironment = envname_x86W;
398 di3.pDriverPath = driver_nt;
399 di3.pDataFile = generic_ppdW;
400 di3.pConfigFile = driver_nt;
401 di3.pDefaultDataType = rawW;
403 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
404 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
406 di3.cVersion = 0;
407 di3.pEnvironment = envname_win40W;
408 di3.pDriverPath = driver_9x;
409 di3.pConfigFile = driver_9x;
410 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
411 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
413 return TRUE;
416 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
417 return FALSE;
420 #ifdef SONAME_LIBCUPS
421 static typeof(cupsFreeDests) *pcupsFreeDests;
422 static typeof(cupsGetDests) *pcupsGetDests;
423 static typeof(cupsGetPPD) *pcupsGetPPD;
424 static typeof(cupsPrintFile) *pcupsPrintFile;
425 static void *cupshandle;
427 static BOOL CUPS_LoadPrinters(void)
429 int i, nrofdests;
430 BOOL hadprinter = FALSE, haddefault = FALSE;
431 cups_dest_t *dests;
432 PRINTER_INFO_2W pi2;
433 WCHAR *port;
434 HKEY hkeyPrinter, hkeyPrinters;
435 char loaderror[256];
436 WCHAR nameW[MAX_PATH];
438 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
439 if (!cupshandle) {
440 TRACE("%s\n", loaderror);
441 return FALSE;
443 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
445 #define DYNCUPS(x) \
446 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
447 if (!p##x) return FALSE;
449 DYNCUPS(cupsFreeDests);
450 DYNCUPS(cupsGetPPD);
451 DYNCUPS(cupsGetDests);
452 DYNCUPS(cupsPrintFile);
453 #undef DYNCUPS
455 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
456 ERROR_SUCCESS) {
457 ERR("Can't create Printers key\n");
458 return FALSE;
461 nrofdests = pcupsGetDests(&dests);
462 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
463 for (i=0;i<nrofdests;i++) {
464 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
466 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
467 lstrcpyW(port, CUPS_Port);
468 lstrcatW(port, nameW);
470 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
471 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
472 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
473 and continue */
474 TRACE("Printer already exists\n");
475 /* overwrite old LPR:* port */
476 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
477 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
478 RegCloseKey(hkeyPrinter);
479 } else {
480 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
481 ' ','u','s','i','n','g',' ','C','U','P','S',0};
483 add_printer_driver(nameW);
485 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
486 pi2.pPrinterName = nameW;
487 pi2.pDatatype = rawW;
488 pi2.pPrintProcessor = WinPrintW;
489 pi2.pDriverName = nameW;
490 pi2.pComment = comment_cups;
491 pi2.pLocation = emptyStringW;
492 pi2.pPortName = port;
493 pi2.pParameters = emptyStringW;
494 pi2.pShareName = emptyStringW;
495 pi2.pSepFile = emptyStringW;
497 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
498 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
499 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
502 HeapFree(GetProcessHeap(),0,port);
504 hadprinter = TRUE;
505 if (dests[i].is_default) {
506 SetDefaultPrinterW(nameW);
507 haddefault = TRUE;
510 if (hadprinter && !haddefault) {
511 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
512 SetDefaultPrinterW(nameW);
514 pcupsFreeDests(nrofdests, dests);
515 RegCloseKey(hkeyPrinters);
516 return hadprinter;
518 #endif
520 static BOOL
521 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
522 PRINTER_INFO_2A pinfo2a;
523 const char *r;
524 size_t name_len;
525 char *e,*s,*name,*prettyname,*devname;
526 BOOL ret = FALSE, set_default = FALSE;
527 char *port = NULL, *env_default;
528 HKEY hkeyPrinter, hkeyPrinters;
529 WCHAR devnameW[MAX_PATH];
531 while (isspace(*pent)) pent++;
532 r = strchr(pent,':');
533 if (r)
534 name_len = r - pent;
535 else
536 name_len = strlen(pent);
537 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
538 memcpy(name, pent, name_len);
539 name[name_len] = '\0';
540 if (r)
541 pent = r;
542 else
543 pent = "";
545 TRACE("name=%s entry=%s\n",name, pent);
547 if(ispunct(*name)) { /* a tc entry, not a real printer */
548 TRACE("skipping tc entry\n");
549 goto end;
552 if(strstr(pent,":server")) { /* server only version so skip */
553 TRACE("skipping server entry\n");
554 goto end;
557 /* Determine whether this is a postscript printer. */
559 ret = TRUE;
560 env_default = getenv("PRINTER");
561 prettyname = name;
562 /* Get longest name, usually the one at the right for later display. */
563 while((s=strchr(prettyname,'|'))) {
564 *s = '\0';
565 e = s;
566 while(isspace(*--e)) *e = '\0';
567 TRACE("\t%s\n", debugstr_a(prettyname));
568 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
569 for(prettyname = s+1; isspace(*prettyname); prettyname++)
572 e = prettyname + strlen(prettyname);
573 while(isspace(*--e)) *e = '\0';
574 TRACE("\t%s\n", debugstr_a(prettyname));
575 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
577 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
578 * if it is too long, we use it as comment below. */
579 devname = prettyname;
580 if (strlen(devname)>=CCHDEVICENAME-1)
581 devname = name;
582 if (strlen(devname)>=CCHDEVICENAME-1) {
583 ret = FALSE;
584 goto end;
587 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
588 sprintf(port,"LPR:%s",name);
590 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
591 ERROR_SUCCESS) {
592 ERR("Can't create Printers key\n");
593 ret = FALSE;
594 goto end;
597 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
599 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
600 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
601 and continue */
602 TRACE("Printer already exists\n");
603 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
604 RegCloseKey(hkeyPrinter);
605 } else {
606 static CHAR data_type[] = "RAW",
607 print_proc[] = "WinPrint",
608 comment[] = "WINEPS Printer using LPR",
609 params[] = "<parameters?>",
610 share_name[] = "<share name?>",
611 sep_file[] = "<sep file?>";
613 add_printer_driver(devnameW);
615 memset(&pinfo2a,0,sizeof(pinfo2a));
616 pinfo2a.pPrinterName = devname;
617 pinfo2a.pDatatype = data_type;
618 pinfo2a.pPrintProcessor = print_proc;
619 pinfo2a.pDriverName = devname;
620 pinfo2a.pComment = comment;
621 pinfo2a.pLocation = prettyname;
622 pinfo2a.pPortName = port;
623 pinfo2a.pParameters = params;
624 pinfo2a.pShareName = share_name;
625 pinfo2a.pSepFile = sep_file;
627 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
628 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
629 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
632 RegCloseKey(hkeyPrinters);
634 if (isfirst || set_default)
635 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
637 end:
638 HeapFree(GetProcessHeap(), 0, port);
639 HeapFree(GetProcessHeap(), 0, name);
640 return ret;
643 static BOOL
644 PRINTCAP_LoadPrinters(void) {
645 BOOL hadprinter = FALSE;
646 char buf[200];
647 FILE *f;
648 char *pent = NULL;
649 BOOL had_bash = FALSE;
651 f = fopen("/etc/printcap","r");
652 if (!f)
653 return FALSE;
655 while(fgets(buf,sizeof(buf),f)) {
656 char *start, *end;
658 end=strchr(buf,'\n');
659 if (end) *end='\0';
661 start = buf;
662 while(isspace(*start)) start++;
663 if(*start == '#' || *start == '\0')
664 continue;
666 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
667 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
668 HeapFree(GetProcessHeap(),0,pent);
669 pent = NULL;
672 if (end && *--end == '\\') {
673 *end = '\0';
674 had_bash = TRUE;
675 } else
676 had_bash = FALSE;
678 if (pent) {
679 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
680 strcat(pent,start);
681 } else {
682 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
683 strcpy(pent,start);
687 if(pent) {
688 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
689 HeapFree(GetProcessHeap(),0,pent);
691 fclose(f);
692 return hadprinter;
695 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
697 if (value)
698 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
699 (lstrlenW(value) + 1) * sizeof(WCHAR));
700 else
701 return ERROR_FILE_NOT_FOUND;
704 /******************************************************************
705 * get_servername_from_name (internal)
707 * for an external server, a copy of the serverpart from the full name is returned
710 static LPWSTR get_servername_from_name(LPCWSTR name)
712 LPWSTR server;
713 LPWSTR ptr;
714 WCHAR buffer[MAX_PATH];
715 DWORD len;
717 if (name == NULL) return NULL;
718 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
720 server = strdupW(&name[2]); /* skip over both backslash */
721 if (server == NULL) return NULL;
723 /* strip '\' and the printername */
724 ptr = strchrW(server, '\\');
725 if (ptr) ptr[0] = '\0';
727 TRACE("found %s\n", debugstr_w(server));
729 len = sizeof(buffer)/sizeof(buffer[0]);
730 if (GetComputerNameW(buffer, &len)) {
731 if (lstrcmpW(buffer, server) == 0) {
732 /* The requested Servername is our computername */
733 HeapFree(GetProcessHeap(), 0, server);
734 return NULL;
737 return server;
740 /******************************************************************
741 * get_basename_from_name (internal)
743 * skip over the serverpart from the full name
746 static LPCWSTR get_basename_from_name(LPCWSTR name)
748 if (name == NULL) return NULL;
749 if ((name[0] == '\\') && (name[1] == '\\')) {
750 /* skip over the servername and search for the following '\' */
751 name = strchrW(&name[2], '\\');
752 if ((name) && (name[1])) {
753 /* found a separator ('\') followed by a name:
754 skip over the separator and return the rest */
755 name++;
757 else
759 /* no basename present (we found only a servername) */
760 return NULL;
763 return name;
766 /******************************************************************
767 * get_opened_printer_entry
768 * Get the first place empty in the opened printer table
770 * ToDo:
771 * - pDefault is ignored
773 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
775 UINT_PTR handle = nb_printer_handles, i;
776 jobqueue_t *queue = NULL;
777 opened_printer_t *printer = NULL;
778 LPWSTR servername;
779 LPCWSTR printername;
781 if ((backend == NULL) && !load_backend()) return NULL;
783 servername = get_servername_from_name(name);
784 if (servername) {
785 FIXME("server %s not supported\n", debugstr_w(servername));
786 HeapFree(GetProcessHeap(), 0, servername);
787 SetLastError(ERROR_INVALID_PRINTER_NAME);
788 return NULL;
791 printername = get_basename_from_name(name);
792 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
794 /* an empty printername is invalid */
795 if (printername && (!printername[0])) {
796 SetLastError(ERROR_INVALID_PARAMETER);
797 return NULL;
800 EnterCriticalSection(&printer_handles_cs);
802 for (i = 0; i < nb_printer_handles; i++)
804 if (!printer_handles[i])
806 if(handle == nb_printer_handles)
807 handle = i;
809 else
811 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
812 queue = printer_handles[i]->queue;
816 if (handle >= nb_printer_handles)
818 opened_printer_t **new_array;
819 if (printer_handles)
820 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
821 (nb_printer_handles + 16) * sizeof(*new_array) );
822 else
823 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
824 (nb_printer_handles + 16) * sizeof(*new_array) );
826 if (!new_array)
828 handle = 0;
829 goto end;
831 printer_handles = new_array;
832 nb_printer_handles += 16;
835 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
837 handle = 0;
838 goto end;
841 /* get a printer handle from the backend */
842 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
843 handle = 0;
844 goto end;
847 /* clone the base name. This is NULL for the printserver */
848 printer->printername = strdupW(printername);
850 /* clone the full name */
851 printer->name = strdupW(name);
852 if (name && (!printer->name)) {
853 handle = 0;
854 goto end;
857 if(queue)
858 printer->queue = queue;
859 else
861 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
862 if (!printer->queue) {
863 handle = 0;
864 goto end;
866 list_init(&printer->queue->jobs);
867 printer->queue->ref = 0;
869 InterlockedIncrement(&printer->queue->ref);
871 printer_handles[handle] = printer;
872 handle++;
873 end:
874 LeaveCriticalSection(&printer_handles_cs);
875 if (!handle && printer) {
876 /* Something failed: Free all resources */
877 HeapFree(GetProcessHeap(), 0, printer->printername);
878 HeapFree(GetProcessHeap(), 0, printer->name);
879 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
880 HeapFree(GetProcessHeap(), 0, printer);
883 return (HANDLE)handle;
886 /******************************************************************
887 * get_opened_printer
888 * Get the pointer to the opened printer referred by the handle
890 static opened_printer_t *get_opened_printer(HANDLE hprn)
892 UINT_PTR idx = (UINT_PTR)hprn;
893 opened_printer_t *ret = NULL;
895 EnterCriticalSection(&printer_handles_cs);
897 if ((idx > 0) && (idx <= nb_printer_handles)) {
898 ret = printer_handles[idx - 1];
900 LeaveCriticalSection(&printer_handles_cs);
901 return ret;
904 /******************************************************************
905 * get_opened_printer_name
906 * Get the pointer to the opened printer name referred by the handle
908 static LPCWSTR get_opened_printer_name(HANDLE hprn)
910 opened_printer_t *printer = get_opened_printer(hprn);
911 if(!printer) return NULL;
912 return printer->name;
915 /******************************************************************
916 * WINSPOOL_GetOpenedPrinterRegKey
919 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
921 LPCWSTR name = get_opened_printer_name(hPrinter);
922 DWORD ret;
923 HKEY hkeyPrinters;
925 if(!name) return ERROR_INVALID_HANDLE;
927 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
928 ERROR_SUCCESS)
929 return ret;
931 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
933 ERR("Can't find opened printer %s in registry\n",
934 debugstr_w(name));
935 RegCloseKey(hkeyPrinters);
936 return ERROR_INVALID_PRINTER_NAME; /* ? */
938 RegCloseKey(hkeyPrinters);
939 return ERROR_SUCCESS;
942 void WINSPOOL_LoadSystemPrinters(void)
944 HKEY hkey, hkeyPrinters;
945 HANDLE hprn;
946 DWORD needed, num, i;
947 WCHAR PrinterName[256];
948 BOOL done = FALSE;
950 /* This ensures that all printer entries have a valid Name value. If causes
951 problems later if they don't. If one is found to be missed we create one
952 and set it equal to the name of the key */
953 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
954 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
955 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
956 for(i = 0; i < num; i++) {
957 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
958 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
959 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
960 set_reg_szW(hkey, NameW, PrinterName);
962 RegCloseKey(hkey);
967 RegCloseKey(hkeyPrinters);
970 /* We want to avoid calling AddPrinter on printers as much as
971 possible, because on cups printers this will (eventually) lead
972 to a call to cupsGetPPD which takes forever, even with non-cups
973 printers AddPrinter takes a while. So we'll tag all printers that
974 were automatically added last time around, if they still exist
975 we'll leave them be otherwise we'll delete them. */
976 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
977 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
978 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
979 for(i = 0; i < num; i++) {
980 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
981 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
982 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
983 DWORD dw = 1;
984 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
985 RegCloseKey(hkey);
987 ClosePrinter(hprn);
992 HeapFree(GetProcessHeap(), 0, pi);
996 #ifdef SONAME_LIBCUPS
997 done = CUPS_LoadPrinters();
998 #endif
1000 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1001 PRINTCAP_LoadPrinters();
1003 /* Now enumerate the list again and delete any printers that are still tagged */
1004 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1005 if(needed) {
1006 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1007 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1008 for(i = 0; i < num; i++) {
1009 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1010 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1011 BOOL delete_driver = FALSE;
1012 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1013 DWORD dw, type, size = sizeof(dw);
1014 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1015 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1016 DeletePrinter(hprn);
1017 delete_driver = TRUE;
1019 RegCloseKey(hkey);
1021 ClosePrinter(hprn);
1022 if(delete_driver)
1023 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1028 HeapFree(GetProcessHeap(), 0, pi);
1031 return;
1035 /******************************************************************
1036 * get_job
1038 * Get the pointer to the specified job.
1039 * Should hold the printer_handles_cs before calling.
1041 static job_t *get_job(HANDLE hprn, DWORD JobId)
1043 opened_printer_t *printer = get_opened_printer(hprn);
1044 job_t *job;
1046 if(!printer) return NULL;
1047 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1049 if(job->job_id == JobId)
1050 return job;
1052 return NULL;
1055 /***********************************************************
1056 * DEVMODEcpyAtoW
1058 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1060 BOOL Formname;
1061 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1062 DWORD size;
1064 Formname = (dmA->dmSize > off_formname);
1065 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1066 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1067 dmW->dmDeviceName, CCHDEVICENAME);
1068 if(!Formname) {
1069 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1070 dmA->dmSize - CCHDEVICENAME);
1071 } else {
1072 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1073 off_formname - CCHDEVICENAME);
1074 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1075 dmW->dmFormName, CCHFORMNAME);
1076 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1077 (off_formname + CCHFORMNAME));
1079 dmW->dmSize = size;
1080 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1081 dmA->dmDriverExtra);
1082 return dmW;
1085 /***********************************************************
1086 * DEVMODEdupWtoA
1087 * Creates an ansi copy of supplied devmode
1089 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1091 LPDEVMODEA dmA;
1092 DWORD size;
1094 if (!dmW) return NULL;
1095 size = dmW->dmSize - CCHDEVICENAME -
1096 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1098 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1099 if (!dmA) return NULL;
1101 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1102 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1104 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1105 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1106 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1108 else
1110 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1111 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1112 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1113 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1115 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1118 dmA->dmSize = size;
1119 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1120 return dmA;
1123 /******************************************************************
1124 * convert_printerinfo_W_to_A [internal]
1127 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1128 DWORD level, DWORD outlen, DWORD numentries)
1130 DWORD id = 0;
1131 LPSTR ptr;
1132 INT len;
1134 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1136 len = pi_sizeof[level] * numentries;
1137 ptr = (LPSTR) out + len;
1138 outlen -= len;
1140 /* copy the numbers of all PRINTER_INFO_* first */
1141 memcpy(out, pPrintersW, len);
1143 while (id < numentries) {
1144 switch (level) {
1145 case 1:
1147 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1148 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1150 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1151 if (piW->pDescription) {
1152 piA->pDescription = ptr;
1153 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1154 ptr, outlen, NULL, NULL);
1155 ptr += len;
1156 outlen -= len;
1158 if (piW->pName) {
1159 piA->pName = ptr;
1160 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1161 ptr, outlen, NULL, NULL);
1162 ptr += len;
1163 outlen -= len;
1165 if (piW->pComment) {
1166 piA->pComment = ptr;
1167 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1168 ptr, outlen, NULL, NULL);
1169 ptr += len;
1170 outlen -= len;
1172 break;
1175 case 2:
1177 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1178 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1179 LPDEVMODEA dmA;
1181 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1182 if (piW->pServerName) {
1183 piA->pServerName = ptr;
1184 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1185 ptr, outlen, NULL, NULL);
1186 ptr += len;
1187 outlen -= len;
1189 if (piW->pPrinterName) {
1190 piA->pPrinterName = ptr;
1191 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1192 ptr, outlen, NULL, NULL);
1193 ptr += len;
1194 outlen -= len;
1196 if (piW->pShareName) {
1197 piA->pShareName = ptr;
1198 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1199 ptr, outlen, NULL, NULL);
1200 ptr += len;
1201 outlen -= len;
1203 if (piW->pPortName) {
1204 piA->pPortName = ptr;
1205 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1206 ptr, outlen, NULL, NULL);
1207 ptr += len;
1208 outlen -= len;
1210 if (piW->pDriverName) {
1211 piA->pDriverName = ptr;
1212 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1213 ptr, outlen, NULL, NULL);
1214 ptr += len;
1215 outlen -= len;
1217 if (piW->pComment) {
1218 piA->pComment = ptr;
1219 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1220 ptr, outlen, NULL, NULL);
1221 ptr += len;
1222 outlen -= len;
1224 if (piW->pLocation) {
1225 piA->pLocation = ptr;
1226 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1227 ptr, outlen, NULL, NULL);
1228 ptr += len;
1229 outlen -= len;
1232 dmA = DEVMODEdupWtoA(piW->pDevMode);
1233 if (dmA) {
1234 /* align DEVMODEA to a DWORD boundary */
1235 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1236 ptr += len;
1237 outlen -= len;
1239 piA->pDevMode = (LPDEVMODEA) ptr;
1240 len = dmA->dmSize + dmA->dmDriverExtra;
1241 memcpy(ptr, dmA, len);
1242 HeapFree(GetProcessHeap(), 0, dmA);
1244 ptr += len;
1245 outlen -= len;
1248 if (piW->pSepFile) {
1249 piA->pSepFile = ptr;
1250 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1251 ptr, outlen, NULL, NULL);
1252 ptr += len;
1253 outlen -= len;
1255 if (piW->pPrintProcessor) {
1256 piA->pPrintProcessor = ptr;
1257 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1258 ptr, outlen, NULL, NULL);
1259 ptr += len;
1260 outlen -= len;
1262 if (piW->pDatatype) {
1263 piA->pDatatype = ptr;
1264 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1265 ptr, outlen, NULL, NULL);
1266 ptr += len;
1267 outlen -= len;
1269 if (piW->pParameters) {
1270 piA->pParameters = ptr;
1271 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1272 ptr, outlen, NULL, NULL);
1273 ptr += len;
1274 outlen -= len;
1276 if (piW->pSecurityDescriptor) {
1277 piA->pSecurityDescriptor = NULL;
1278 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1280 break;
1283 case 4:
1285 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1286 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1288 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1290 if (piW->pPrinterName) {
1291 piA->pPrinterName = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1293 ptr, outlen, NULL, NULL);
1294 ptr += len;
1295 outlen -= len;
1297 if (piW->pServerName) {
1298 piA->pServerName = ptr;
1299 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1300 ptr, outlen, NULL, NULL);
1301 ptr += len;
1302 outlen -= len;
1304 break;
1307 case 5:
1309 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1310 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1312 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1314 if (piW->pPrinterName) {
1315 piA->pPrinterName = ptr;
1316 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1317 ptr, outlen, NULL, NULL);
1318 ptr += len;
1319 outlen -= len;
1321 if (piW->pPortName) {
1322 piA->pPortName = ptr;
1323 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1324 ptr, outlen, NULL, NULL);
1325 ptr += len;
1326 outlen -= len;
1328 break;
1331 case 6: /* 6A and 6W are the same structure */
1332 break;
1334 case 7:
1336 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1337 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1339 TRACE("(%u) #%u\n", level, id);
1340 if (piW->pszObjectGUID) {
1341 piA->pszObjectGUID = ptr;
1342 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1343 ptr, outlen, NULL, NULL);
1344 ptr += len;
1345 outlen -= len;
1347 break;
1350 case 9:
1352 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1353 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1354 LPDEVMODEA dmA;
1356 TRACE("(%u) #%u\n", level, id);
1357 dmA = DEVMODEdupWtoA(piW->pDevMode);
1358 if (dmA) {
1359 /* align DEVMODEA to a DWORD boundary */
1360 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1361 ptr += len;
1362 outlen -= len;
1364 piA->pDevMode = (LPDEVMODEA) ptr;
1365 len = dmA->dmSize + dmA->dmDriverExtra;
1366 memcpy(ptr, dmA, len);
1367 HeapFree(GetProcessHeap(), 0, dmA);
1369 ptr += len;
1370 outlen -= len;
1373 break;
1376 default:
1377 FIXME("for level %u\n", level);
1379 pPrintersW += pi_sizeof[level];
1380 out += pi_sizeof[level];
1381 id++;
1385 /******************************************************************
1386 * convert_driverinfo_W_to_A [internal]
1389 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1390 DWORD level, DWORD outlen, DWORD numentries)
1392 DWORD id = 0;
1393 LPSTR ptr;
1394 INT len;
1396 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1398 len = di_sizeof[level] * numentries;
1399 ptr = (LPSTR) out + len;
1400 outlen -= len;
1402 /* copy the numbers of all PRINTER_INFO_* first */
1403 memcpy(out, pDriversW, len);
1405 #define COPY_STRING(fld) \
1406 { if (diW->fld){ \
1407 diA->fld = ptr; \
1408 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1409 ptr += len; outlen -= len;\
1411 #define COPY_MULTIZ_STRING(fld) \
1412 { LPWSTR p = diW->fld; if (p){ \
1413 diA->fld = ptr; \
1414 do {\
1415 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1416 ptr += len; outlen -= len; p += len;\
1418 while(len > 1 && outlen > 0); \
1421 while (id < numentries)
1423 switch (level)
1425 case 1:
1427 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1428 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1430 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1432 COPY_STRING(pName);
1433 break;
1435 case 2:
1437 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1438 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1440 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1442 COPY_STRING(pName);
1443 COPY_STRING(pEnvironment);
1444 COPY_STRING(pDriverPath);
1445 COPY_STRING(pDataFile);
1446 COPY_STRING(pConfigFile);
1447 break;
1449 case 3:
1451 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1452 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1454 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1456 COPY_STRING(pName);
1457 COPY_STRING(pEnvironment);
1458 COPY_STRING(pDriverPath);
1459 COPY_STRING(pDataFile);
1460 COPY_STRING(pConfigFile);
1461 COPY_STRING(pHelpFile);
1462 COPY_MULTIZ_STRING(pDependentFiles);
1463 COPY_STRING(pMonitorName);
1464 COPY_STRING(pDefaultDataType);
1465 break;
1467 case 4:
1469 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1470 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1472 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1474 COPY_STRING(pName);
1475 COPY_STRING(pEnvironment);
1476 COPY_STRING(pDriverPath);
1477 COPY_STRING(pDataFile);
1478 COPY_STRING(pConfigFile);
1479 COPY_STRING(pHelpFile);
1480 COPY_MULTIZ_STRING(pDependentFiles);
1481 COPY_STRING(pMonitorName);
1482 COPY_STRING(pDefaultDataType);
1483 COPY_MULTIZ_STRING(pszzPreviousNames);
1484 break;
1486 case 5:
1488 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1489 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1491 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1493 COPY_STRING(pName);
1494 COPY_STRING(pEnvironment);
1495 COPY_STRING(pDriverPath);
1496 COPY_STRING(pDataFile);
1497 COPY_STRING(pConfigFile);
1498 break;
1500 case 6:
1502 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1503 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1505 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1507 COPY_STRING(pName);
1508 COPY_STRING(pEnvironment);
1509 COPY_STRING(pDriverPath);
1510 COPY_STRING(pDataFile);
1511 COPY_STRING(pConfigFile);
1512 COPY_STRING(pHelpFile);
1513 COPY_MULTIZ_STRING(pDependentFiles);
1514 COPY_STRING(pMonitorName);
1515 COPY_STRING(pDefaultDataType);
1516 COPY_MULTIZ_STRING(pszzPreviousNames);
1517 COPY_STRING(pszMfgName);
1518 COPY_STRING(pszOEMUrl);
1519 COPY_STRING(pszHardwareID);
1520 COPY_STRING(pszProvider);
1521 break;
1523 case 8:
1525 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1526 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1528 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1530 COPY_STRING(pName);
1531 COPY_STRING(pEnvironment);
1532 COPY_STRING(pDriverPath);
1533 COPY_STRING(pDataFile);
1534 COPY_STRING(pConfigFile);
1535 COPY_STRING(pHelpFile);
1536 COPY_MULTIZ_STRING(pDependentFiles);
1537 COPY_STRING(pMonitorName);
1538 COPY_STRING(pDefaultDataType);
1539 COPY_MULTIZ_STRING(pszzPreviousNames);
1540 COPY_STRING(pszMfgName);
1541 COPY_STRING(pszOEMUrl);
1542 COPY_STRING(pszHardwareID);
1543 COPY_STRING(pszProvider);
1544 COPY_STRING(pszPrintProcessor);
1545 COPY_STRING(pszVendorSetup);
1546 COPY_MULTIZ_STRING(pszzColorProfiles);
1547 COPY_STRING(pszInfPath);
1548 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1549 break;
1553 default:
1554 FIXME("for level %u\n", level);
1557 pDriversW += di_sizeof[level];
1558 out += di_sizeof[level];
1559 id++;
1562 #undef COPY_STRING
1563 #undef COPY_MULTIZ_STRING
1567 /***********************************************************
1568 * PRINTER_INFO_2AtoW
1569 * Creates a unicode copy of PRINTER_INFO_2A on heap
1571 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1573 LPPRINTER_INFO_2W piW;
1574 UNICODE_STRING usBuffer;
1576 if(!piA) return NULL;
1577 piW = HeapAlloc(heap, 0, sizeof(*piW));
1578 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1580 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1581 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1582 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1583 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1584 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1585 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1586 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1587 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1588 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1589 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1590 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1591 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1592 return piW;
1595 /***********************************************************
1596 * FREE_PRINTER_INFO_2W
1597 * Free PRINTER_INFO_2W and all strings
1599 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1601 if(!piW) return;
1603 HeapFree(heap,0,piW->pServerName);
1604 HeapFree(heap,0,piW->pPrinterName);
1605 HeapFree(heap,0,piW->pShareName);
1606 HeapFree(heap,0,piW->pPortName);
1607 HeapFree(heap,0,piW->pDriverName);
1608 HeapFree(heap,0,piW->pComment);
1609 HeapFree(heap,0,piW->pLocation);
1610 HeapFree(heap,0,piW->pDevMode);
1611 HeapFree(heap,0,piW->pSepFile);
1612 HeapFree(heap,0,piW->pPrintProcessor);
1613 HeapFree(heap,0,piW->pDatatype);
1614 HeapFree(heap,0,piW->pParameters);
1615 HeapFree(heap,0,piW);
1616 return;
1619 /******************************************************************
1620 * DeviceCapabilities [WINSPOOL.@]
1621 * DeviceCapabilitiesA [WINSPOOL.@]
1624 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1625 LPSTR pOutput, LPDEVMODEA lpdm)
1627 INT ret;
1629 if (!GDI_CallDeviceCapabilities16)
1631 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1632 (LPCSTR)104 );
1633 if (!GDI_CallDeviceCapabilities16) return -1;
1635 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1637 /* If DC_PAPERSIZE map POINT16s to POINTs */
1638 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1639 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1640 POINT *pt = (POINT *)pOutput;
1641 INT i;
1642 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1643 for(i = 0; i < ret; i++, pt++)
1645 pt->x = tmp[i].x;
1646 pt->y = tmp[i].y;
1648 HeapFree( GetProcessHeap(), 0, tmp );
1650 return ret;
1654 /*****************************************************************************
1655 * DeviceCapabilitiesW [WINSPOOL.@]
1657 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1660 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1661 WORD fwCapability, LPWSTR pOutput,
1662 const DEVMODEW *pDevMode)
1664 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1665 LPSTR pDeviceA = strdupWtoA(pDevice);
1666 LPSTR pPortA = strdupWtoA(pPort);
1667 INT ret;
1669 if(pOutput && (fwCapability == DC_BINNAMES ||
1670 fwCapability == DC_FILEDEPENDENCIES ||
1671 fwCapability == DC_PAPERNAMES)) {
1672 /* These need A -> W translation */
1673 INT size = 0, i;
1674 LPSTR pOutputA;
1675 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1676 dmA);
1677 if(ret == -1)
1678 return ret;
1679 switch(fwCapability) {
1680 case DC_BINNAMES:
1681 size = 24;
1682 break;
1683 case DC_PAPERNAMES:
1684 case DC_FILEDEPENDENCIES:
1685 size = 64;
1686 break;
1688 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1689 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1690 dmA);
1691 for(i = 0; i < ret; i++)
1692 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1693 pOutput + (i * size), size);
1694 HeapFree(GetProcessHeap(), 0, pOutputA);
1695 } else {
1696 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1697 (LPSTR)pOutput, dmA);
1699 HeapFree(GetProcessHeap(),0,pPortA);
1700 HeapFree(GetProcessHeap(),0,pDeviceA);
1701 HeapFree(GetProcessHeap(),0,dmA);
1702 return ret;
1705 /******************************************************************
1706 * DocumentPropertiesA [WINSPOOL.@]
1708 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1710 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1711 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1712 LPDEVMODEA pDevModeInput,DWORD fMode )
1714 LPSTR lpName = pDeviceName;
1715 static CHAR port[] = "LPT1:";
1716 LONG ret;
1718 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1719 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1722 if(!pDeviceName) {
1723 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1724 if(!lpNameW) {
1725 ERR("no name from hPrinter?\n");
1726 SetLastError(ERROR_INVALID_HANDLE);
1727 return -1;
1729 lpName = strdupWtoA(lpNameW);
1732 if (!GDI_CallExtDeviceMode16)
1734 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1735 (LPCSTR)102 );
1736 if (!GDI_CallExtDeviceMode16) {
1737 ERR("No CallExtDeviceMode16?\n");
1738 return -1;
1741 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1742 pDevModeInput, NULL, fMode);
1744 if(!pDeviceName)
1745 HeapFree(GetProcessHeap(),0,lpName);
1746 return ret;
1750 /*****************************************************************************
1751 * DocumentPropertiesW (WINSPOOL.@)
1753 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1755 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1756 LPWSTR pDeviceName,
1757 LPDEVMODEW pDevModeOutput,
1758 LPDEVMODEW pDevModeInput, DWORD fMode)
1761 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1762 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1763 LPDEVMODEA pDevModeOutputA = NULL;
1764 LONG ret;
1766 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1767 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1768 fMode);
1769 if(pDevModeOutput) {
1770 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1771 if(ret < 0) return ret;
1772 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1774 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1775 pDevModeInputA, fMode);
1776 if(pDevModeOutput) {
1777 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1778 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1780 if(fMode == 0 && ret > 0)
1781 ret += (CCHDEVICENAME + CCHFORMNAME);
1782 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1783 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1784 return ret;
1787 /*****************************************************************************
1788 * IsValidDevmodeA [WINSPOOL.@]
1790 * Validate a DEVMODE structure and fix errors if possible.
1793 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1795 FIXME("(%p,%ld): stub\n", pDevMode, size);
1797 if(!pDevMode)
1798 return FALSE;
1800 return TRUE;
1803 /*****************************************************************************
1804 * IsValidDevmodeW [WINSPOOL.@]
1806 * Validate a DEVMODE structure and fix errors if possible.
1809 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1811 FIXME("(%p,%ld): stub\n", pDevMode, size);
1813 if(!pDevMode)
1814 return FALSE;
1816 return TRUE;
1819 /******************************************************************
1820 * OpenPrinterA [WINSPOOL.@]
1822 * See OpenPrinterW.
1825 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1826 LPPRINTER_DEFAULTSA pDefault)
1828 UNICODE_STRING lpPrinterNameW;
1829 UNICODE_STRING usBuffer;
1830 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1831 PWSTR pwstrPrinterNameW;
1832 BOOL ret;
1834 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1836 if(pDefault) {
1837 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1838 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1839 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1840 pDefaultW = &DefaultW;
1842 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1843 if(pDefault) {
1844 RtlFreeUnicodeString(&usBuffer);
1845 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1847 RtlFreeUnicodeString(&lpPrinterNameW);
1848 return ret;
1851 /******************************************************************
1852 * OpenPrinterW [WINSPOOL.@]
1854 * Open a Printer / Printserver or a Printer-Object
1856 * PARAMS
1857 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1858 * phPrinter [O] The resulting Handle is stored here
1859 * pDefault [I] PTR to Default Printer Settings or NULL
1861 * RETURNS
1862 * Success: TRUE
1863 * Failure: FALSE
1865 * NOTES
1866 * lpPrinterName is one of:
1867 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1868 *| Printer: "PrinterName"
1869 *| Printer-Object: "PrinterName,Job xxx"
1870 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1871 *| XcvPort: "Servername,XcvPort PortName"
1873 * BUGS
1874 *| Printer-Object not supported
1875 *| pDefaults is ignored
1878 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1881 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1882 if (pDefault) {
1883 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1884 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1887 if(!phPrinter) {
1888 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1889 SetLastError(ERROR_INVALID_PARAMETER);
1890 return FALSE;
1893 /* Get the unique handle of the printer or Printserver */
1894 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1895 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1896 return (*phPrinter != 0);
1899 /******************************************************************
1900 * AddMonitorA [WINSPOOL.@]
1902 * See AddMonitorW.
1905 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1907 LPWSTR nameW = NULL;
1908 INT len;
1909 BOOL res;
1910 LPMONITOR_INFO_2A mi2a;
1911 MONITOR_INFO_2W mi2w;
1913 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1914 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1915 debugstr_a(mi2a ? mi2a->pName : NULL),
1916 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1917 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1919 if (Level != 2) {
1920 SetLastError(ERROR_INVALID_LEVEL);
1921 return FALSE;
1924 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1925 if (mi2a == NULL) {
1926 return FALSE;
1929 if (pName) {
1930 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1931 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1932 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1935 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1936 if (mi2a->pName) {
1937 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1938 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1939 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1941 if (mi2a->pEnvironment) {
1942 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1943 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1944 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1946 if (mi2a->pDLLName) {
1947 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1948 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1949 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1952 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1954 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1955 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1956 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1958 HeapFree(GetProcessHeap(), 0, nameW);
1959 return (res);
1962 /******************************************************************************
1963 * AddMonitorW [WINSPOOL.@]
1965 * Install a Printmonitor
1967 * PARAMS
1968 * pName [I] Servername or NULL (local Computer)
1969 * Level [I] Structure-Level (Must be 2)
1970 * pMonitors [I] PTR to MONITOR_INFO_2
1972 * RETURNS
1973 * Success: TRUE
1974 * Failure: FALSE
1976 * NOTES
1977 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1980 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1982 LPMONITOR_INFO_2W mi2w;
1984 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1985 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1986 debugstr_w(mi2w ? mi2w->pName : NULL),
1987 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1988 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1990 if ((backend == NULL) && !load_backend()) return FALSE;
1992 if (Level != 2) {
1993 SetLastError(ERROR_INVALID_LEVEL);
1994 return FALSE;
1997 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1998 if (mi2w == NULL) {
1999 return FALSE;
2002 return backend->fpAddMonitor(pName, Level, pMonitors);
2005 /******************************************************************
2006 * DeletePrinterDriverA [WINSPOOL.@]
2009 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2011 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2014 /******************************************************************
2015 * DeletePrinterDriverW [WINSPOOL.@]
2018 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2020 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2023 /******************************************************************
2024 * DeleteMonitorA [WINSPOOL.@]
2026 * See DeleteMonitorW.
2029 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2031 LPWSTR nameW = NULL;
2032 LPWSTR EnvironmentW = NULL;
2033 LPWSTR MonitorNameW = NULL;
2034 BOOL res;
2035 INT len;
2037 if (pName) {
2038 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2039 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2040 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2043 if (pEnvironment) {
2044 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2045 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2046 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2048 if (pMonitorName) {
2049 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2050 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2051 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2054 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2056 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2057 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2058 HeapFree(GetProcessHeap(), 0, nameW);
2059 return (res);
2062 /******************************************************************
2063 * DeleteMonitorW [WINSPOOL.@]
2065 * Delete a specific Printmonitor from a Printing-Environment
2067 * PARAMS
2068 * pName [I] Servername or NULL (local Computer)
2069 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2070 * pMonitorName [I] Name of the Monitor, that should be deleted
2072 * RETURNS
2073 * Success: TRUE
2074 * Failure: FALSE
2076 * NOTES
2077 * pEnvironment is ignored in Windows for the local Computer.
2080 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2083 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2084 debugstr_w(pMonitorName));
2086 if ((backend == NULL) && !load_backend()) return FALSE;
2088 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2092 /******************************************************************
2093 * DeletePortA [WINSPOOL.@]
2095 * See DeletePortW.
2098 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2100 LPWSTR nameW = NULL;
2101 LPWSTR portW = NULL;
2102 INT len;
2103 DWORD res;
2105 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2107 /* convert servername to unicode */
2108 if (pName) {
2109 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2110 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2111 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2114 /* convert portname to unicode */
2115 if (pPortName) {
2116 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2117 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2118 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2121 res = DeletePortW(nameW, hWnd, portW);
2122 HeapFree(GetProcessHeap(), 0, nameW);
2123 HeapFree(GetProcessHeap(), 0, portW);
2124 return res;
2127 /******************************************************************
2128 * DeletePortW [WINSPOOL.@]
2130 * Delete a specific Port
2132 * PARAMS
2133 * pName [I] Servername or NULL (local Computer)
2134 * hWnd [I] Handle to parent Window for the Dialog-Box
2135 * pPortName [I] Name of the Port, that should be deleted
2137 * RETURNS
2138 * Success: TRUE
2139 * Failure: FALSE
2142 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2144 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2146 if ((backend == NULL) && !load_backend()) return FALSE;
2148 if (!pPortName) {
2149 SetLastError(RPC_X_NULL_REF_POINTER);
2150 return FALSE;
2153 return backend->fpDeletePort(pName, hWnd, pPortName);
2156 /******************************************************************************
2157 * SetPrinterW [WINSPOOL.@]
2159 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2161 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2162 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2163 return FALSE;
2166 /******************************************************************************
2167 * WritePrinter [WINSPOOL.@]
2169 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2171 opened_printer_t *printer;
2172 BOOL ret = FALSE;
2174 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2176 EnterCriticalSection(&printer_handles_cs);
2177 printer = get_opened_printer(hPrinter);
2178 if(!printer)
2180 SetLastError(ERROR_INVALID_HANDLE);
2181 goto end;
2184 if(!printer->doc)
2186 SetLastError(ERROR_SPL_NO_STARTDOC);
2187 goto end;
2190 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2191 end:
2192 LeaveCriticalSection(&printer_handles_cs);
2193 return ret;
2196 /*****************************************************************************
2197 * AddFormA [WINSPOOL.@]
2199 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2201 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2202 return 1;
2205 /*****************************************************************************
2206 * AddFormW [WINSPOOL.@]
2208 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2210 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2211 return 1;
2214 /*****************************************************************************
2215 * AddJobA [WINSPOOL.@]
2217 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2219 BOOL ret;
2220 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2221 DWORD needed;
2223 if(Level != 1) {
2224 SetLastError(ERROR_INVALID_LEVEL);
2225 return FALSE;
2228 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2230 if(ret) {
2231 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2232 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2233 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2234 if(*pcbNeeded > cbBuf) {
2235 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2236 ret = FALSE;
2237 } else {
2238 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2239 addjobA->JobId = addjobW->JobId;
2240 addjobA->Path = (char *)(addjobA + 1);
2241 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2244 return ret;
2247 /*****************************************************************************
2248 * AddJobW [WINSPOOL.@]
2250 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2252 opened_printer_t *printer;
2253 job_t *job;
2254 BOOL ret = FALSE;
2255 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2256 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2257 WCHAR path[MAX_PATH], filename[MAX_PATH];
2258 DWORD len;
2259 ADDJOB_INFO_1W *addjob;
2261 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2263 EnterCriticalSection(&printer_handles_cs);
2265 printer = get_opened_printer(hPrinter);
2267 if(!printer) {
2268 SetLastError(ERROR_INVALID_HANDLE);
2269 goto end;
2272 if(Level != 1) {
2273 SetLastError(ERROR_INVALID_LEVEL);
2274 goto end;
2277 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2278 if(!job)
2279 goto end;
2281 job->job_id = InterlockedIncrement(&next_job_id);
2283 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2284 if(path[len - 1] != '\\')
2285 path[len++] = '\\';
2286 memcpy(path + len, spool_path, sizeof(spool_path));
2287 sprintfW(filename, fmtW, path, job->job_id);
2289 len = strlenW(filename);
2290 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2291 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2292 job->document_title = strdupW(default_doc_title);
2293 job->printer_name = strdupW(printer->name);
2294 job->devmode = NULL;
2295 list_add_tail(&printer->queue->jobs, &job->entry);
2297 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2298 if(*pcbNeeded <= cbBuf) {
2299 addjob = (ADDJOB_INFO_1W*)pData;
2300 addjob->JobId = job->job_id;
2301 addjob->Path = (WCHAR *)(addjob + 1);
2302 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2303 ret = TRUE;
2304 } else
2305 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2307 end:
2308 LeaveCriticalSection(&printer_handles_cs);
2309 return ret;
2312 /*****************************************************************************
2313 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2315 * Return the PATH for the Print-Processors
2317 * See GetPrintProcessorDirectoryW.
2321 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2322 DWORD level, LPBYTE Info,
2323 DWORD cbBuf, LPDWORD pcbNeeded)
2325 LPWSTR serverW = NULL;
2326 LPWSTR envW = NULL;
2327 BOOL ret;
2328 INT len;
2330 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2331 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2334 if (server) {
2335 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2336 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2337 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2340 if (env) {
2341 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2342 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2343 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2346 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2347 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2349 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2350 cbBuf, pcbNeeded);
2352 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2353 cbBuf, NULL, NULL) > 0;
2356 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2357 HeapFree(GetProcessHeap(), 0, envW);
2358 HeapFree(GetProcessHeap(), 0, serverW);
2359 return ret;
2362 /*****************************************************************************
2363 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2365 * Return the PATH for the Print-Processors
2367 * PARAMS
2368 * server [I] Servername (NT only) or NULL (local Computer)
2369 * env [I] Printing-Environment (see below) or NULL (Default)
2370 * level [I] Structure-Level (must be 1)
2371 * Info [O] PTR to Buffer that receives the Result
2372 * cbBuf [I] Size of Buffer at "Info"
2373 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2374 * required for the Buffer at "Info"
2376 * RETURNS
2377 * Success: TRUE and in pcbNeeded the Bytes used in Info
2378 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2379 * if cbBuf is too small
2381 * Native Values returned in Info on Success:
2382 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2383 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2384 *| win9x(Windows 4.0): "%winsysdir%"
2386 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2388 * BUGS
2389 * Only NULL or "" is supported for server
2392 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2393 DWORD level, LPBYTE Info,
2394 DWORD cbBuf, LPDWORD pcbNeeded)
2397 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2398 Info, cbBuf, pcbNeeded);
2400 if ((backend == NULL) && !load_backend()) return FALSE;
2402 if (level != 1) {
2403 /* (Level != 1) is ignored in win9x */
2404 SetLastError(ERROR_INVALID_LEVEL);
2405 return FALSE;
2408 if (pcbNeeded == NULL) {
2409 /* (pcbNeeded == NULL) is ignored in win9x */
2410 SetLastError(RPC_X_NULL_REF_POINTER);
2411 return FALSE;
2414 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2417 /*****************************************************************************
2418 * WINSPOOL_OpenDriverReg [internal]
2420 * opens the registry for the printer drivers depending on the given input
2421 * variable pEnvironment
2423 * RETURNS:
2424 * the opened hkey on success
2425 * NULL on error
2427 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2429 HKEY retval = NULL;
2430 LPWSTR buffer;
2431 const printenv_t * env;
2433 TRACE("(%s)\n", debugstr_w(pEnvironment));
2435 env = validate_envW(pEnvironment);
2436 if (!env) return NULL;
2438 buffer = HeapAlloc( GetProcessHeap(), 0,
2439 (strlenW(DriversW) + strlenW(env->envname) +
2440 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2441 if(buffer) {
2442 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2443 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2444 HeapFree(GetProcessHeap(), 0, buffer);
2446 return retval;
2449 /*****************************************************************************
2450 * set_devices_and_printerports [internal]
2452 * set the [Devices] and [PrinterPorts] entries for a printer.
2455 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2457 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2458 WCHAR *devline;
2459 HKEY hkey;
2461 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2463 /* FIXME: the driver must change to "winspool" */
2464 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2465 if (devline) {
2466 lstrcpyW(devline, driver_nt);
2467 lstrcatW(devline, commaW);
2468 lstrcatW(devline, pi->pPortName);
2470 TRACE("using %s\n", debugstr_w(devline));
2471 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2472 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2473 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2474 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2475 RegCloseKey(hkey);
2478 lstrcatW(devline, timeout_15_45);
2479 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2480 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2481 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2482 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2483 RegCloseKey(hkey);
2485 HeapFree(GetProcessHeap(), 0, devline);
2489 /*****************************************************************************
2490 * AddPrinterW [WINSPOOL.@]
2492 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2494 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2495 LPDEVMODEA dmA;
2496 LPDEVMODEW dmW;
2497 HANDLE retval;
2498 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2499 LONG size;
2500 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2501 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2502 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2503 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2504 statusW[] = {'S','t','a','t','u','s',0},
2505 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2507 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2509 if(pName != NULL) {
2510 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2511 SetLastError(ERROR_INVALID_PARAMETER);
2512 return 0;
2514 if(Level != 2) {
2515 ERR("Level = %d, unsupported!\n", Level);
2516 SetLastError(ERROR_INVALID_LEVEL);
2517 return 0;
2519 if(!pPrinter) {
2520 SetLastError(ERROR_INVALID_PARAMETER);
2521 return 0;
2523 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2524 ERROR_SUCCESS) {
2525 ERR("Can't create Printers key\n");
2526 return 0;
2528 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2529 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2530 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2531 RegCloseKey(hkeyPrinter);
2532 RegCloseKey(hkeyPrinters);
2533 return 0;
2535 RegCloseKey(hkeyPrinter);
2537 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2538 if(!hkeyDrivers) {
2539 ERR("Can't create Drivers key\n");
2540 RegCloseKey(hkeyPrinters);
2541 return 0;
2543 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2544 ERROR_SUCCESS) {
2545 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2546 RegCloseKey(hkeyPrinters);
2547 RegCloseKey(hkeyDrivers);
2548 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2549 return 0;
2551 RegCloseKey(hkeyDriver);
2552 RegCloseKey(hkeyDrivers);
2554 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2555 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2556 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2557 RegCloseKey(hkeyPrinters);
2558 return 0;
2561 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2562 ERROR_SUCCESS) {
2563 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2564 SetLastError(ERROR_INVALID_PRINTER_NAME);
2565 RegCloseKey(hkeyPrinters);
2566 return 0;
2569 set_devices_and_printerports(pi);
2570 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2571 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2572 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2574 /* See if we can load the driver. We may need the devmode structure anyway
2576 * FIXME:
2577 * Note that DocumentPropertiesW will briefly try to open the printer we
2578 * just create to find a DEVMODEA struct (it will use the WINEPS default
2579 * one in case it is not there, so we are ok).
2581 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2583 if(size < 0) {
2584 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2585 size = sizeof(DEVMODEW);
2587 if(pi->pDevMode)
2588 dmW = pi->pDevMode;
2589 else
2591 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2592 dmW->dmSize = size;
2593 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2595 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2596 HeapFree(GetProcessHeap(),0,dmW);
2597 dmW=NULL;
2599 else
2601 /* set devmode to printer name */
2602 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2606 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2607 and we support these drivers. NT writes DEVMODEW so somehow
2608 we'll need to distinguish between these when we support NT
2609 drivers */
2610 if (dmW)
2612 dmA = DEVMODEdupWtoA(dmW);
2613 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2614 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2615 HeapFree(GetProcessHeap(), 0, dmA);
2616 if(!pi->pDevMode)
2617 HeapFree(GetProcessHeap(), 0, dmW);
2619 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2620 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2621 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2622 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2624 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2625 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2626 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2627 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2628 (LPBYTE)&pi->Priority, sizeof(DWORD));
2629 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2630 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2631 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2632 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2633 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2634 (LPBYTE)&pi->Status, sizeof(DWORD));
2635 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2636 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2638 RegCloseKey(hkeyPrinter);
2639 RegCloseKey(hkeyPrinters);
2640 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2641 ERR("OpenPrinter failing\n");
2642 return 0;
2644 return retval;
2647 /*****************************************************************************
2648 * AddPrinterA [WINSPOOL.@]
2650 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2652 UNICODE_STRING pNameW;
2653 PWSTR pwstrNameW;
2654 PRINTER_INFO_2W *piW;
2655 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2656 HANDLE ret;
2658 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2659 if(Level != 2) {
2660 ERR("Level = %d, unsupported!\n", Level);
2661 SetLastError(ERROR_INVALID_LEVEL);
2662 return 0;
2664 pwstrNameW = asciitounicode(&pNameW,pName);
2665 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2667 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2669 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2670 RtlFreeUnicodeString(&pNameW);
2671 return ret;
2675 /*****************************************************************************
2676 * ClosePrinter [WINSPOOL.@]
2678 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2680 UINT_PTR i = (UINT_PTR)hPrinter;
2681 opened_printer_t *printer = NULL;
2682 BOOL ret = FALSE;
2684 TRACE("(%p)\n", hPrinter);
2686 EnterCriticalSection(&printer_handles_cs);
2688 if ((i > 0) && (i <= nb_printer_handles))
2689 printer = printer_handles[i - 1];
2692 if(printer)
2694 struct list *cursor, *cursor2;
2696 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2698 if (printer->backend_printer) {
2699 backend->fpClosePrinter(printer->backend_printer);
2702 if(printer->doc)
2703 EndDocPrinter(hPrinter);
2705 if(InterlockedDecrement(&printer->queue->ref) == 0)
2707 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2709 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2710 ScheduleJob(hPrinter, job->job_id);
2712 HeapFree(GetProcessHeap(), 0, printer->queue);
2715 HeapFree(GetProcessHeap(), 0, printer->printername);
2716 HeapFree(GetProcessHeap(), 0, printer->name);
2717 HeapFree(GetProcessHeap(), 0, printer);
2718 printer_handles[i - 1] = NULL;
2719 ret = TRUE;
2721 LeaveCriticalSection(&printer_handles_cs);
2722 return ret;
2725 /*****************************************************************************
2726 * DeleteFormA [WINSPOOL.@]
2728 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2730 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2731 return 1;
2734 /*****************************************************************************
2735 * DeleteFormW [WINSPOOL.@]
2737 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2739 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2740 return 1;
2743 /*****************************************************************************
2744 * DeletePrinter [WINSPOOL.@]
2746 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2748 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2749 HKEY hkeyPrinters, hkey;
2751 if(!lpNameW) {
2752 SetLastError(ERROR_INVALID_HANDLE);
2753 return FALSE;
2755 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2756 RegDeleteTreeW(hkeyPrinters, lpNameW);
2757 RegCloseKey(hkeyPrinters);
2759 WriteProfileStringW(devicesW, lpNameW, NULL);
2760 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2762 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2763 RegDeleteValueW(hkey, lpNameW);
2764 RegCloseKey(hkey);
2767 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2768 RegDeleteValueW(hkey, lpNameW);
2769 RegCloseKey(hkey);
2771 return TRUE;
2774 /*****************************************************************************
2775 * SetPrinterA [WINSPOOL.@]
2777 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2778 DWORD Command)
2780 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2781 return FALSE;
2784 /*****************************************************************************
2785 * SetJobA [WINSPOOL.@]
2787 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2788 LPBYTE pJob, DWORD Command)
2790 BOOL ret;
2791 LPBYTE JobW;
2792 UNICODE_STRING usBuffer;
2794 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2796 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2797 are all ignored by SetJob, so we don't bother copying them */
2798 switch(Level)
2800 case 0:
2801 JobW = NULL;
2802 break;
2803 case 1:
2805 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2806 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2808 JobW = (LPBYTE)info1W;
2809 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2810 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2811 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2812 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2813 info1W->Status = info1A->Status;
2814 info1W->Priority = info1A->Priority;
2815 info1W->Position = info1A->Position;
2816 info1W->PagesPrinted = info1A->PagesPrinted;
2817 break;
2819 case 2:
2821 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2822 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2824 JobW = (LPBYTE)info2W;
2825 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2826 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2827 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2828 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2829 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2830 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2831 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2832 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2833 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2834 info2W->Status = info2A->Status;
2835 info2W->Priority = info2A->Priority;
2836 info2W->Position = info2A->Position;
2837 info2W->StartTime = info2A->StartTime;
2838 info2W->UntilTime = info2A->UntilTime;
2839 info2W->PagesPrinted = info2A->PagesPrinted;
2840 break;
2842 case 3:
2843 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2844 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2845 break;
2846 default:
2847 SetLastError(ERROR_INVALID_LEVEL);
2848 return FALSE;
2851 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2853 switch(Level)
2855 case 1:
2857 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2858 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2859 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2860 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2861 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2862 break;
2864 case 2:
2866 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2867 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2868 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2869 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2870 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2871 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2872 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2873 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2874 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2875 break;
2878 HeapFree(GetProcessHeap(), 0, JobW);
2880 return ret;
2883 /*****************************************************************************
2884 * SetJobW [WINSPOOL.@]
2886 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2887 LPBYTE pJob, DWORD Command)
2889 BOOL ret = FALSE;
2890 job_t *job;
2891 DWORD size;
2893 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2894 FIXME("Ignoring everything other than document title\n");
2896 EnterCriticalSection(&printer_handles_cs);
2897 job = get_job(hPrinter, JobId);
2898 if(!job)
2899 goto end;
2901 switch(Level)
2903 case 0:
2904 break;
2905 case 1:
2907 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2908 HeapFree(GetProcessHeap(), 0, job->document_title);
2909 job->document_title = strdupW(info1->pDocument);
2910 break;
2912 case 2:
2914 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2915 HeapFree(GetProcessHeap(), 0, job->document_title);
2916 job->document_title = strdupW(info2->pDocument);
2917 HeapFree(GetProcessHeap(), 0, job->devmode);
2918 if (info2->pDevMode)
2920 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2921 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2922 memcpy(job->devmode, info2->pDevMode, size);
2924 else
2925 job->devmode = NULL;
2926 break;
2928 case 3:
2929 break;
2930 default:
2931 SetLastError(ERROR_INVALID_LEVEL);
2932 goto end;
2934 ret = TRUE;
2935 end:
2936 LeaveCriticalSection(&printer_handles_cs);
2937 return ret;
2940 /*****************************************************************************
2941 * EndDocPrinter [WINSPOOL.@]
2943 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2945 opened_printer_t *printer;
2946 BOOL ret = FALSE;
2947 TRACE("(%p)\n", hPrinter);
2949 EnterCriticalSection(&printer_handles_cs);
2951 printer = get_opened_printer(hPrinter);
2952 if(!printer)
2954 SetLastError(ERROR_INVALID_HANDLE);
2955 goto end;
2958 if(!printer->doc)
2960 SetLastError(ERROR_SPL_NO_STARTDOC);
2961 goto end;
2964 CloseHandle(printer->doc->hf);
2965 ScheduleJob(hPrinter, printer->doc->job_id);
2966 HeapFree(GetProcessHeap(), 0, printer->doc);
2967 printer->doc = NULL;
2968 ret = TRUE;
2969 end:
2970 LeaveCriticalSection(&printer_handles_cs);
2971 return ret;
2974 /*****************************************************************************
2975 * EndPagePrinter [WINSPOOL.@]
2977 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2979 FIXME("(%p): stub\n", hPrinter);
2980 return TRUE;
2983 /*****************************************************************************
2984 * StartDocPrinterA [WINSPOOL.@]
2986 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2988 UNICODE_STRING usBuffer;
2989 DOC_INFO_2W doc2W;
2990 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2991 DWORD ret;
2993 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2994 or one (DOC_INFO_3) extra DWORDs */
2996 switch(Level) {
2997 case 2:
2998 doc2W.JobId = doc2->JobId;
2999 /* fall through */
3000 case 3:
3001 doc2W.dwMode = doc2->dwMode;
3002 /* fall through */
3003 case 1:
3004 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3005 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3006 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3007 break;
3009 default:
3010 SetLastError(ERROR_INVALID_LEVEL);
3011 return FALSE;
3014 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3016 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3017 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3018 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3020 return ret;
3023 /*****************************************************************************
3024 * StartDocPrinterW [WINSPOOL.@]
3026 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3028 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3029 opened_printer_t *printer;
3030 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3031 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3032 JOB_INFO_1W job_info;
3033 DWORD needed, ret = 0;
3034 HANDLE hf;
3035 WCHAR *filename;
3036 job_t *job;
3038 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3039 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3040 debugstr_w(doc->pDatatype));
3042 if(Level < 1 || Level > 3)
3044 SetLastError(ERROR_INVALID_LEVEL);
3045 return 0;
3048 EnterCriticalSection(&printer_handles_cs);
3049 printer = get_opened_printer(hPrinter);
3050 if(!printer)
3052 SetLastError(ERROR_INVALID_HANDLE);
3053 goto end;
3056 if(printer->doc)
3058 SetLastError(ERROR_INVALID_PRINTER_STATE);
3059 goto end;
3062 /* Even if we're printing to a file we still add a print job, we'll
3063 just ignore the spool file name */
3065 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3067 ERR("AddJob failed gle %u\n", GetLastError());
3068 goto end;
3071 /* use pOutputFile only, when it is a real filename */
3072 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3073 filename = doc->pOutputFile;
3074 else
3075 filename = addjob->Path;
3077 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3078 if(hf == INVALID_HANDLE_VALUE)
3079 goto end;
3081 memset(&job_info, 0, sizeof(job_info));
3082 job_info.pDocument = doc->pDocName;
3083 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3085 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3086 printer->doc->hf = hf;
3087 ret = printer->doc->job_id = addjob->JobId;
3088 job = get_job(hPrinter, ret);
3089 job->portname = strdupW(doc->pOutputFile);
3091 end:
3092 LeaveCriticalSection(&printer_handles_cs);
3094 return ret;
3097 /*****************************************************************************
3098 * StartPagePrinter [WINSPOOL.@]
3100 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3102 FIXME("(%p): stub\n", hPrinter);
3103 return TRUE;
3106 /*****************************************************************************
3107 * GetFormA [WINSPOOL.@]
3109 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3110 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3112 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3113 Level,pForm,cbBuf,pcbNeeded);
3114 return FALSE;
3117 /*****************************************************************************
3118 * GetFormW [WINSPOOL.@]
3120 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3121 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3123 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3124 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3125 return FALSE;
3128 /*****************************************************************************
3129 * SetFormA [WINSPOOL.@]
3131 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3132 LPBYTE pForm)
3134 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3135 return FALSE;
3138 /*****************************************************************************
3139 * SetFormW [WINSPOOL.@]
3141 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3142 LPBYTE pForm)
3144 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3145 return FALSE;
3148 /*****************************************************************************
3149 * ReadPrinter [WINSPOOL.@]
3151 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3152 LPDWORD pNoBytesRead)
3154 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3155 return FALSE;
3158 /*****************************************************************************
3159 * ResetPrinterA [WINSPOOL.@]
3161 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3163 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3164 return FALSE;
3167 /*****************************************************************************
3168 * ResetPrinterW [WINSPOOL.@]
3170 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3172 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3173 return FALSE;
3176 /*****************************************************************************
3177 * WINSPOOL_GetDWORDFromReg
3179 * Return DWORD associated with ValueName from hkey.
3181 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3183 DWORD sz = sizeof(DWORD), type, value = 0;
3184 LONG ret;
3186 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3188 if(ret != ERROR_SUCCESS) {
3189 WARN("Got ret = %d on name %s\n", ret, ValueName);
3190 return 0;
3192 if(type != REG_DWORD) {
3193 ERR("Got type %d\n", type);
3194 return 0;
3196 return value;
3200 /*****************************************************************************
3201 * get_filename_from_reg [internal]
3203 * Get ValueName from hkey storing result in out
3204 * when the Value in the registry has only a filename, use driverdir as prefix
3205 * outlen is space left in out
3206 * String is stored either as unicode or ascii
3210 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3211 LPBYTE out, DWORD outlen, LPDWORD needed)
3213 WCHAR filename[MAX_PATH];
3214 DWORD size;
3215 DWORD type;
3216 LONG ret;
3217 LPWSTR buffer = filename;
3218 LPWSTR ptr;
3220 *needed = 0;
3221 size = sizeof(filename);
3222 buffer[0] = '\0';
3223 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3224 if (ret == ERROR_MORE_DATA) {
3225 TRACE("need dynamic buffer: %u\n", size);
3226 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3227 if (!buffer) {
3228 /* No Memory is bad */
3229 return FALSE;
3231 buffer[0] = '\0';
3232 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3235 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3236 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3237 return FALSE;
3240 ptr = buffer;
3241 while (ptr) {
3242 /* do we have a full path ? */
3243 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3244 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3246 if (!ret) {
3247 /* we must build the full Path */
3248 *needed += dirlen;
3249 if ((out) && (outlen > dirlen)) {
3250 lstrcpyW((LPWSTR)out, driverdir);
3251 out += dirlen;
3252 outlen -= dirlen;
3254 else
3255 out = NULL;
3258 /* write the filename */
3259 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3260 if ((out) && (outlen >= size)) {
3261 lstrcpyW((LPWSTR)out, ptr);
3262 out += size;
3263 outlen -= size;
3265 else
3266 out = NULL;
3267 *needed += size;
3268 ptr += lstrlenW(ptr)+1;
3269 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3272 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3274 /* write the multisz-termination */
3275 if (type == REG_MULTI_SZ) {
3276 size = sizeof(WCHAR);
3278 *needed += size;
3279 if (out && (outlen >= size)) {
3280 memset (out, 0, size);
3283 return TRUE;
3286 /*****************************************************************************
3287 * WINSPOOL_GetStringFromReg
3289 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3290 * String is stored as unicode.
3292 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3293 DWORD buflen, DWORD *needed)
3295 DWORD sz = buflen, type;
3296 LONG ret;
3298 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3299 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3300 WARN("Got ret = %d\n", ret);
3301 *needed = 0;
3302 return FALSE;
3304 /* add space for terminating '\0' */
3305 sz += sizeof(WCHAR);
3306 *needed = sz;
3308 if (ptr)
3309 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3311 return TRUE;
3314 /*****************************************************************************
3315 * WINSPOOL_GetDefaultDevMode
3317 * Get a default DevMode values for wineps.
3318 * FIXME - use ppd.
3321 static void WINSPOOL_GetDefaultDevMode(
3322 LPBYTE ptr,
3323 DWORD buflen, DWORD *needed)
3325 DEVMODEW dm;
3326 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3328 /* fill default DEVMODE - should be read from ppd... */
3329 ZeroMemory( &dm, sizeof(dm) );
3330 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3331 dm.dmSpecVersion = DM_SPECVERSION;
3332 dm.dmDriverVersion = 1;
3333 dm.dmSize = sizeof(DEVMODEW);
3334 dm.dmDriverExtra = 0;
3335 dm.dmFields =
3336 DM_ORIENTATION | DM_PAPERSIZE |
3337 DM_PAPERLENGTH | DM_PAPERWIDTH |
3338 DM_SCALE |
3339 DM_COPIES |
3340 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3341 DM_YRESOLUTION | DM_TTOPTION;
3343 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3344 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3345 dm.u1.s1.dmPaperLength = 2970;
3346 dm.u1.s1.dmPaperWidth = 2100;
3348 dm.u1.s1.dmScale = 100;
3349 dm.u1.s1.dmCopies = 1;
3350 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3351 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3352 /* dm.dmColor */
3353 /* dm.dmDuplex */
3354 dm.dmYResolution = 300; /* 300dpi */
3355 dm.dmTTOption = DMTT_BITMAP;
3356 /* dm.dmCollate */
3357 /* dm.dmFormName */
3358 /* dm.dmLogPixels */
3359 /* dm.dmBitsPerPel */
3360 /* dm.dmPelsWidth */
3361 /* dm.dmPelsHeight */
3362 /* dm.u2.dmDisplayFlags */
3363 /* dm.dmDisplayFrequency */
3364 /* dm.dmICMMethod */
3365 /* dm.dmICMIntent */
3366 /* dm.dmMediaType */
3367 /* dm.dmDitherType */
3368 /* dm.dmReserved1 */
3369 /* dm.dmReserved2 */
3370 /* dm.dmPanningWidth */
3371 /* dm.dmPanningHeight */
3373 if(buflen >= sizeof(DEVMODEW))
3374 memcpy(ptr, &dm, sizeof(DEVMODEW));
3375 *needed = sizeof(DEVMODEW);
3378 /*****************************************************************************
3379 * WINSPOOL_GetDevModeFromReg
3381 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3382 * DevMode is stored either as unicode or ascii.
3384 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3385 LPBYTE ptr,
3386 DWORD buflen, DWORD *needed)
3388 DWORD sz = buflen, type;
3389 LONG ret;
3391 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3392 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3393 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3394 if (sz < sizeof(DEVMODEA))
3396 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3397 return FALSE;
3399 /* ensures that dmSize is not erratically bogus if registry is invalid */
3400 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3401 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3402 sz += (CCHDEVICENAME + CCHFORMNAME);
3403 if (ptr && (buflen >= sz)) {
3404 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3405 memcpy(ptr, dmW, sz);
3406 HeapFree(GetProcessHeap(),0,dmW);
3408 *needed = sz;
3409 return TRUE;
3412 /*********************************************************************
3413 * WINSPOOL_GetPrinter_1
3415 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3417 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3418 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3420 DWORD size, left = cbBuf;
3421 BOOL space = (cbBuf > 0);
3422 LPBYTE ptr = buf;
3424 *pcbNeeded = 0;
3426 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3427 if(space && size <= left) {
3428 pi1->pName = (LPWSTR)ptr;
3429 ptr += size;
3430 left -= size;
3431 } else
3432 space = FALSE;
3433 *pcbNeeded += size;
3436 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3437 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3438 if(space && size <= left) {
3439 pi1->pDescription = (LPWSTR)ptr;
3440 ptr += size;
3441 left -= size;
3442 } else
3443 space = FALSE;
3444 *pcbNeeded += size;
3447 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3448 if(space && size <= left) {
3449 pi1->pComment = (LPWSTR)ptr;
3450 ptr += size;
3451 left -= size;
3452 } else
3453 space = FALSE;
3454 *pcbNeeded += size;
3457 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3459 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3460 memset(pi1, 0, sizeof(*pi1));
3462 return space;
3464 /*********************************************************************
3465 * WINSPOOL_GetPrinter_2
3467 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3469 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3470 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3472 DWORD size, left = cbBuf;
3473 BOOL space = (cbBuf > 0);
3474 LPBYTE ptr = buf;
3476 *pcbNeeded = 0;
3478 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3479 if(space && size <= left) {
3480 pi2->pPrinterName = (LPWSTR)ptr;
3481 ptr += size;
3482 left -= size;
3483 } else
3484 space = FALSE;
3485 *pcbNeeded += size;
3487 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3488 if(space && size <= left) {
3489 pi2->pShareName = (LPWSTR)ptr;
3490 ptr += size;
3491 left -= size;
3492 } else
3493 space = FALSE;
3494 *pcbNeeded += size;
3496 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3497 if(space && size <= left) {
3498 pi2->pPortName = (LPWSTR)ptr;
3499 ptr += size;
3500 left -= size;
3501 } else
3502 space = FALSE;
3503 *pcbNeeded += size;
3505 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3506 if(space && size <= left) {
3507 pi2->pDriverName = (LPWSTR)ptr;
3508 ptr += size;
3509 left -= size;
3510 } else
3511 space = FALSE;
3512 *pcbNeeded += size;
3514 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3515 if(space && size <= left) {
3516 pi2->pComment = (LPWSTR)ptr;
3517 ptr += size;
3518 left -= size;
3519 } else
3520 space = FALSE;
3521 *pcbNeeded += size;
3523 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3524 if(space && size <= left) {
3525 pi2->pLocation = (LPWSTR)ptr;
3526 ptr += size;
3527 left -= size;
3528 } else
3529 space = FALSE;
3530 *pcbNeeded += size;
3532 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3533 if(space && size <= left) {
3534 pi2->pDevMode = (LPDEVMODEW)ptr;
3535 ptr += size;
3536 left -= size;
3537 } else
3538 space = FALSE;
3539 *pcbNeeded += size;
3541 else
3543 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3544 if(space && size <= left) {
3545 pi2->pDevMode = (LPDEVMODEW)ptr;
3546 ptr += size;
3547 left -= size;
3548 } else
3549 space = FALSE;
3550 *pcbNeeded += size;
3552 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3553 if(space && size <= left) {
3554 pi2->pSepFile = (LPWSTR)ptr;
3555 ptr += size;
3556 left -= size;
3557 } else
3558 space = FALSE;
3559 *pcbNeeded += size;
3561 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3562 if(space && size <= left) {
3563 pi2->pPrintProcessor = (LPWSTR)ptr;
3564 ptr += size;
3565 left -= size;
3566 } else
3567 space = FALSE;
3568 *pcbNeeded += size;
3570 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3571 if(space && size <= left) {
3572 pi2->pDatatype = (LPWSTR)ptr;
3573 ptr += size;
3574 left -= size;
3575 } else
3576 space = FALSE;
3577 *pcbNeeded += size;
3579 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3580 if(space && size <= left) {
3581 pi2->pParameters = (LPWSTR)ptr;
3582 ptr += size;
3583 left -= size;
3584 } else
3585 space = FALSE;
3586 *pcbNeeded += size;
3588 if(pi2) {
3589 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3590 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3591 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3592 "Default Priority");
3593 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3594 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3597 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3598 memset(pi2, 0, sizeof(*pi2));
3600 return space;
3603 /*********************************************************************
3604 * WINSPOOL_GetPrinter_4
3606 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3608 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3609 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3611 DWORD size, left = cbBuf;
3612 BOOL space = (cbBuf > 0);
3613 LPBYTE ptr = buf;
3615 *pcbNeeded = 0;
3617 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3618 if(space && size <= left) {
3619 pi4->pPrinterName = (LPWSTR)ptr;
3620 ptr += size;
3621 left -= size;
3622 } else
3623 space = FALSE;
3624 *pcbNeeded += size;
3626 if(pi4) {
3627 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3630 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3631 memset(pi4, 0, sizeof(*pi4));
3633 return space;
3636 /*********************************************************************
3637 * WINSPOOL_GetPrinter_5
3639 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3641 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3642 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3644 DWORD size, left = cbBuf;
3645 BOOL space = (cbBuf > 0);
3646 LPBYTE ptr = buf;
3648 *pcbNeeded = 0;
3650 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3651 if(space && size <= left) {
3652 pi5->pPrinterName = (LPWSTR)ptr;
3653 ptr += size;
3654 left -= size;
3655 } else
3656 space = FALSE;
3657 *pcbNeeded += size;
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3660 if(space && size <= left) {
3661 pi5->pPortName = (LPWSTR)ptr;
3662 ptr += size;
3663 left -= size;
3664 } else
3665 space = FALSE;
3666 *pcbNeeded += size;
3668 if(pi5) {
3669 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3670 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3671 "dnsTimeout");
3672 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3673 "txTimeout");
3676 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3677 memset(pi5, 0, sizeof(*pi5));
3679 return space;
3682 /*********************************************************************
3683 * WINSPOOL_GetPrinter_7
3685 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3687 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3688 DWORD cbBuf, LPDWORD pcbNeeded)
3690 DWORD size, left = cbBuf;
3691 BOOL space = (cbBuf > 0);
3692 LPBYTE ptr = buf;
3694 *pcbNeeded = 0;
3696 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3698 ptr = NULL;
3699 size = sizeof(pi7->pszObjectGUID);
3701 if (space && size <= left) {
3702 pi7->pszObjectGUID = (LPWSTR)ptr;
3703 ptr += size;
3704 left -= size;
3705 } else
3706 space = FALSE;
3707 *pcbNeeded += size;
3708 if (pi7) {
3709 /* We do not have a Directory Service */
3710 pi7->dwAction = DSPRINT_UNPUBLISH;
3713 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3714 memset(pi7, 0, sizeof(*pi7));
3716 return space;
3719 /*********************************************************************
3720 * WINSPOOL_GetPrinter_9
3722 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3724 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3725 DWORD cbBuf, LPDWORD pcbNeeded)
3727 DWORD size;
3728 BOOL space = (cbBuf > 0);
3730 *pcbNeeded = 0;
3732 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3733 if(space && size <= cbBuf) {
3734 pi9->pDevMode = (LPDEVMODEW)buf;
3735 } else
3736 space = FALSE;
3737 *pcbNeeded += size;
3739 else
3741 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3742 if(space && size <= cbBuf) {
3743 pi9->pDevMode = (LPDEVMODEW)buf;
3744 } else
3745 space = FALSE;
3746 *pcbNeeded += size;
3749 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3750 memset(pi9, 0, sizeof(*pi9));
3752 return space;
3755 /*****************************************************************************
3756 * GetPrinterW [WINSPOOL.@]
3758 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3759 DWORD cbBuf, LPDWORD pcbNeeded)
3761 LPCWSTR name;
3762 DWORD size, needed = 0;
3763 LPBYTE ptr = NULL;
3764 HKEY hkeyPrinter, hkeyPrinters;
3765 BOOL ret;
3767 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3769 if (!(name = get_opened_printer_name(hPrinter))) {
3770 SetLastError(ERROR_INVALID_HANDLE);
3771 return FALSE;
3774 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3775 ERROR_SUCCESS) {
3776 ERR("Can't create Printers key\n");
3777 return FALSE;
3779 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3781 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3782 RegCloseKey(hkeyPrinters);
3783 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3784 return FALSE;
3787 switch(Level) {
3788 case 2:
3790 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3792 size = sizeof(PRINTER_INFO_2W);
3793 if(size <= cbBuf) {
3794 ptr = pPrinter + size;
3795 cbBuf -= size;
3796 memset(pPrinter, 0, size);
3797 } else {
3798 pi2 = NULL;
3799 cbBuf = 0;
3801 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3802 needed += size;
3803 break;
3806 case 4:
3808 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3810 size = sizeof(PRINTER_INFO_4W);
3811 if(size <= cbBuf) {
3812 ptr = pPrinter + size;
3813 cbBuf -= size;
3814 memset(pPrinter, 0, size);
3815 } else {
3816 pi4 = NULL;
3817 cbBuf = 0;
3819 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3820 needed += size;
3821 break;
3825 case 5:
3827 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3829 size = sizeof(PRINTER_INFO_5W);
3830 if(size <= cbBuf) {
3831 ptr = pPrinter + size;
3832 cbBuf -= size;
3833 memset(pPrinter, 0, size);
3834 } else {
3835 pi5 = NULL;
3836 cbBuf = 0;
3839 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3840 needed += size;
3841 break;
3845 case 6:
3847 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3849 size = sizeof(PRINTER_INFO_6);
3850 if (size <= cbBuf) {
3851 /* FIXME: We do not update the status yet */
3852 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3853 ret = TRUE;
3854 } else {
3855 ret = FALSE;
3858 needed += size;
3859 break;
3862 case 7:
3864 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3866 size = sizeof(PRINTER_INFO_7W);
3867 if (size <= cbBuf) {
3868 ptr = pPrinter + size;
3869 cbBuf -= size;
3870 memset(pPrinter, 0, size);
3871 } else {
3872 pi7 = NULL;
3873 cbBuf = 0;
3876 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3877 needed += size;
3878 break;
3882 case 9:
3884 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3886 size = sizeof(PRINTER_INFO_9W);
3887 if(size <= cbBuf) {
3888 ptr = pPrinter + size;
3889 cbBuf -= size;
3890 memset(pPrinter, 0, size);
3891 } else {
3892 pi9 = NULL;
3893 cbBuf = 0;
3896 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3897 needed += size;
3898 break;
3902 default:
3903 FIXME("Unimplemented level %d\n", Level);
3904 SetLastError(ERROR_INVALID_LEVEL);
3905 RegCloseKey(hkeyPrinters);
3906 RegCloseKey(hkeyPrinter);
3907 return FALSE;
3910 RegCloseKey(hkeyPrinter);
3911 RegCloseKey(hkeyPrinters);
3913 TRACE("returning %d needed = %d\n", ret, needed);
3914 if(pcbNeeded) *pcbNeeded = needed;
3915 if(!ret)
3916 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3917 return ret;
3920 /*****************************************************************************
3921 * GetPrinterA [WINSPOOL.@]
3923 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3924 DWORD cbBuf, LPDWORD pcbNeeded)
3926 BOOL ret;
3927 LPBYTE buf = NULL;
3929 if (cbBuf)
3930 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3932 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3933 if (ret)
3934 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3935 HeapFree(GetProcessHeap(), 0, buf);
3937 return ret;
3940 /*****************************************************************************
3941 * WINSPOOL_EnumPrintersW
3943 * Implementation of EnumPrintersW
3945 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3946 DWORD dwLevel, LPBYTE lpbPrinters,
3947 DWORD cbBuf, LPDWORD lpdwNeeded,
3948 LPDWORD lpdwReturned)
3951 HKEY hkeyPrinters, hkeyPrinter;
3952 WCHAR PrinterName[255];
3953 DWORD needed = 0, number = 0;
3954 DWORD used, i, left;
3955 PBYTE pi, buf;
3957 if(lpbPrinters)
3958 memset(lpbPrinters, 0, cbBuf);
3959 if(lpdwReturned)
3960 *lpdwReturned = 0;
3961 if(lpdwNeeded)
3962 *lpdwNeeded = 0;
3964 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3965 if(dwType == PRINTER_ENUM_DEFAULT)
3966 return TRUE;
3968 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3969 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3970 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3971 if (!dwType) {
3972 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3973 return TRUE;
3978 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3979 FIXME("dwType = %08x\n", dwType);
3980 SetLastError(ERROR_INVALID_FLAGS);
3981 return FALSE;
3984 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3985 ERROR_SUCCESS) {
3986 ERR("Can't create Printers key\n");
3987 return FALSE;
3990 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3991 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3992 RegCloseKey(hkeyPrinters);
3993 ERR("Can't query Printers key\n");
3994 return FALSE;
3996 TRACE("Found %d printers\n", number);
3998 switch(dwLevel) {
3999 case 1:
4000 used = number * sizeof(PRINTER_INFO_1W);
4001 break;
4002 case 2:
4003 used = number * sizeof(PRINTER_INFO_2W);
4004 break;
4005 case 4:
4006 used = number * sizeof(PRINTER_INFO_4W);
4007 break;
4008 case 5:
4009 used = number * sizeof(PRINTER_INFO_5W);
4010 break;
4012 default:
4013 SetLastError(ERROR_INVALID_LEVEL);
4014 RegCloseKey(hkeyPrinters);
4015 return FALSE;
4017 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4019 for(i = 0; i < number; i++) {
4020 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4021 ERROR_SUCCESS) {
4022 ERR("Can't enum key number %d\n", i);
4023 RegCloseKey(hkeyPrinters);
4024 return FALSE;
4026 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4027 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4028 ERROR_SUCCESS) {
4029 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4030 RegCloseKey(hkeyPrinters);
4031 return FALSE;
4034 if(cbBuf > used) {
4035 buf = lpbPrinters + used;
4036 left = cbBuf - used;
4037 } else {
4038 buf = NULL;
4039 left = 0;
4042 switch(dwLevel) {
4043 case 1:
4044 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4045 left, &needed);
4046 used += needed;
4047 if(pi) pi += sizeof(PRINTER_INFO_1W);
4048 break;
4049 case 2:
4050 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4051 left, &needed);
4052 used += needed;
4053 if(pi) pi += sizeof(PRINTER_INFO_2W);
4054 break;
4055 case 4:
4056 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4057 left, &needed);
4058 used += needed;
4059 if(pi) pi += sizeof(PRINTER_INFO_4W);
4060 break;
4061 case 5:
4062 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4063 left, &needed);
4064 used += needed;
4065 if(pi) pi += sizeof(PRINTER_INFO_5W);
4066 break;
4067 default:
4068 ERR("Shouldn't be here!\n");
4069 RegCloseKey(hkeyPrinter);
4070 RegCloseKey(hkeyPrinters);
4071 return FALSE;
4073 RegCloseKey(hkeyPrinter);
4075 RegCloseKey(hkeyPrinters);
4077 if(lpdwNeeded)
4078 *lpdwNeeded = used;
4080 if(used > cbBuf) {
4081 if(lpbPrinters)
4082 memset(lpbPrinters, 0, cbBuf);
4083 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4084 return FALSE;
4086 if(lpdwReturned)
4087 *lpdwReturned = number;
4088 SetLastError(ERROR_SUCCESS);
4089 return TRUE;
4093 /******************************************************************
4094 * EnumPrintersW [WINSPOOL.@]
4096 * Enumerates the available printers, print servers and print
4097 * providers, depending on the specified flags, name and level.
4099 * RETURNS:
4101 * If level is set to 1:
4102 * Returns an array of PRINTER_INFO_1 data structures in the
4103 * lpbPrinters buffer.
4105 * If level is set to 2:
4106 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4107 * Returns an array of PRINTER_INFO_2 data structures in the
4108 * lpbPrinters buffer. Note that according to MSDN also an
4109 * OpenPrinter should be performed on every remote printer.
4111 * If level is set to 4 (officially WinNT only):
4112 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4113 * Fast: Only the registry is queried to retrieve printer names,
4114 * no connection to the driver is made.
4115 * Returns an array of PRINTER_INFO_4 data structures in the
4116 * lpbPrinters buffer.
4118 * If level is set to 5 (officially WinNT4/Win9x only):
4119 * Fast: Only the registry is queried to retrieve printer names,
4120 * no connection to the driver is made.
4121 * Returns an array of PRINTER_INFO_5 data structures in the
4122 * lpbPrinters buffer.
4124 * If level set to 3 or 6+:
4125 * returns zero (failure!)
4127 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4128 * for information.
4130 * BUGS:
4131 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4132 * - Only levels 2, 4 and 5 are implemented at the moment.
4133 * - 16-bit printer drivers are not enumerated.
4134 * - Returned amount of bytes used/needed does not match the real Windoze
4135 * implementation (as in this implementation, all strings are part
4136 * of the buffer, whereas Win32 keeps them somewhere else)
4137 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4139 * NOTE:
4140 * - In a regular Wine installation, no registry settings for printers
4141 * exist, which makes this function return an empty list.
4143 BOOL WINAPI EnumPrintersW(
4144 DWORD dwType, /* [in] Types of print objects to enumerate */
4145 LPWSTR lpszName, /* [in] name of objects to enumerate */
4146 DWORD dwLevel, /* [in] type of printer info structure */
4147 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4148 DWORD cbBuf, /* [in] max size of buffer in bytes */
4149 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4150 LPDWORD lpdwReturned /* [out] number of entries returned */
4153 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4154 lpdwNeeded, lpdwReturned);
4157 /******************************************************************
4158 * EnumPrintersA [WINSPOOL.@]
4160 * See EnumPrintersW
4163 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4164 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4166 BOOL ret;
4167 UNICODE_STRING pNameU;
4168 LPWSTR pNameW;
4169 LPBYTE pPrintersW;
4171 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4172 pPrinters, cbBuf, pcbNeeded, pcReturned);
4174 pNameW = asciitounicode(&pNameU, pName);
4176 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4177 MS Office need this */
4178 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4180 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4182 RtlFreeUnicodeString(&pNameU);
4183 if (ret) {
4184 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4186 HeapFree(GetProcessHeap(), 0, pPrintersW);
4187 return ret;
4190 /*****************************************************************************
4191 * WINSPOOL_GetDriverInfoFromReg [internal]
4193 * Enters the information from the registry into the DRIVER_INFO struct
4195 * RETURNS
4196 * zero if the printer driver does not exist in the registry
4197 * (only if Level > 1) otherwise nonzero
4199 static BOOL WINSPOOL_GetDriverInfoFromReg(
4200 HKEY hkeyDrivers,
4201 LPWSTR DriverName,
4202 const printenv_t * env,
4203 DWORD Level,
4204 LPBYTE ptr, /* DRIVER_INFO */
4205 LPBYTE pDriverStrings, /* strings buffer */
4206 DWORD cbBuf, /* size of string buffer */
4207 LPDWORD pcbNeeded) /* space needed for str. */
4209 DWORD size, tmp;
4210 HKEY hkeyDriver;
4211 WCHAR driverdir[MAX_PATH];
4212 DWORD dirlen;
4213 LPBYTE strPtr = pDriverStrings;
4214 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4216 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4217 debugstr_w(DriverName), env,
4218 Level, di, pDriverStrings, cbBuf);
4220 if (di) ZeroMemory(di, di_sizeof[Level]);
4222 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4223 if (*pcbNeeded <= cbBuf)
4224 strcpyW((LPWSTR)strPtr, DriverName);
4226 /* pName for level 1 has a different offset! */
4227 if (Level == 1) {
4228 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4229 return TRUE;
4232 /* .cVersion and .pName for level > 1 */
4233 if (di) {
4234 di->cVersion = env->driverversion;
4235 di->pName = (LPWSTR) strPtr;
4236 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4239 /* Reserve Space for the largest subdir and a Backslash*/
4240 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4241 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4242 /* Should never Fail */
4243 return FALSE;
4245 lstrcatW(driverdir, env->versionsubdir);
4246 lstrcatW(driverdir, backslashW);
4248 /* dirlen must not include the terminating zero */
4249 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4251 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4252 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4253 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4254 return FALSE;
4257 /* pEnvironment */
4258 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4260 *pcbNeeded += size;
4261 if (*pcbNeeded <= cbBuf) {
4262 lstrcpyW((LPWSTR)strPtr, env->envname);
4263 if (di) di->pEnvironment = (LPWSTR)strPtr;
4264 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4267 /* .pDriverPath is the Graphics rendering engine.
4268 The full Path is required to avoid a crash in some apps */
4269 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4270 *pcbNeeded += size;
4271 if (*pcbNeeded <= cbBuf)
4272 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4274 if (di) di->pDriverPath = (LPWSTR)strPtr;
4275 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4278 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4279 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4280 *pcbNeeded += size;
4281 if (*pcbNeeded <= cbBuf)
4282 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4284 if (di) di->pDataFile = (LPWSTR)strPtr;
4285 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4288 /* .pConfigFile is the Driver user Interface */
4289 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4290 *pcbNeeded += size;
4291 if (*pcbNeeded <= cbBuf)
4292 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4294 if (di) di->pConfigFile = (LPWSTR)strPtr;
4295 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4298 if (Level == 2 ) {
4299 RegCloseKey(hkeyDriver);
4300 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4301 return TRUE;
4304 if (Level == 5 ) {
4305 RegCloseKey(hkeyDriver);
4306 FIXME("level 5: incomplete\n");
4307 return TRUE;
4310 /* .pHelpFile */
4311 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4312 *pcbNeeded += size;
4313 if (*pcbNeeded <= cbBuf)
4314 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4316 if (di) di->pHelpFile = (LPWSTR)strPtr;
4317 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4320 /* .pDependentFiles */
4321 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4322 *pcbNeeded += size;
4323 if (*pcbNeeded <= cbBuf)
4324 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4326 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4327 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4329 else if (GetVersion() & 0x80000000) {
4330 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4331 size = 2 * sizeof(WCHAR);
4332 *pcbNeeded += size;
4333 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4335 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4336 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4339 /* .pMonitorName is the optional Language Monitor */
4340 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4341 *pcbNeeded += size;
4342 if (*pcbNeeded <= cbBuf)
4343 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4345 if (di) di->pMonitorName = (LPWSTR)strPtr;
4346 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4349 /* .pDefaultDataType */
4350 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4351 *pcbNeeded += size;
4352 if(*pcbNeeded <= cbBuf)
4353 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4355 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4356 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4359 if (Level == 3 ) {
4360 RegCloseKey(hkeyDriver);
4361 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4362 return TRUE;
4365 /* .pszzPreviousNames */
4366 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4367 *pcbNeeded += size;
4368 if(*pcbNeeded <= cbBuf)
4369 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4371 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4372 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4375 if (Level == 4 ) {
4376 RegCloseKey(hkeyDriver);
4377 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4378 return TRUE;
4381 /* support is missing, but not important enough for a FIXME */
4382 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4384 /* .pszMfgName */
4385 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4386 *pcbNeeded += size;
4387 if(*pcbNeeded <= cbBuf)
4388 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4390 if (di) di->pszMfgName = (LPWSTR)strPtr;
4391 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4394 /* .pszOEMUrl */
4395 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4396 *pcbNeeded += size;
4397 if(*pcbNeeded <= cbBuf)
4398 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4400 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4401 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4404 /* .pszHardwareID */
4405 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4406 *pcbNeeded += size;
4407 if(*pcbNeeded <= cbBuf)
4408 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4410 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4411 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4414 /* .pszProvider */
4415 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4416 *pcbNeeded += size;
4417 if(*pcbNeeded <= cbBuf)
4418 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4420 if (di) di->pszProvider = (LPWSTR)strPtr;
4421 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4424 if (Level == 6 ) {
4425 RegCloseKey(hkeyDriver);
4426 return TRUE;
4429 /* support is missing, but not important enough for a FIXME */
4430 TRACE("level 8: incomplete\n");
4432 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4433 RegCloseKey(hkeyDriver);
4434 return TRUE;
4437 /*****************************************************************************
4438 * GetPrinterDriverW [WINSPOOL.@]
4440 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4441 DWORD Level, LPBYTE pDriverInfo,
4442 DWORD cbBuf, LPDWORD pcbNeeded)
4444 LPCWSTR name;
4445 WCHAR DriverName[100];
4446 DWORD ret, type, size, needed = 0;
4447 LPBYTE ptr = NULL;
4448 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4449 const printenv_t * env;
4451 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4452 Level,pDriverInfo,cbBuf, pcbNeeded);
4454 if (cbBuf > 0)
4455 ZeroMemory(pDriverInfo, cbBuf);
4457 if (!(name = get_opened_printer_name(hPrinter))) {
4458 SetLastError(ERROR_INVALID_HANDLE);
4459 return FALSE;
4462 if (Level < 1 || Level == 7 || Level > 8) {
4463 SetLastError(ERROR_INVALID_LEVEL);
4464 return FALSE;
4467 env = validate_envW(pEnvironment);
4468 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4470 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4471 ERROR_SUCCESS) {
4472 ERR("Can't create Printers key\n");
4473 return FALSE;
4475 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4476 != ERROR_SUCCESS) {
4477 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4478 RegCloseKey(hkeyPrinters);
4479 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4480 return FALSE;
4482 size = sizeof(DriverName);
4483 DriverName[0] = 0;
4484 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4485 (LPBYTE)DriverName, &size);
4486 RegCloseKey(hkeyPrinter);
4487 RegCloseKey(hkeyPrinters);
4488 if(ret != ERROR_SUCCESS) {
4489 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4490 return FALSE;
4493 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4494 if(!hkeyDrivers) {
4495 ERR("Can't create Drivers key\n");
4496 return FALSE;
4499 size = di_sizeof[Level];
4500 if ((size <= cbBuf) && pDriverInfo)
4501 ptr = pDriverInfo + size;
4503 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4504 env, Level, pDriverInfo, ptr,
4505 (cbBuf < size) ? 0 : cbBuf - size,
4506 &needed)) {
4507 RegCloseKey(hkeyDrivers);
4508 return FALSE;
4511 RegCloseKey(hkeyDrivers);
4513 if(pcbNeeded) *pcbNeeded = size + needed;
4514 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4515 if(cbBuf >= size + needed) return TRUE;
4516 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4517 return FALSE;
4520 /*****************************************************************************
4521 * GetPrinterDriverA [WINSPOOL.@]
4523 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4524 DWORD Level, LPBYTE pDriverInfo,
4525 DWORD cbBuf, LPDWORD pcbNeeded)
4527 BOOL ret;
4528 UNICODE_STRING pEnvW;
4529 PWSTR pwstrEnvW;
4530 LPBYTE buf = NULL;
4532 if (cbBuf)
4534 ZeroMemory(pDriverInfo, cbBuf);
4535 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4538 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4539 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4540 cbBuf, pcbNeeded);
4541 if (ret)
4542 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4544 HeapFree(GetProcessHeap(), 0, buf);
4546 RtlFreeUnicodeString(&pEnvW);
4547 return ret;
4550 /*****************************************************************************
4551 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4553 * Return the PATH for the Printer-Drivers (UNICODE)
4555 * PARAMS
4556 * pName [I] Servername (NT only) or NULL (local Computer)
4557 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4558 * Level [I] Structure-Level (must be 1)
4559 * pDriverDirectory [O] PTR to Buffer that receives the Result
4560 * cbBuf [I] Size of Buffer at pDriverDirectory
4561 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4562 * required for pDriverDirectory
4564 * RETURNS
4565 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4566 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4567 * if cbBuf is too small
4569 * Native Values returned in pDriverDirectory on Success:
4570 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4571 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4572 *| win9x(Windows 4.0): "%winsysdir%"
4574 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4576 * FIXME
4577 *- Only NULL or "" is supported for pName
4580 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4581 DWORD Level, LPBYTE pDriverDirectory,
4582 DWORD cbBuf, LPDWORD pcbNeeded)
4584 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4585 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4587 if ((backend == NULL) && !load_backend()) return FALSE;
4589 if (Level != 1) {
4590 /* (Level != 1) is ignored in win9x */
4591 SetLastError(ERROR_INVALID_LEVEL);
4592 return FALSE;
4594 if (pcbNeeded == NULL) {
4595 /* (pcbNeeded == NULL) is ignored in win9x */
4596 SetLastError(RPC_X_NULL_REF_POINTER);
4597 return FALSE;
4600 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4601 pDriverDirectory, cbBuf, pcbNeeded);
4606 /*****************************************************************************
4607 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4609 * Return the PATH for the Printer-Drivers (ANSI)
4611 * See GetPrinterDriverDirectoryW.
4613 * NOTES
4614 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4617 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4618 DWORD Level, LPBYTE pDriverDirectory,
4619 DWORD cbBuf, LPDWORD pcbNeeded)
4621 UNICODE_STRING nameW, environmentW;
4622 BOOL ret;
4623 DWORD pcbNeededW;
4624 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4625 WCHAR *driverDirectoryW = NULL;
4627 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4628 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4630 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4632 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4633 else nameW.Buffer = NULL;
4634 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4635 else environmentW.Buffer = NULL;
4637 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4638 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4639 if (ret) {
4640 DWORD needed;
4641 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4642 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4643 if(pcbNeeded)
4644 *pcbNeeded = needed;
4645 ret = (needed <= cbBuf) ? TRUE : FALSE;
4646 } else
4647 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4649 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4651 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4652 RtlFreeUnicodeString(&environmentW);
4653 RtlFreeUnicodeString(&nameW);
4655 return ret;
4658 /*****************************************************************************
4659 * AddPrinterDriverA [WINSPOOL.@]
4661 * See AddPrinterDriverW.
4664 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4666 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4667 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4670 /******************************************************************************
4671 * AddPrinterDriverW (WINSPOOL.@)
4673 * Install a Printer Driver
4675 * PARAMS
4676 * pName [I] Servername or NULL (local Computer)
4677 * level [I] Level for the supplied DRIVER_INFO_*W struct
4678 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4680 * RESULTS
4681 * Success: TRUE
4682 * Failure: FALSE
4685 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4687 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4688 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4691 /*****************************************************************************
4692 * AddPrintProcessorA [WINSPOOL.@]
4694 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4695 LPSTR pPrintProcessorName)
4697 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4698 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4699 return FALSE;
4702 /*****************************************************************************
4703 * AddPrintProcessorW [WINSPOOL.@]
4705 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4706 LPWSTR pPrintProcessorName)
4708 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4709 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4710 return TRUE;
4713 /*****************************************************************************
4714 * AddPrintProvidorA [WINSPOOL.@]
4716 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4718 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4719 return FALSE;
4722 /*****************************************************************************
4723 * AddPrintProvidorW [WINSPOOL.@]
4725 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4727 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4728 return FALSE;
4731 /*****************************************************************************
4732 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4734 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4735 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4737 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4738 pDevModeOutput, pDevModeInput);
4739 return 0;
4742 /*****************************************************************************
4743 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4745 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4746 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4748 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4749 pDevModeOutput, pDevModeInput);
4750 return 0;
4753 /*****************************************************************************
4754 * PrinterProperties [WINSPOOL.@]
4756 * Displays a dialog to set the properties of the printer.
4758 * RETURNS
4759 * nonzero on success or zero on failure
4761 * BUGS
4762 * implemented as stub only
4764 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4765 HANDLE hPrinter /* [in] handle to printer object */
4767 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4768 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4769 return FALSE;
4772 /*****************************************************************************
4773 * EnumJobsA [WINSPOOL.@]
4776 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4777 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4778 LPDWORD pcReturned)
4780 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4781 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4783 if(pcbNeeded) *pcbNeeded = 0;
4784 if(pcReturned) *pcReturned = 0;
4785 return FALSE;
4789 /*****************************************************************************
4790 * EnumJobsW [WINSPOOL.@]
4793 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4794 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4795 LPDWORD pcReturned)
4797 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4798 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4800 if(pcbNeeded) *pcbNeeded = 0;
4801 if(pcReturned) *pcReturned = 0;
4802 return FALSE;
4805 /*****************************************************************************
4806 * WINSPOOL_EnumPrinterDrivers [internal]
4808 * Delivers information about all printer drivers installed on the
4809 * localhost or a given server
4811 * RETURNS
4812 * nonzero on success or zero on failure. If the buffer for the returned
4813 * information is too small the function will return an error
4815 * BUGS
4816 * - only implemented for localhost, foreign hosts will return an error
4818 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4819 DWORD Level, LPBYTE pDriverInfo,
4820 DWORD driver_index,
4821 DWORD cbBuf, LPDWORD pcbNeeded,
4822 LPDWORD pcFound, DWORD data_offset)
4824 { HKEY hkeyDrivers;
4825 DWORD i, size = 0;
4826 const printenv_t * env;
4828 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4829 debugstr_w(pName), debugstr_w(pEnvironment),
4830 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4832 env = validate_envW(pEnvironment);
4833 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4835 *pcFound = 0;
4837 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4838 if(!hkeyDrivers) {
4839 ERR("Can't open Drivers key\n");
4840 return FALSE;
4843 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4844 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4845 RegCloseKey(hkeyDrivers);
4846 ERR("Can't query Drivers key\n");
4847 return FALSE;
4849 TRACE("Found %d Drivers\n", *pcFound);
4851 /* get size of single struct
4852 * unicode and ascii structure have the same size
4854 size = di_sizeof[Level];
4856 if (data_offset == 0)
4857 data_offset = size * (*pcFound);
4858 *pcbNeeded = data_offset;
4860 for( i = 0; i < *pcFound; i++) {
4861 WCHAR DriverNameW[255];
4862 PBYTE table_ptr = NULL;
4863 PBYTE data_ptr = NULL;
4864 DWORD needed = 0;
4866 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4867 != ERROR_SUCCESS) {
4868 ERR("Can't enum key number %d\n", i);
4869 RegCloseKey(hkeyDrivers);
4870 return FALSE;
4873 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4874 table_ptr = pDriverInfo + (driver_index + i) * size;
4875 if (pDriverInfo && *pcbNeeded <= cbBuf)
4876 data_ptr = pDriverInfo + *pcbNeeded;
4878 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4879 env, Level, table_ptr, data_ptr,
4880 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4881 &needed)) {
4882 RegCloseKey(hkeyDrivers);
4883 return FALSE;
4886 *pcbNeeded += needed;
4889 RegCloseKey(hkeyDrivers);
4891 if(cbBuf < *pcbNeeded){
4892 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4893 return FALSE;
4896 return TRUE;
4899 /*****************************************************************************
4900 * EnumPrinterDriversW [WINSPOOL.@]
4902 * see function EnumPrinterDrivers for RETURNS, BUGS
4904 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4905 LPBYTE pDriverInfo, DWORD cbBuf,
4906 LPDWORD pcbNeeded, LPDWORD pcReturned)
4908 static const WCHAR allW[] = {'a','l','l',0};
4909 BOOL ret;
4910 DWORD found;
4912 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4914 SetLastError(RPC_X_NULL_REF_POINTER);
4915 return FALSE;
4918 /* check for local drivers */
4919 if((pName) && (pName[0])) {
4920 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4921 SetLastError(ERROR_ACCESS_DENIED);
4922 return FALSE;
4925 /* check input parameter */
4926 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4927 SetLastError(ERROR_INVALID_LEVEL);
4928 return FALSE;
4931 if(pDriverInfo && cbBuf > 0)
4932 memset( pDriverInfo, 0, cbBuf);
4934 /* Exception: pull all printers */
4935 if (pEnvironment && !strcmpW(pEnvironment, allW))
4937 DWORD i, needed, bufsize = cbBuf;
4938 DWORD total_needed = 0;
4939 DWORD total_found = 0;
4940 DWORD data_offset;
4942 /* Precompute the overall total; we need this to know
4943 where pointers end and data begins (i.e. data_offset) */
4944 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4946 needed = found = 0;
4947 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4948 NULL, 0, 0, &needed, &found, 0);
4949 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4950 total_needed += needed;
4951 total_found += found;
4954 data_offset = di_sizeof[Level] * total_found;
4956 *pcReturned = 0;
4957 *pcbNeeded = 0;
4958 total_found = 0;
4959 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4961 needed = found = 0;
4962 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4963 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4964 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4965 else if (ret)
4966 *pcReturned += found;
4967 *pcbNeeded = needed;
4968 data_offset = needed;
4969 total_found += found;
4971 return ret;
4974 /* Normal behavior */
4975 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4976 0, cbBuf, pcbNeeded, &found, 0);
4977 if (ret)
4978 *pcReturned = found;
4980 return ret;
4983 /*****************************************************************************
4984 * EnumPrinterDriversA [WINSPOOL.@]
4986 * see function EnumPrinterDrivers for RETURNS, BUGS
4988 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4989 LPBYTE pDriverInfo, DWORD cbBuf,
4990 LPDWORD pcbNeeded, LPDWORD pcReturned)
4992 BOOL ret;
4993 UNICODE_STRING pNameW, pEnvironmentW;
4994 PWSTR pwstrNameW, pwstrEnvironmentW;
4995 LPBYTE buf = NULL;
4997 if (cbBuf)
4998 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5000 pwstrNameW = asciitounicode(&pNameW, pName);
5001 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5003 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5004 buf, cbBuf, pcbNeeded, pcReturned);
5005 if (ret)
5006 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5008 HeapFree(GetProcessHeap(), 0, buf);
5010 RtlFreeUnicodeString(&pNameW);
5011 RtlFreeUnicodeString(&pEnvironmentW);
5013 return ret;
5016 /******************************************************************************
5017 * EnumPortsA (WINSPOOL.@)
5019 * See EnumPortsW.
5022 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5023 LPDWORD pcbNeeded, LPDWORD pcReturned)
5025 BOOL res;
5026 LPBYTE bufferW = NULL;
5027 LPWSTR nameW = NULL;
5028 DWORD needed = 0;
5029 DWORD numentries = 0;
5030 INT len;
5032 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5033 cbBuf, pcbNeeded, pcReturned);
5035 /* convert servername to unicode */
5036 if (pName) {
5037 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5038 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5039 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5041 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5042 needed = cbBuf * sizeof(WCHAR);
5043 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5044 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5046 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5047 if (pcbNeeded) needed = *pcbNeeded;
5048 /* HeapReAlloc return NULL, when bufferW was NULL */
5049 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5050 HeapAlloc(GetProcessHeap(), 0, needed);
5052 /* Try again with the large Buffer */
5053 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5055 needed = pcbNeeded ? *pcbNeeded : 0;
5056 numentries = pcReturned ? *pcReturned : 0;
5059 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5060 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5062 if (res) {
5063 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5064 DWORD entrysize = 0;
5065 DWORD index;
5066 LPSTR ptr;
5067 LPPORT_INFO_2W pi2w;
5068 LPPORT_INFO_2A pi2a;
5070 needed = 0;
5071 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5073 /* First pass: calculate the size for all Entries */
5074 pi2w = (LPPORT_INFO_2W) bufferW;
5075 pi2a = (LPPORT_INFO_2A) pPorts;
5076 index = 0;
5077 while (index < numentries) {
5078 index++;
5079 needed += entrysize; /* PORT_INFO_?A */
5080 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5082 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5083 NULL, 0, NULL, NULL);
5084 if (Level > 1) {
5085 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5086 NULL, 0, NULL, NULL);
5087 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5088 NULL, 0, NULL, NULL);
5090 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5091 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5092 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5095 /* check for errors and quit on failure */
5096 if (cbBuf < needed) {
5097 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5098 res = FALSE;
5099 goto cleanup;
5101 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5102 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5103 cbBuf -= len ; /* free Bytes in the user-Buffer */
5104 pi2w = (LPPORT_INFO_2W) bufferW;
5105 pi2a = (LPPORT_INFO_2A) pPorts;
5106 index = 0;
5107 /* Second Pass: Fill the User Buffer (if we have one) */
5108 while ((index < numentries) && pPorts) {
5109 index++;
5110 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5111 pi2a->pPortName = ptr;
5112 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5113 ptr, cbBuf , NULL, NULL);
5114 ptr += len;
5115 cbBuf -= len;
5116 if (Level > 1) {
5117 pi2a->pMonitorName = ptr;
5118 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5119 ptr, cbBuf, NULL, NULL);
5120 ptr += len;
5121 cbBuf -= len;
5123 pi2a->pDescription = ptr;
5124 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5125 ptr, cbBuf, NULL, NULL);
5126 ptr += len;
5127 cbBuf -= len;
5129 pi2a->fPortType = pi2w->fPortType;
5130 pi2a->Reserved = 0; /* documented: "must be zero" */
5133 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5134 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5135 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5139 cleanup:
5140 if (pcbNeeded) *pcbNeeded = needed;
5141 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5143 HeapFree(GetProcessHeap(), 0, nameW);
5144 HeapFree(GetProcessHeap(), 0, bufferW);
5146 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5147 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5149 return (res);
5153 /******************************************************************************
5154 * EnumPortsW (WINSPOOL.@)
5156 * Enumerate available Ports
5158 * PARAMS
5159 * pName [I] Servername or NULL (local Computer)
5160 * Level [I] Structure-Level (1 or 2)
5161 * pPorts [O] PTR to Buffer that receives the Result
5162 * cbBuf [I] Size of Buffer at pPorts
5163 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5164 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5166 * RETURNS
5167 * Success: TRUE
5168 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5171 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5174 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5175 cbBuf, pcbNeeded, pcReturned);
5177 if ((backend == NULL) && !load_backend()) return FALSE;
5179 /* Level is not checked in win9x */
5180 if (!Level || (Level > 2)) {
5181 WARN("level (%d) is ignored in win9x\n", Level);
5182 SetLastError(ERROR_INVALID_LEVEL);
5183 return FALSE;
5185 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5186 SetLastError(RPC_X_NULL_REF_POINTER);
5187 return FALSE;
5190 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5193 /******************************************************************************
5194 * GetDefaultPrinterW (WINSPOOL.@)
5196 * FIXME
5197 * This function must read the value from data 'device' of key
5198 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5200 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5202 BOOL retval = TRUE;
5203 DWORD insize, len;
5204 WCHAR *buffer, *ptr;
5206 if (!namesize)
5208 SetLastError(ERROR_INVALID_PARAMETER);
5209 return FALSE;
5212 /* make the buffer big enough for the stuff from the profile/registry,
5213 * the content must fit into the local buffer to compute the correct
5214 * size even if the extern buffer is too small or not given.
5215 * (20 for ,driver,port) */
5216 insize = *namesize;
5217 len = max(100, (insize + 20));
5218 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5220 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5222 SetLastError (ERROR_FILE_NOT_FOUND);
5223 retval = FALSE;
5224 goto end;
5226 TRACE("%s\n", debugstr_w(buffer));
5228 if ((ptr = strchrW(buffer, ',')) == NULL)
5230 SetLastError(ERROR_INVALID_NAME);
5231 retval = FALSE;
5232 goto end;
5235 *ptr = 0;
5236 *namesize = strlenW(buffer) + 1;
5237 if(!name || (*namesize > insize))
5239 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5240 retval = FALSE;
5241 goto end;
5243 strcpyW(name, buffer);
5245 end:
5246 HeapFree( GetProcessHeap(), 0, buffer);
5247 return retval;
5251 /******************************************************************************
5252 * GetDefaultPrinterA (WINSPOOL.@)
5254 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5256 BOOL retval = TRUE;
5257 DWORD insize = 0;
5258 WCHAR *bufferW = NULL;
5260 if (!namesize)
5262 SetLastError(ERROR_INVALID_PARAMETER);
5263 return FALSE;
5266 if(name && *namesize) {
5267 insize = *namesize;
5268 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5271 if(!GetDefaultPrinterW( bufferW, namesize)) {
5272 retval = FALSE;
5273 goto end;
5276 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5277 NULL, NULL);
5278 if (!*namesize)
5280 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5281 retval = FALSE;
5283 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5285 end:
5286 HeapFree( GetProcessHeap(), 0, bufferW);
5287 return retval;
5291 /******************************************************************************
5292 * SetDefaultPrinterW (WINSPOOL.204)
5294 * Set the Name of the Default Printer
5296 * PARAMS
5297 * pszPrinter [I] Name of the Printer or NULL
5299 * RETURNS
5300 * Success: True
5301 * Failure: FALSE
5303 * NOTES
5304 * When the Parameter is NULL or points to an Empty String and
5305 * a Default Printer was already present, then this Function changes nothing.
5306 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5307 * the First enumerated local Printer is used.
5310 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5312 WCHAR default_printer[MAX_PATH];
5313 LPWSTR buffer = NULL;
5314 HKEY hreg;
5315 DWORD size;
5316 DWORD namelen;
5317 LONG lres;
5319 TRACE("(%s)\n", debugstr_w(pszPrinter));
5320 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5322 default_printer[0] = '\0';
5323 size = sizeof(default_printer)/sizeof(WCHAR);
5325 /* if we have a default Printer, do nothing. */
5326 if (GetDefaultPrinterW(default_printer, &size))
5327 return TRUE;
5329 pszPrinter = NULL;
5330 /* we have no default Printer: search local Printers and use the first */
5331 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5333 default_printer[0] = '\0';
5334 size = sizeof(default_printer)/sizeof(WCHAR);
5335 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5337 pszPrinter = default_printer;
5338 TRACE("using %s\n", debugstr_w(pszPrinter));
5340 RegCloseKey(hreg);
5343 if (pszPrinter == NULL) {
5344 TRACE("no local printer found\n");
5345 SetLastError(ERROR_FILE_NOT_FOUND);
5346 return FALSE;
5350 /* "pszPrinter" is never empty or NULL here. */
5351 namelen = lstrlenW(pszPrinter);
5352 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5353 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5354 if (!buffer ||
5355 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5356 HeapFree(GetProcessHeap(), 0, buffer);
5357 SetLastError(ERROR_FILE_NOT_FOUND);
5358 return FALSE;
5361 /* read the devices entry for the printer (driver,port) to build the string for the
5362 default device entry (printer,driver,port) */
5363 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5364 buffer[namelen] = ',';
5365 namelen++; /* move index to the start of the driver */
5367 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5368 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5369 if (!lres) {
5370 TRACE("set device to %s\n", debugstr_w(buffer));
5372 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5373 TRACE("failed to set the device entry: %d\n", GetLastError());
5374 lres = ERROR_INVALID_PRINTER_NAME;
5377 /* remove the next section, when INIFileMapping is implemented */
5379 HKEY hdev;
5380 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5381 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5382 RegCloseKey(hdev);
5386 else
5388 if (lres != ERROR_FILE_NOT_FOUND)
5389 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5391 SetLastError(ERROR_INVALID_PRINTER_NAME);
5394 RegCloseKey(hreg);
5395 HeapFree(GetProcessHeap(), 0, buffer);
5396 return (lres == ERROR_SUCCESS);
5399 /******************************************************************************
5400 * SetDefaultPrinterA (WINSPOOL.202)
5402 * See SetDefaultPrinterW.
5405 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5407 LPWSTR bufferW = NULL;
5408 BOOL res;
5410 TRACE("(%s)\n", debugstr_a(pszPrinter));
5411 if(pszPrinter) {
5412 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5413 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5414 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5416 res = SetDefaultPrinterW(bufferW);
5417 HeapFree(GetProcessHeap(), 0, bufferW);
5418 return res;
5421 /******************************************************************************
5422 * SetPrinterDataExA (WINSPOOL.@)
5424 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5425 LPCSTR pValueName, DWORD Type,
5426 LPBYTE pData, DWORD cbData)
5428 HKEY hkeyPrinter, hkeySubkey;
5429 DWORD ret;
5431 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5432 debugstr_a(pValueName), Type, pData, cbData);
5434 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5435 != ERROR_SUCCESS)
5436 return ret;
5438 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5439 != ERROR_SUCCESS) {
5440 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5441 RegCloseKey(hkeyPrinter);
5442 return ret;
5444 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5445 RegCloseKey(hkeySubkey);
5446 RegCloseKey(hkeyPrinter);
5447 return ret;
5450 /******************************************************************************
5451 * SetPrinterDataExW (WINSPOOL.@)
5453 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5454 LPCWSTR pValueName, DWORD Type,
5455 LPBYTE pData, DWORD cbData)
5457 HKEY hkeyPrinter, hkeySubkey;
5458 DWORD ret;
5460 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5461 debugstr_w(pValueName), Type, pData, cbData);
5463 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5464 != ERROR_SUCCESS)
5465 return ret;
5467 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5468 != ERROR_SUCCESS) {
5469 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5470 RegCloseKey(hkeyPrinter);
5471 return ret;
5473 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5474 RegCloseKey(hkeySubkey);
5475 RegCloseKey(hkeyPrinter);
5476 return ret;
5479 /******************************************************************************
5480 * SetPrinterDataA (WINSPOOL.@)
5482 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5483 LPBYTE pData, DWORD cbData)
5485 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5486 pData, cbData);
5489 /******************************************************************************
5490 * SetPrinterDataW (WINSPOOL.@)
5492 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5493 LPBYTE pData, DWORD cbData)
5495 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5496 pData, cbData);
5499 /******************************************************************************
5500 * GetPrinterDataExA (WINSPOOL.@)
5502 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5503 LPCSTR pValueName, LPDWORD pType,
5504 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5506 opened_printer_t *printer;
5507 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5508 DWORD ret;
5510 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5511 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5513 printer = get_opened_printer(hPrinter);
5514 if(!printer) return ERROR_INVALID_HANDLE;
5516 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5517 if (ret) return ret;
5519 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5521 if (printer->name) {
5523 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5524 if (ret) {
5525 RegCloseKey(hkeyPrinters);
5526 return ret;
5528 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5529 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5530 RegCloseKey(hkeyPrinter);
5531 RegCloseKey(hkeyPrinters);
5532 return ret;
5535 *pcbNeeded = nSize;
5536 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5537 0, pType, pData, pcbNeeded);
5539 if (!ret && !pData) ret = ERROR_MORE_DATA;
5541 RegCloseKey(hkeySubkey);
5542 RegCloseKey(hkeyPrinter);
5543 RegCloseKey(hkeyPrinters);
5545 TRACE("--> %d\n", ret);
5546 return ret;
5549 /******************************************************************************
5550 * GetPrinterDataExW (WINSPOOL.@)
5552 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5553 LPCWSTR pValueName, LPDWORD pType,
5554 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5556 opened_printer_t *printer;
5557 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5558 DWORD ret;
5560 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5561 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5563 printer = get_opened_printer(hPrinter);
5564 if(!printer) return ERROR_INVALID_HANDLE;
5566 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5567 if (ret) return ret;
5569 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5571 if (printer->name) {
5573 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5574 if (ret) {
5575 RegCloseKey(hkeyPrinters);
5576 return ret;
5578 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5579 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5580 RegCloseKey(hkeyPrinter);
5581 RegCloseKey(hkeyPrinters);
5582 return ret;
5585 *pcbNeeded = nSize;
5586 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5587 0, pType, pData, pcbNeeded);
5589 if (!ret && !pData) ret = ERROR_MORE_DATA;
5591 RegCloseKey(hkeySubkey);
5592 RegCloseKey(hkeyPrinter);
5593 RegCloseKey(hkeyPrinters);
5595 TRACE("--> %d\n", ret);
5596 return ret;
5599 /******************************************************************************
5600 * GetPrinterDataA (WINSPOOL.@)
5602 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5603 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5605 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5606 pData, nSize, pcbNeeded);
5609 /******************************************************************************
5610 * GetPrinterDataW (WINSPOOL.@)
5612 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5613 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5615 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5616 pData, nSize, pcbNeeded);
5619 /*******************************************************************************
5620 * EnumPrinterDataExW [WINSPOOL.@]
5622 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5623 LPBYTE pEnumValues, DWORD cbEnumValues,
5624 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5626 HKEY hkPrinter, hkSubKey;
5627 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5628 cbValueNameLen, cbMaxValueLen, cbValueLen,
5629 cbBufSize, dwType;
5630 LPWSTR lpValueName;
5631 HANDLE hHeap;
5632 PBYTE lpValue;
5633 PPRINTER_ENUM_VALUESW ppev;
5635 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5637 if (pKeyName == NULL || *pKeyName == 0)
5638 return ERROR_INVALID_PARAMETER;
5640 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5641 if (ret != ERROR_SUCCESS)
5643 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5644 hPrinter, ret);
5645 return ret;
5648 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5649 if (ret != ERROR_SUCCESS)
5651 r = RegCloseKey (hkPrinter);
5652 if (r != ERROR_SUCCESS)
5653 WARN ("RegCloseKey returned %i\n", r);
5654 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5655 debugstr_w (pKeyName), ret);
5656 return ret;
5659 ret = RegCloseKey (hkPrinter);
5660 if (ret != ERROR_SUCCESS)
5662 ERR ("RegCloseKey returned %i\n", ret);
5663 r = RegCloseKey (hkSubKey);
5664 if (r != ERROR_SUCCESS)
5665 WARN ("RegCloseKey returned %i\n", r);
5666 return ret;
5669 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5670 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5671 if (ret != ERROR_SUCCESS)
5673 r = RegCloseKey (hkSubKey);
5674 if (r != ERROR_SUCCESS)
5675 WARN ("RegCloseKey returned %i\n", r);
5676 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5677 return ret;
5680 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5681 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5683 if (cValues == 0) /* empty key */
5685 r = RegCloseKey (hkSubKey);
5686 if (r != ERROR_SUCCESS)
5687 WARN ("RegCloseKey returned %i\n", r);
5688 *pcbEnumValues = *pnEnumValues = 0;
5689 return ERROR_SUCCESS;
5692 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5694 hHeap = GetProcessHeap ();
5695 if (hHeap == NULL)
5697 ERR ("GetProcessHeap failed\n");
5698 r = RegCloseKey (hkSubKey);
5699 if (r != ERROR_SUCCESS)
5700 WARN ("RegCloseKey returned %i\n", r);
5701 return ERROR_OUTOFMEMORY;
5704 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5705 if (lpValueName == NULL)
5707 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5708 r = RegCloseKey (hkSubKey);
5709 if (r != ERROR_SUCCESS)
5710 WARN ("RegCloseKey returned %i\n", r);
5711 return ERROR_OUTOFMEMORY;
5714 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5715 if (lpValue == NULL)
5717 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5718 if (HeapFree (hHeap, 0, lpValueName) == 0)
5719 WARN ("HeapFree failed with code %i\n", GetLastError ());
5720 r = RegCloseKey (hkSubKey);
5721 if (r != ERROR_SUCCESS)
5722 WARN ("RegCloseKey returned %i\n", r);
5723 return ERROR_OUTOFMEMORY;
5726 TRACE ("pass 1: calculating buffer required for all names and values\n");
5728 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5730 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5732 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5734 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5735 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5736 NULL, NULL, lpValue, &cbValueLen);
5737 if (ret != ERROR_SUCCESS)
5739 if (HeapFree (hHeap, 0, lpValue) == 0)
5740 WARN ("HeapFree failed with code %i\n", GetLastError ());
5741 if (HeapFree (hHeap, 0, lpValueName) == 0)
5742 WARN ("HeapFree failed with code %i\n", GetLastError ());
5743 r = RegCloseKey (hkSubKey);
5744 if (r != ERROR_SUCCESS)
5745 WARN ("RegCloseKey returned %i\n", r);
5746 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5747 return ret;
5750 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5751 debugstr_w (lpValueName), dwIndex,
5752 cbValueNameLen + 1, cbValueLen);
5754 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5755 cbBufSize += cbValueLen;
5758 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5760 *pcbEnumValues = cbBufSize;
5761 *pnEnumValues = cValues;
5763 if (cbEnumValues < cbBufSize) /* buffer too small */
5765 if (HeapFree (hHeap, 0, lpValue) == 0)
5766 WARN ("HeapFree failed with code %i\n", GetLastError ());
5767 if (HeapFree (hHeap, 0, lpValueName) == 0)
5768 WARN ("HeapFree failed with code %i\n", GetLastError ());
5769 r = RegCloseKey (hkSubKey);
5770 if (r != ERROR_SUCCESS)
5771 WARN ("RegCloseKey returned %i\n", r);
5772 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5773 return ERROR_MORE_DATA;
5776 TRACE ("pass 2: copying all names and values to buffer\n");
5778 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5779 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5781 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5783 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5784 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5785 NULL, &dwType, lpValue, &cbValueLen);
5786 if (ret != ERROR_SUCCESS)
5788 if (HeapFree (hHeap, 0, lpValue) == 0)
5789 WARN ("HeapFree failed with code %i\n", GetLastError ());
5790 if (HeapFree (hHeap, 0, lpValueName) == 0)
5791 WARN ("HeapFree failed with code %i\n", GetLastError ());
5792 r = RegCloseKey (hkSubKey);
5793 if (r != ERROR_SUCCESS)
5794 WARN ("RegCloseKey returned %i\n", r);
5795 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5796 return ret;
5799 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5800 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5801 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5802 pEnumValues += cbValueNameLen;
5804 /* return # of *bytes* (including trailing \0), not # of chars */
5805 ppev[dwIndex].cbValueName = cbValueNameLen;
5807 ppev[dwIndex].dwType = dwType;
5809 memcpy (pEnumValues, lpValue, cbValueLen);
5810 ppev[dwIndex].pData = pEnumValues;
5811 pEnumValues += cbValueLen;
5813 ppev[dwIndex].cbData = cbValueLen;
5815 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5816 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5819 if (HeapFree (hHeap, 0, lpValue) == 0)
5821 ret = GetLastError ();
5822 ERR ("HeapFree failed with code %i\n", ret);
5823 if (HeapFree (hHeap, 0, lpValueName) == 0)
5824 WARN ("HeapFree failed with code %i\n", GetLastError ());
5825 r = RegCloseKey (hkSubKey);
5826 if (r != ERROR_SUCCESS)
5827 WARN ("RegCloseKey returned %i\n", r);
5828 return ret;
5831 if (HeapFree (hHeap, 0, lpValueName) == 0)
5833 ret = GetLastError ();
5834 ERR ("HeapFree failed with code %i\n", ret);
5835 r = RegCloseKey (hkSubKey);
5836 if (r != ERROR_SUCCESS)
5837 WARN ("RegCloseKey returned %i\n", r);
5838 return ret;
5841 ret = RegCloseKey (hkSubKey);
5842 if (ret != ERROR_SUCCESS)
5844 ERR ("RegCloseKey returned %i\n", ret);
5845 return ret;
5848 return ERROR_SUCCESS;
5851 /*******************************************************************************
5852 * EnumPrinterDataExA [WINSPOOL.@]
5854 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5855 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5856 * what Windows 2000 SP1 does.
5859 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5860 LPBYTE pEnumValues, DWORD cbEnumValues,
5861 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5863 INT len;
5864 LPWSTR pKeyNameW;
5865 DWORD ret, dwIndex, dwBufSize;
5866 HANDLE hHeap;
5867 LPSTR pBuffer;
5869 TRACE ("%p %s\n", hPrinter, pKeyName);
5871 if (pKeyName == NULL || *pKeyName == 0)
5872 return ERROR_INVALID_PARAMETER;
5874 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5875 if (len == 0)
5877 ret = GetLastError ();
5878 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5879 return ret;
5882 hHeap = GetProcessHeap ();
5883 if (hHeap == NULL)
5885 ERR ("GetProcessHeap failed\n");
5886 return ERROR_OUTOFMEMORY;
5889 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5890 if (pKeyNameW == NULL)
5892 ERR ("Failed to allocate %i bytes from process heap\n",
5893 (LONG)(len * sizeof (WCHAR)));
5894 return ERROR_OUTOFMEMORY;
5897 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5899 ret = GetLastError ();
5900 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5901 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5902 WARN ("HeapFree failed with code %i\n", GetLastError ());
5903 return ret;
5906 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5907 pcbEnumValues, pnEnumValues);
5908 if (ret != ERROR_SUCCESS)
5910 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5911 WARN ("HeapFree failed with code %i\n", GetLastError ());
5912 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5913 return ret;
5916 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5918 ret = GetLastError ();
5919 ERR ("HeapFree failed with code %i\n", ret);
5920 return ret;
5923 if (*pnEnumValues == 0) /* empty key */
5924 return ERROR_SUCCESS;
5926 dwBufSize = 0;
5927 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5929 PPRINTER_ENUM_VALUESW ppev =
5930 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5932 if (dwBufSize < ppev->cbValueName)
5933 dwBufSize = ppev->cbValueName;
5935 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5936 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5937 dwBufSize = ppev->cbData;
5940 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5942 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5943 if (pBuffer == NULL)
5945 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5946 return ERROR_OUTOFMEMORY;
5949 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5951 PPRINTER_ENUM_VALUESW ppev =
5952 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5954 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5955 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5956 NULL);
5957 if (len == 0)
5959 ret = GetLastError ();
5960 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5961 if (HeapFree (hHeap, 0, pBuffer) == 0)
5962 WARN ("HeapFree failed with code %i\n", GetLastError ());
5963 return ret;
5966 memcpy (ppev->pValueName, pBuffer, len);
5968 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5970 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5971 ppev->dwType != REG_MULTI_SZ)
5972 continue;
5974 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5975 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5976 if (len == 0)
5978 ret = GetLastError ();
5979 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5980 if (HeapFree (hHeap, 0, pBuffer) == 0)
5981 WARN ("HeapFree failed with code %i\n", GetLastError ());
5982 return ret;
5985 memcpy (ppev->pData, pBuffer, len);
5987 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5988 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5991 if (HeapFree (hHeap, 0, pBuffer) == 0)
5993 ret = GetLastError ();
5994 ERR ("HeapFree failed with code %i\n", ret);
5995 return ret;
5998 return ERROR_SUCCESS;
6001 /******************************************************************************
6002 * AbortPrinter (WINSPOOL.@)
6004 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6006 FIXME("(%p), stub!\n", hPrinter);
6007 return TRUE;
6010 /******************************************************************************
6011 * AddPortA (WINSPOOL.@)
6013 * See AddPortW.
6016 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6018 LPWSTR nameW = NULL;
6019 LPWSTR monitorW = NULL;
6020 DWORD len;
6021 BOOL res;
6023 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6025 if (pName) {
6026 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6027 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6028 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6031 if (pMonitorName) {
6032 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6033 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6034 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6036 res = AddPortW(nameW, hWnd, monitorW);
6037 HeapFree(GetProcessHeap(), 0, nameW);
6038 HeapFree(GetProcessHeap(), 0, monitorW);
6039 return res;
6042 /******************************************************************************
6043 * AddPortW (WINSPOOL.@)
6045 * Add a Port for a specific Monitor
6047 * PARAMS
6048 * pName [I] Servername or NULL (local Computer)
6049 * hWnd [I] Handle to parent Window for the Dialog-Box
6050 * pMonitorName [I] Name of the Monitor that manage the Port
6052 * RETURNS
6053 * Success: TRUE
6054 * Failure: FALSE
6057 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6059 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6061 if ((backend == NULL) && !load_backend()) return FALSE;
6063 if (!pMonitorName) {
6064 SetLastError(RPC_X_NULL_REF_POINTER);
6065 return FALSE;
6068 return backend->fpAddPort(pName, hWnd, pMonitorName);
6071 /******************************************************************************
6072 * AddPortExA (WINSPOOL.@)
6074 * See AddPortExW.
6077 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6079 PORT_INFO_2W pi2W;
6080 PORT_INFO_2A * pi2A;
6081 LPWSTR nameW = NULL;
6082 LPWSTR monitorW = NULL;
6083 DWORD len;
6084 BOOL res;
6086 pi2A = (PORT_INFO_2A *) pBuffer;
6088 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6089 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6091 if ((level < 1) || (level > 2)) {
6092 SetLastError(ERROR_INVALID_LEVEL);
6093 return FALSE;
6096 if (!pi2A) {
6097 SetLastError(ERROR_INVALID_PARAMETER);
6098 return FALSE;
6101 if (pName) {
6102 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6103 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6104 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6107 if (pMonitorName) {
6108 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6109 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6110 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6113 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6115 if (pi2A->pPortName) {
6116 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6117 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6118 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6121 if (level > 1) {
6122 if (pi2A->pMonitorName) {
6123 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6124 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6125 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6128 if (pi2A->pDescription) {
6129 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6130 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6131 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6133 pi2W.fPortType = pi2A->fPortType;
6134 pi2W.Reserved = pi2A->Reserved;
6137 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6139 HeapFree(GetProcessHeap(), 0, nameW);
6140 HeapFree(GetProcessHeap(), 0, monitorW);
6141 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6142 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6143 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6144 return res;
6148 /******************************************************************************
6149 * AddPortExW (WINSPOOL.@)
6151 * Add a Port for a specific Monitor, without presenting a user interface
6153 * PARAMS
6154 * pName [I] Servername or NULL (local Computer)
6155 * level [I] Structure-Level (1 or 2) for pBuffer
6156 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6157 * pMonitorName [I] Name of the Monitor that manage the Port
6159 * RETURNS
6160 * Success: TRUE
6161 * Failure: FALSE
6164 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6166 PORT_INFO_2W * pi2;
6168 pi2 = (PORT_INFO_2W *) pBuffer;
6170 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6171 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6172 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6173 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6175 if ((backend == NULL) && !load_backend()) return FALSE;
6177 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6178 SetLastError(ERROR_INVALID_PARAMETER);
6179 return FALSE;
6182 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6185 /******************************************************************************
6186 * AddPrinterConnectionA (WINSPOOL.@)
6188 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6190 FIXME("%s\n", debugstr_a(pName));
6191 return FALSE;
6194 /******************************************************************************
6195 * AddPrinterConnectionW (WINSPOOL.@)
6197 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6199 FIXME("%s\n", debugstr_w(pName));
6200 return FALSE;
6203 /******************************************************************************
6204 * AddPrinterDriverExW (WINSPOOL.@)
6206 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6208 * PARAMS
6209 * pName [I] Servername or NULL (local Computer)
6210 * level [I] Level for the supplied DRIVER_INFO_*W struct
6211 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6212 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6214 * RESULTS
6215 * Success: TRUE
6216 * Failure: FALSE
6219 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6221 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6223 if ((backend == NULL) && !load_backend()) return FALSE;
6225 if (level < 2 || level == 5 || level == 7 || level > 8) {
6226 SetLastError(ERROR_INVALID_LEVEL);
6227 return FALSE;
6230 if (!pDriverInfo) {
6231 SetLastError(ERROR_INVALID_PARAMETER);
6232 return FALSE;
6235 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6238 /******************************************************************************
6239 * AddPrinterDriverExA (WINSPOOL.@)
6241 * See AddPrinterDriverExW.
6244 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6246 DRIVER_INFO_8A *diA;
6247 DRIVER_INFO_8W diW;
6248 LPWSTR nameW = NULL;
6249 DWORD lenA;
6250 DWORD len;
6251 DWORD res = FALSE;
6253 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6255 diA = (DRIVER_INFO_8A *) pDriverInfo;
6256 ZeroMemory(&diW, sizeof(diW));
6258 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6259 SetLastError(ERROR_INVALID_LEVEL);
6260 return FALSE;
6263 if (diA == NULL) {
6264 SetLastError(ERROR_INVALID_PARAMETER);
6265 return FALSE;
6268 /* convert servername to unicode */
6269 if (pName) {
6270 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6271 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6272 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6275 /* common fields */
6276 diW.cVersion = diA->cVersion;
6278 if (diA->pName) {
6279 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6280 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6281 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6284 if (diA->pEnvironment) {
6285 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6286 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6287 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6290 if (diA->pDriverPath) {
6291 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6292 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6293 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6296 if (diA->pDataFile) {
6297 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6298 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6299 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6302 if (diA->pConfigFile) {
6303 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6304 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6305 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6308 if ((Level > 2) && diA->pDependentFiles) {
6309 lenA = multi_sz_lenA(diA->pDependentFiles);
6310 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6311 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6312 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6315 if ((Level > 2) && diA->pMonitorName) {
6316 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6317 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6318 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6321 if ((Level > 3) && diA->pDefaultDataType) {
6322 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6323 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6324 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6327 if ((Level > 3) && diA->pszzPreviousNames) {
6328 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6329 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6330 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6331 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6334 if ((Level > 5) && diA->pszMfgName) {
6335 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6336 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6337 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6340 if ((Level > 5) && diA->pszOEMUrl) {
6341 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6342 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6343 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6346 if ((Level > 5) && diA->pszHardwareID) {
6347 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6348 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6349 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6352 if ((Level > 5) && diA->pszProvider) {
6353 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6354 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6355 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6358 if (Level > 7) {
6359 FIXME("level %u is incomplete\n", Level);
6362 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6363 TRACE("got %u with %u\n", res, GetLastError());
6364 HeapFree(GetProcessHeap(), 0, nameW);
6365 HeapFree(GetProcessHeap(), 0, diW.pName);
6366 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6367 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6368 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6369 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6370 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6371 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6372 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6373 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6374 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6375 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6376 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6377 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6379 TRACE("=> %u with %u\n", res, GetLastError());
6380 return res;
6383 /******************************************************************************
6384 * ConfigurePortA (WINSPOOL.@)
6386 * See ConfigurePortW.
6389 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6391 LPWSTR nameW = NULL;
6392 LPWSTR portW = NULL;
6393 INT len;
6394 DWORD res;
6396 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6398 /* convert servername to unicode */
6399 if (pName) {
6400 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6401 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6402 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6405 /* convert portname to unicode */
6406 if (pPortName) {
6407 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6408 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6409 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6412 res = ConfigurePortW(nameW, hWnd, portW);
6413 HeapFree(GetProcessHeap(), 0, nameW);
6414 HeapFree(GetProcessHeap(), 0, portW);
6415 return res;
6418 /******************************************************************************
6419 * ConfigurePortW (WINSPOOL.@)
6421 * Display the Configuration-Dialog for a specific Port
6423 * PARAMS
6424 * pName [I] Servername or NULL (local Computer)
6425 * hWnd [I] Handle to parent Window for the Dialog-Box
6426 * pPortName [I] Name of the Port, that should be configured
6428 * RETURNS
6429 * Success: TRUE
6430 * Failure: FALSE
6433 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6436 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6438 if ((backend == NULL) && !load_backend()) return FALSE;
6440 if (!pPortName) {
6441 SetLastError(RPC_X_NULL_REF_POINTER);
6442 return FALSE;
6445 return backend->fpConfigurePort(pName, hWnd, pPortName);
6448 /******************************************************************************
6449 * ConnectToPrinterDlg (WINSPOOL.@)
6451 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6453 FIXME("%p %x\n", hWnd, Flags);
6454 return NULL;
6457 /******************************************************************************
6458 * DeletePrinterConnectionA (WINSPOOL.@)
6460 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6462 FIXME("%s\n", debugstr_a(pName));
6463 return TRUE;
6466 /******************************************************************************
6467 * DeletePrinterConnectionW (WINSPOOL.@)
6469 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6471 FIXME("%s\n", debugstr_w(pName));
6472 return TRUE;
6475 /******************************************************************************
6476 * DeletePrinterDriverExW (WINSPOOL.@)
6478 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6479 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6481 HKEY hkey_drivers;
6482 BOOL ret = FALSE;
6484 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6485 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6487 if(pName && pName[0])
6489 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6490 SetLastError(ERROR_INVALID_PARAMETER);
6491 return FALSE;
6494 if(dwDeleteFlag)
6496 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6497 SetLastError(ERROR_INVALID_PARAMETER);
6498 return FALSE;
6501 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6503 if(!hkey_drivers)
6505 ERR("Can't open drivers key\n");
6506 return FALSE;
6509 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6510 ret = TRUE;
6512 RegCloseKey(hkey_drivers);
6514 return ret;
6517 /******************************************************************************
6518 * DeletePrinterDriverExA (WINSPOOL.@)
6520 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6521 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6523 UNICODE_STRING NameW, EnvW, DriverW;
6524 BOOL ret;
6526 asciitounicode(&NameW, pName);
6527 asciitounicode(&EnvW, pEnvironment);
6528 asciitounicode(&DriverW, pDriverName);
6530 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6532 RtlFreeUnicodeString(&DriverW);
6533 RtlFreeUnicodeString(&EnvW);
6534 RtlFreeUnicodeString(&NameW);
6536 return ret;
6539 /******************************************************************************
6540 * DeletePrinterDataExW (WINSPOOL.@)
6542 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6543 LPCWSTR pValueName)
6545 FIXME("%p %s %s\n", hPrinter,
6546 debugstr_w(pKeyName), debugstr_w(pValueName));
6547 return ERROR_INVALID_PARAMETER;
6550 /******************************************************************************
6551 * DeletePrinterDataExA (WINSPOOL.@)
6553 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6554 LPCSTR pValueName)
6556 FIXME("%p %s %s\n", hPrinter,
6557 debugstr_a(pKeyName), debugstr_a(pValueName));
6558 return ERROR_INVALID_PARAMETER;
6561 /******************************************************************************
6562 * DeletePrintProcessorA (WINSPOOL.@)
6564 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6566 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6567 debugstr_a(pPrintProcessorName));
6568 return TRUE;
6571 /******************************************************************************
6572 * DeletePrintProcessorW (WINSPOOL.@)
6574 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6576 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6577 debugstr_w(pPrintProcessorName));
6578 return TRUE;
6581 /******************************************************************************
6582 * DeletePrintProvidorA (WINSPOOL.@)
6584 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6586 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6587 debugstr_a(pPrintProviderName));
6588 return TRUE;
6591 /******************************************************************************
6592 * DeletePrintProvidorW (WINSPOOL.@)
6594 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6596 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6597 debugstr_w(pPrintProviderName));
6598 return TRUE;
6601 /******************************************************************************
6602 * EnumFormsA (WINSPOOL.@)
6604 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6605 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6607 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6608 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6609 return FALSE;
6612 /******************************************************************************
6613 * EnumFormsW (WINSPOOL.@)
6615 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6616 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6618 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6619 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6620 return FALSE;
6623 /*****************************************************************************
6624 * EnumMonitorsA [WINSPOOL.@]
6626 * See EnumMonitorsW.
6629 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6630 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6632 BOOL res;
6633 LPBYTE bufferW = NULL;
6634 LPWSTR nameW = NULL;
6635 DWORD needed = 0;
6636 DWORD numentries = 0;
6637 INT len;
6639 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6640 cbBuf, pcbNeeded, pcReturned);
6642 /* convert servername to unicode */
6643 if (pName) {
6644 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6645 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6646 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6648 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6649 needed = cbBuf * sizeof(WCHAR);
6650 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6651 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6653 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6654 if (pcbNeeded) needed = *pcbNeeded;
6655 /* HeapReAlloc return NULL, when bufferW was NULL */
6656 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6657 HeapAlloc(GetProcessHeap(), 0, needed);
6659 /* Try again with the large Buffer */
6660 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6662 numentries = pcReturned ? *pcReturned : 0;
6663 needed = 0;
6665 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6666 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6668 if (res) {
6669 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6670 DWORD entrysize = 0;
6671 DWORD index;
6672 LPSTR ptr;
6673 LPMONITOR_INFO_2W mi2w;
6674 LPMONITOR_INFO_2A mi2a;
6676 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6677 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6679 /* First pass: calculate the size for all Entries */
6680 mi2w = (LPMONITOR_INFO_2W) bufferW;
6681 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6682 index = 0;
6683 while (index < numentries) {
6684 index++;
6685 needed += entrysize; /* MONITOR_INFO_?A */
6686 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6688 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6689 NULL, 0, NULL, NULL);
6690 if (Level > 1) {
6691 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6692 NULL, 0, NULL, NULL);
6693 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6694 NULL, 0, NULL, NULL);
6696 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6697 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6698 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6701 /* check for errors and quit on failure */
6702 if (cbBuf < needed) {
6703 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6704 res = FALSE;
6705 goto emA_cleanup;
6707 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6708 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6709 cbBuf -= len ; /* free Bytes in the user-Buffer */
6710 mi2w = (LPMONITOR_INFO_2W) bufferW;
6711 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6712 index = 0;
6713 /* Second Pass: Fill the User Buffer (if we have one) */
6714 while ((index < numentries) && pMonitors) {
6715 index++;
6716 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6717 mi2a->pName = ptr;
6718 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6719 ptr, cbBuf , NULL, NULL);
6720 ptr += len;
6721 cbBuf -= len;
6722 if (Level > 1) {
6723 mi2a->pEnvironment = ptr;
6724 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6725 ptr, cbBuf, NULL, NULL);
6726 ptr += len;
6727 cbBuf -= len;
6729 mi2a->pDLLName = ptr;
6730 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6731 ptr, cbBuf, NULL, NULL);
6732 ptr += len;
6733 cbBuf -= len;
6735 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6736 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6737 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6740 emA_cleanup:
6741 if (pcbNeeded) *pcbNeeded = needed;
6742 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6744 HeapFree(GetProcessHeap(), 0, nameW);
6745 HeapFree(GetProcessHeap(), 0, bufferW);
6747 TRACE("returning %d with %d (%d byte for %d entries)\n",
6748 (res), GetLastError(), needed, numentries);
6750 return (res);
6754 /*****************************************************************************
6755 * EnumMonitorsW [WINSPOOL.@]
6757 * Enumerate available Port-Monitors
6759 * PARAMS
6760 * pName [I] Servername or NULL (local Computer)
6761 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6762 * pMonitors [O] PTR to Buffer that receives the Result
6763 * cbBuf [I] Size of Buffer at pMonitors
6764 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6765 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6767 * RETURNS
6768 * Success: TRUE
6769 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6772 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6773 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6776 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6777 cbBuf, pcbNeeded, pcReturned);
6779 if ((backend == NULL) && !load_backend()) return FALSE;
6781 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6782 SetLastError(RPC_X_NULL_REF_POINTER);
6783 return FALSE;
6786 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6789 /******************************************************************************
6790 * SpoolerInit (WINSPOOL.@)
6792 * Initialize the Spooler
6794 * RETURNS
6795 * Success: TRUE
6796 * Failure: FALSE
6798 * NOTES
6799 * The function fails on windows, when the spooler service is not running
6802 BOOL WINAPI SpoolerInit(void)
6805 if ((backend == NULL) && !load_backend()) return FALSE;
6806 return TRUE;
6809 /******************************************************************************
6810 * XcvDataW (WINSPOOL.@)
6812 * Execute commands in the Printmonitor DLL
6814 * PARAMS
6815 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6816 * pszDataName [i] Name of the command to execute
6817 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6818 * cbInputData [i] Size in Bytes of Buffer at pInputData
6819 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6820 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6821 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6822 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6824 * RETURNS
6825 * Success: TRUE
6826 * Failure: FALSE
6828 * NOTES
6829 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6830 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6832 * Minimal List of commands, that a Printmonitor DLL should support:
6834 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6835 *| "AddPort" : Add a Port
6836 *| "DeletePort": Delete a Port
6838 * Many Printmonitors support additional commands. Examples for localspl.dll:
6839 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6840 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6843 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6844 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6845 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6847 opened_printer_t *printer;
6849 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6850 pInputData, cbInputData, pOutputData,
6851 cbOutputData, pcbOutputNeeded, pdwStatus);
6853 if ((backend == NULL) && !load_backend()) return FALSE;
6855 printer = get_opened_printer(hXcv);
6856 if (!printer || (!printer->backend_printer)) {
6857 SetLastError(ERROR_INVALID_HANDLE);
6858 return FALSE;
6861 if (!pcbOutputNeeded) {
6862 SetLastError(ERROR_INVALID_PARAMETER);
6863 return FALSE;
6866 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6867 SetLastError(RPC_X_NULL_REF_POINTER);
6868 return FALSE;
6871 *pcbOutputNeeded = 0;
6873 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6874 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6878 /*****************************************************************************
6879 * EnumPrinterDataA [WINSPOOL.@]
6882 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6883 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6884 DWORD cbData, LPDWORD pcbData )
6886 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6887 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6888 return ERROR_NO_MORE_ITEMS;
6891 /*****************************************************************************
6892 * EnumPrinterDataW [WINSPOOL.@]
6895 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6896 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6897 DWORD cbData, LPDWORD pcbData )
6899 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6900 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6901 return ERROR_NO_MORE_ITEMS;
6904 /*****************************************************************************
6905 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6908 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6909 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6910 LPDWORD pcbNeeded, LPDWORD pcReturned)
6912 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6913 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6914 pcbNeeded, pcReturned);
6915 return FALSE;
6918 /*****************************************************************************
6919 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6922 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6923 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6924 LPDWORD pcbNeeded, LPDWORD pcReturned)
6926 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6927 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6928 pcbNeeded, pcReturned);
6929 return FALSE;
6932 /*****************************************************************************
6933 * EnumPrintProcessorsA [WINSPOOL.@]
6935 * See EnumPrintProcessorsW.
6938 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6939 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6941 BOOL res;
6942 LPBYTE bufferW = NULL;
6943 LPWSTR nameW = NULL;
6944 LPWSTR envW = NULL;
6945 DWORD needed = 0;
6946 DWORD numentries = 0;
6947 INT len;
6949 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6950 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6952 /* convert names to unicode */
6953 if (pName) {
6954 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6955 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6956 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6958 if (pEnvironment) {
6959 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6960 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6961 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6964 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6965 needed = cbBuf * sizeof(WCHAR);
6966 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6967 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6969 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6970 if (pcbNeeded) needed = *pcbNeeded;
6971 /* HeapReAlloc return NULL, when bufferW was NULL */
6972 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6973 HeapAlloc(GetProcessHeap(), 0, needed);
6975 /* Try again with the large Buffer */
6976 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6978 numentries = pcReturned ? *pcReturned : 0;
6979 needed = 0;
6981 if (res) {
6982 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6983 DWORD index;
6984 LPSTR ptr;
6985 PPRINTPROCESSOR_INFO_1W ppiw;
6986 PPRINTPROCESSOR_INFO_1A ppia;
6988 /* First pass: calculate the size for all Entries */
6989 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6990 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6991 index = 0;
6992 while (index < numentries) {
6993 index++;
6994 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6995 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6997 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6998 NULL, 0, NULL, NULL);
7000 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7001 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7004 /* check for errors and quit on failure */
7005 if (cbBuf < needed) {
7006 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7007 res = FALSE;
7008 goto epp_cleanup;
7011 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7012 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7013 cbBuf -= len ; /* free Bytes in the user-Buffer */
7014 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7015 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7016 index = 0;
7017 /* Second Pass: Fill the User Buffer (if we have one) */
7018 while ((index < numentries) && pPPInfo) {
7019 index++;
7020 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7021 ppia->pName = ptr;
7022 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7023 ptr, cbBuf , NULL, NULL);
7024 ptr += len;
7025 cbBuf -= len;
7027 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7028 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7032 epp_cleanup:
7033 if (pcbNeeded) *pcbNeeded = needed;
7034 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7036 HeapFree(GetProcessHeap(), 0, nameW);
7037 HeapFree(GetProcessHeap(), 0, envW);
7038 HeapFree(GetProcessHeap(), 0, bufferW);
7040 TRACE("returning %d with %d (%d byte for %d entries)\n",
7041 (res), GetLastError(), needed, numentries);
7043 return (res);
7046 /*****************************************************************************
7047 * EnumPrintProcessorsW [WINSPOOL.@]
7049 * Enumerate available Print Processors
7051 * PARAMS
7052 * pName [I] Servername or NULL (local Computer)
7053 * pEnvironment [I] Printing-Environment or NULL (Default)
7054 * Level [I] Structure-Level (Only 1 is allowed)
7055 * pPPInfo [O] PTR to Buffer that receives the Result
7056 * cbBuf [I] Size of Buffer at pPPInfo
7057 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7058 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7060 * RETURNS
7061 * Success: TRUE
7062 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7065 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7066 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7069 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7070 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7072 if ((backend == NULL) && !load_backend()) return FALSE;
7074 if (!pcbNeeded || !pcReturned) {
7075 SetLastError(RPC_X_NULL_REF_POINTER);
7076 return FALSE;
7079 if (!pPPInfo && (cbBuf > 0)) {
7080 SetLastError(ERROR_INVALID_USER_BUFFER);
7081 return FALSE;
7084 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7085 cbBuf, pcbNeeded, pcReturned);
7088 /*****************************************************************************
7089 * ExtDeviceMode [WINSPOOL.@]
7092 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7093 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7094 DWORD fMode)
7096 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7097 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7098 debugstr_a(pProfile), fMode);
7099 return -1;
7102 /*****************************************************************************
7103 * FindClosePrinterChangeNotification [WINSPOOL.@]
7106 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7108 FIXME("Stub: %p\n", hChange);
7109 return TRUE;
7112 /*****************************************************************************
7113 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7116 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7117 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7119 FIXME("Stub: %p %x %x %p\n",
7120 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7121 return INVALID_HANDLE_VALUE;
7124 /*****************************************************************************
7125 * FindNextPrinterChangeNotification [WINSPOOL.@]
7128 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7129 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7131 FIXME("Stub: %p %p %p %p\n",
7132 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7133 return FALSE;
7136 /*****************************************************************************
7137 * FreePrinterNotifyInfo [WINSPOOL.@]
7140 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7142 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7143 return TRUE;
7146 /*****************************************************************************
7147 * string_to_buf
7149 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7150 * ansi depending on the unicode parameter.
7152 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7154 if(!str)
7156 *size = 0;
7157 return TRUE;
7160 if(unicode)
7162 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7163 if(*size <= cb)
7165 memcpy(ptr, str, *size);
7166 return TRUE;
7168 return FALSE;
7170 else
7172 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7173 if(*size <= cb)
7175 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7176 return TRUE;
7178 return FALSE;
7182 /*****************************************************************************
7183 * get_job_info_1
7185 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7186 LPDWORD pcbNeeded, BOOL unicode)
7188 DWORD size, left = cbBuf;
7189 BOOL space = (cbBuf > 0);
7190 LPBYTE ptr = buf;
7192 *pcbNeeded = 0;
7194 if(space)
7196 ji1->JobId = job->job_id;
7199 string_to_buf(job->document_title, ptr, left, &size, unicode);
7200 if(space && size <= left)
7202 ji1->pDocument = (LPWSTR)ptr;
7203 ptr += size;
7204 left -= size;
7206 else
7207 space = FALSE;
7208 *pcbNeeded += size;
7210 if (job->printer_name)
7212 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7213 if(space && size <= left)
7215 ji1->pPrinterName = (LPWSTR)ptr;
7216 ptr += size;
7217 left -= size;
7219 else
7220 space = FALSE;
7221 *pcbNeeded += size;
7224 return space;
7227 /*****************************************************************************
7228 * get_job_info_2
7230 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7231 LPDWORD pcbNeeded, BOOL unicode)
7233 DWORD size, left = cbBuf;
7234 DWORD shift;
7235 BOOL space = (cbBuf > 0);
7236 LPBYTE ptr = buf;
7237 LPDEVMODEA dmA = NULL;
7238 LPDEVMODEW devmode;
7240 *pcbNeeded = 0;
7242 if(space)
7244 ji2->JobId = job->job_id;
7247 string_to_buf(job->document_title, ptr, left, &size, unicode);
7248 if(space && size <= left)
7250 ji2->pDocument = (LPWSTR)ptr;
7251 ptr += size;
7252 left -= size;
7254 else
7255 space = FALSE;
7256 *pcbNeeded += size;
7258 if (job->printer_name)
7260 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7261 if(space && size <= left)
7263 ji2->pPrinterName = (LPWSTR)ptr;
7264 ptr += size;
7265 left -= size;
7267 else
7268 space = FALSE;
7269 *pcbNeeded += size;
7272 if (job->devmode)
7274 if (!unicode)
7276 dmA = DEVMODEdupWtoA(job->devmode);
7277 devmode = (LPDEVMODEW) dmA;
7278 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7280 else
7282 devmode = job->devmode;
7283 size = devmode->dmSize + devmode->dmDriverExtra;
7286 if (!devmode)
7287 FIXME("Can't convert DEVMODE W to A\n");
7288 else
7290 /* align DEVMODE to a DWORD boundary */
7291 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7292 size += shift;
7294 if (size <= left)
7296 ptr += shift;
7297 memcpy(ptr, devmode, size-shift);
7298 ji2->pDevMode = (LPDEVMODEW)ptr;
7299 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7300 ptr += size;
7301 left -= size;
7303 else
7304 space = FALSE;
7305 *pcbNeeded +=size;
7309 return space;
7312 /*****************************************************************************
7313 * get_job_info
7315 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7316 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7318 BOOL ret = FALSE;
7319 DWORD needed = 0, size;
7320 job_t *job;
7321 LPBYTE ptr = pJob;
7323 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7325 EnterCriticalSection(&printer_handles_cs);
7326 job = get_job(hPrinter, JobId);
7327 if(!job)
7328 goto end;
7330 switch(Level)
7332 case 1:
7333 size = sizeof(JOB_INFO_1W);
7334 if(cbBuf >= size)
7336 cbBuf -= size;
7337 ptr += size;
7338 memset(pJob, 0, size);
7340 else
7341 cbBuf = 0;
7342 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7343 needed += size;
7344 break;
7346 case 2:
7347 size = sizeof(JOB_INFO_2W);
7348 if(cbBuf >= size)
7350 cbBuf -= size;
7351 ptr += size;
7352 memset(pJob, 0, size);
7354 else
7355 cbBuf = 0;
7356 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7357 needed += size;
7358 break;
7360 case 3:
7361 size = sizeof(JOB_INFO_3);
7362 if(cbBuf >= size)
7364 cbBuf -= size;
7365 memset(pJob, 0, size);
7366 ret = TRUE;
7368 else
7369 cbBuf = 0;
7370 needed = size;
7371 break;
7373 default:
7374 SetLastError(ERROR_INVALID_LEVEL);
7375 goto end;
7377 if(pcbNeeded)
7378 *pcbNeeded = needed;
7379 end:
7380 LeaveCriticalSection(&printer_handles_cs);
7381 return ret;
7384 /*****************************************************************************
7385 * GetJobA [WINSPOOL.@]
7388 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7389 DWORD cbBuf, LPDWORD pcbNeeded)
7391 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7394 /*****************************************************************************
7395 * GetJobW [WINSPOOL.@]
7398 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7399 DWORD cbBuf, LPDWORD pcbNeeded)
7401 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7404 /*****************************************************************************
7405 * schedule_pipe
7407 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7409 #ifdef HAVE_FORK
7410 char *unixname, *cmdA;
7411 DWORD len;
7412 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7413 BOOL ret = FALSE;
7414 char buf[1024];
7415 pid_t pid, wret;
7416 int status;
7418 if(!(unixname = wine_get_unix_file_name(filename)))
7419 return FALSE;
7421 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7422 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7423 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7425 TRACE("printing with: %s\n", cmdA);
7427 if((file_fd = open(unixname, O_RDONLY)) == -1)
7428 goto end;
7430 if (pipe(fds))
7432 ERR("pipe() failed!\n");
7433 goto end;
7436 if ((pid = fork()) == 0)
7438 close(0);
7439 dup2(fds[0], 0);
7440 close(fds[1]);
7442 /* reset signals that we previously set to SIG_IGN */
7443 signal(SIGPIPE, SIG_DFL);
7445 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7446 _exit(1);
7448 else if (pid == -1)
7450 ERR("fork() failed!\n");
7451 goto end;
7454 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7455 write(fds[1], buf, no_read);
7457 close(fds[1]);
7458 fds[1] = -1;
7460 /* reap child */
7461 do {
7462 wret = waitpid(pid, &status, 0);
7463 } while (wret < 0 && errno == EINTR);
7464 if (wret < 0)
7466 ERR("waitpid() failed!\n");
7467 goto end;
7469 if (!WIFEXITED(status) || WEXITSTATUS(status))
7471 ERR("child process failed! %d\n", status);
7472 goto end;
7475 ret = TRUE;
7477 end:
7478 if(file_fd != -1) close(file_fd);
7479 if(fds[0] != -1) close(fds[0]);
7480 if(fds[1] != -1) close(fds[1]);
7482 HeapFree(GetProcessHeap(), 0, cmdA);
7483 HeapFree(GetProcessHeap(), 0, unixname);
7484 return ret;
7485 #else
7486 return FALSE;
7487 #endif
7490 /*****************************************************************************
7491 * schedule_lpr
7493 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7495 WCHAR *cmd;
7496 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7497 BOOL r;
7499 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7500 sprintfW(cmd, fmtW, printer_name);
7502 r = schedule_pipe(cmd, filename);
7504 HeapFree(GetProcessHeap(), 0, cmd);
7505 return r;
7508 /*****************************************************************************
7509 * schedule_cups
7511 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7513 #ifdef SONAME_LIBCUPS
7514 if(pcupsPrintFile)
7516 char *unixname, *queue, *unix_doc_title;
7517 DWORD len;
7518 BOOL ret;
7520 if(!(unixname = wine_get_unix_file_name(filename)))
7521 return FALSE;
7523 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7524 queue = HeapAlloc(GetProcessHeap(), 0, len);
7525 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7527 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7528 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7529 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7531 TRACE("printing via cups\n");
7532 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7533 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7534 HeapFree(GetProcessHeap(), 0, queue);
7535 HeapFree(GetProcessHeap(), 0, unixname);
7536 return ret;
7538 else
7539 #endif
7541 return schedule_lpr(printer_name, filename);
7545 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7547 LPWSTR filename;
7549 switch(msg)
7551 case WM_INITDIALOG:
7552 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7553 return TRUE;
7555 case WM_COMMAND:
7556 if(HIWORD(wparam) == BN_CLICKED)
7558 if(LOWORD(wparam) == IDOK)
7560 HANDLE hf;
7561 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7562 LPWSTR *output;
7564 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7565 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7567 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7569 WCHAR caption[200], message[200];
7570 int mb_ret;
7572 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7573 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7574 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7575 if(mb_ret == IDCANCEL)
7577 HeapFree(GetProcessHeap(), 0, filename);
7578 return TRUE;
7581 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7582 if(hf == INVALID_HANDLE_VALUE)
7584 WCHAR caption[200], message[200];
7586 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7587 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7588 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7589 HeapFree(GetProcessHeap(), 0, filename);
7590 return TRUE;
7592 CloseHandle(hf);
7593 DeleteFileW(filename);
7594 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7595 *output = filename;
7596 EndDialog(hwnd, IDOK);
7597 return TRUE;
7599 if(LOWORD(wparam) == IDCANCEL)
7601 EndDialog(hwnd, IDCANCEL);
7602 return TRUE;
7605 return FALSE;
7607 return FALSE;
7610 /*****************************************************************************
7611 * get_filename
7613 static BOOL get_filename(LPWSTR *filename)
7615 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7616 file_dlg_proc, (LPARAM)filename) == IDOK;
7619 /*****************************************************************************
7620 * schedule_file
7622 static BOOL schedule_file(LPCWSTR filename)
7624 LPWSTR output = NULL;
7626 if(get_filename(&output))
7628 BOOL r;
7629 TRACE("copy to %s\n", debugstr_w(output));
7630 r = CopyFileW(filename, output, FALSE);
7631 HeapFree(GetProcessHeap(), 0, output);
7632 return r;
7634 return FALSE;
7637 /*****************************************************************************
7638 * schedule_unixfile
7640 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7642 int in_fd, out_fd, no_read;
7643 char buf[1024];
7644 BOOL ret = FALSE;
7645 char *unixname, *outputA;
7646 DWORD len;
7648 if(!(unixname = wine_get_unix_file_name(filename)))
7649 return FALSE;
7651 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7652 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7653 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7655 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7656 in_fd = open(unixname, O_RDONLY);
7657 if(out_fd == -1 || in_fd == -1)
7658 goto end;
7660 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7661 write(out_fd, buf, no_read);
7663 ret = TRUE;
7664 end:
7665 if(in_fd != -1) close(in_fd);
7666 if(out_fd != -1) close(out_fd);
7667 HeapFree(GetProcessHeap(), 0, outputA);
7668 HeapFree(GetProcessHeap(), 0, unixname);
7669 return ret;
7672 /*****************************************************************************
7673 * ScheduleJob [WINSPOOL.@]
7676 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7678 opened_printer_t *printer;
7679 BOOL ret = FALSE;
7680 struct list *cursor, *cursor2;
7682 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7683 EnterCriticalSection(&printer_handles_cs);
7684 printer = get_opened_printer(hPrinter);
7685 if(!printer)
7686 goto end;
7688 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7690 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7691 HANDLE hf;
7693 if(job->job_id != dwJobID) continue;
7695 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7696 if(hf != INVALID_HANDLE_VALUE)
7698 PRINTER_INFO_5W *pi5 = NULL;
7699 LPWSTR portname = job->portname;
7700 DWORD needed;
7701 HKEY hkey;
7702 WCHAR output[1024];
7703 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7704 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7706 if (!portname)
7708 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7709 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7710 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7711 portname = pi5->pPortName;
7713 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7714 debugstr_w(portname));
7716 output[0] = 0;
7718 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7719 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7721 DWORD type, count = sizeof(output);
7722 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7723 RegCloseKey(hkey);
7725 if(output[0] == '|')
7727 ret = schedule_pipe(output + 1, job->filename);
7729 else if(output[0])
7731 ret = schedule_unixfile(output, job->filename);
7733 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7735 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7737 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7739 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7741 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7743 ret = schedule_file(job->filename);
7745 else
7747 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7749 HeapFree(GetProcessHeap(), 0, pi5);
7750 CloseHandle(hf);
7751 DeleteFileW(job->filename);
7753 list_remove(cursor);
7754 HeapFree(GetProcessHeap(), 0, job->document_title);
7755 HeapFree(GetProcessHeap(), 0, job->printer_name);
7756 HeapFree(GetProcessHeap(), 0, job->portname);
7757 HeapFree(GetProcessHeap(), 0, job->filename);
7758 HeapFree(GetProcessHeap(), 0, job->devmode);
7759 HeapFree(GetProcessHeap(), 0, job);
7760 break;
7762 end:
7763 LeaveCriticalSection(&printer_handles_cs);
7764 return ret;
7767 /*****************************************************************************
7768 * StartDocDlgA [WINSPOOL.@]
7770 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7772 UNICODE_STRING usBuffer;
7773 DOCINFOW docW;
7774 LPWSTR retW;
7775 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7776 LPSTR ret = NULL;
7778 docW.cbSize = sizeof(docW);
7779 if (doc->lpszDocName)
7781 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7782 if (!(docW.lpszDocName = docnameW)) return NULL;
7784 if (doc->lpszOutput)
7786 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7787 if (!(docW.lpszOutput = outputW)) return NULL;
7789 if (doc->lpszDatatype)
7791 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7792 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7794 docW.fwType = doc->fwType;
7796 retW = StartDocDlgW(hPrinter, &docW);
7798 if(retW)
7800 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7801 ret = HeapAlloc(GetProcessHeap(), 0, len);
7802 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7803 HeapFree(GetProcessHeap(), 0, retW);
7806 HeapFree(GetProcessHeap(), 0, datatypeW);
7807 HeapFree(GetProcessHeap(), 0, outputW);
7808 HeapFree(GetProcessHeap(), 0, docnameW);
7810 return ret;
7813 /*****************************************************************************
7814 * StartDocDlgW [WINSPOOL.@]
7816 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7817 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7818 * port is "FILE:". Also returns the full path if passed a relative path.
7820 * The caller should free the returned string from the process heap.
7822 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7824 LPWSTR ret = NULL;
7825 DWORD len, attr;
7827 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7829 PRINTER_INFO_5W *pi5;
7830 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7831 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7832 return NULL;
7833 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7834 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7835 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7837 HeapFree(GetProcessHeap(), 0, pi5);
7838 return NULL;
7840 HeapFree(GetProcessHeap(), 0, pi5);
7843 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7845 LPWSTR name;
7847 if (get_filename(&name))
7849 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7851 HeapFree(GetProcessHeap(), 0, name);
7852 return NULL;
7854 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7855 GetFullPathNameW(name, len, ret, NULL);
7856 HeapFree(GetProcessHeap(), 0, name);
7858 return ret;
7861 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7862 return NULL;
7864 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7865 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7867 attr = GetFileAttributesW(ret);
7868 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7870 HeapFree(GetProcessHeap(), 0, ret);
7871 ret = NULL;
7873 return ret;