winspool: Remove unused code.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob92098f1ef64c51ff2278fe2392488e7d1110fc49
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #include <signal.h>
40 #ifdef HAVE_CUPS_CUPS_H
41 # include <cups/cups.h>
42 #endif
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
46 #include "wine/library.h"
47 #include "windef.h"
48 #include "winbase.h"
49 #include "winuser.h"
50 #include "winerror.h"
51 #include "winreg.h"
52 #include "wingdi.h"
53 #include "winspool.h"
54 #include "winternl.h"
55 #include "wine/windef16.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
58 #include "wine/list.h"
59 #include "winnls.h"
61 #include "ddk/winsplp.h"
62 #include "wspool.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
66 /* ############################### */
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
77 /* ############################### */
79 typedef struct {
80 DWORD job_id;
81 HANDLE hf;
82 } started_doc_t;
84 typedef struct {
85 struct list jobs;
86 LONG ref;
87 } jobqueue_t;
89 typedef struct {
90 LPWSTR name;
91 LPWSTR printername;
92 HANDLE backend_printer;
93 jobqueue_t *queue;
94 started_doc_t *doc;
95 } opened_printer_t;
97 typedef struct {
98 struct list entry;
99 DWORD job_id;
100 WCHAR *filename;
101 WCHAR *portname;
102 WCHAR *document_title;
103 WCHAR *printer_name;
104 LPDEVMODEW devmode;
105 } job_t;
108 typedef struct {
109 LPCWSTR envname;
110 LPCWSTR subdir;
111 DWORD driverversion;
112 LPCWSTR versionregpath;
113 LPCWSTR versionsubdir;
114 } printenv_t;
116 /* ############################### */
118 static opened_printer_t **printer_handles;
119 static UINT nb_printer_handles;
120 static LONG next_job_id = 1;
122 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
123 WORD fwCapability, LPSTR lpszOutput,
124 LPDEVMODEA lpdm );
125 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
126 LPSTR lpszDevice, LPSTR lpszPort,
127 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
128 DWORD fwMode );
130 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'c','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
135 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
137 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
138 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
139 'C','o','n','t','r','o','l','\\',
140 'P','r','i','n','t','\\',
141 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
145 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
146 'M','i','c','r','o','s','o','f','t','\\',
147 'W','i','n','d','o','w','s',' ','N','T','\\',
148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
149 'W','i','n','d','o','w','s',0};
151 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'D','e','v','i','c','e','s',0};
157 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
158 'M','i','c','r','o','s','o','f','t','\\',
159 'W','i','n','d','o','w','s',' ','N','T','\\',
160 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
161 'P','o','r','t','s',0};
163 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s',' ','N','T','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'P','r','i','n','t','e','r','P','o','r','t','s',0};
169 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
170 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
171 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
172 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
173 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
174 static const WCHAR subdir_x64W[] = {'x','6','4',0};
175 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
176 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
177 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
178 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
179 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
181 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
182 static const WCHAR backslashW[] = {'\\',0};
183 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
184 'i','o','n',' ','F','i','l','e',0};
185 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
186 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
187 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
188 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
189 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
190 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
191 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
192 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
193 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
194 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
195 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
196 static const WCHAR NameW[] = {'N','a','m','e',0};
197 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
198 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
199 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
200 static const WCHAR PortW[] = {'P','o','r','t',0};
201 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
202 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
203 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
204 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
205 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
206 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
207 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
208 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
209 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
210 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
211 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
212 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
213 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
214 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
215 static const WCHAR emptyStringW[] = {0};
217 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
219 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
220 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
221 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
223 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
224 'D','o','c','u','m','e','n','t',0};
226 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
227 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
228 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
229 0, sizeof(DRIVER_INFO_8W)};
232 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
233 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
234 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
235 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
236 sizeof(PRINTER_INFO_9W)};
238 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
239 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
240 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
242 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
244 /******************************************************************
245 * validate the user-supplied printing-environment [internal]
247 * PARAMS
248 * env [I] PTR to Environment-String or NULL
250 * RETURNS
251 * Failure: NULL
252 * Success: PTR to printenv_t
254 * NOTES
255 * An empty string is handled the same way as NULL.
256 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
260 static const printenv_t * validate_envW(LPCWSTR env)
262 const printenv_t *result = NULL;
263 unsigned int i;
265 TRACE("testing %s\n", debugstr_w(env));
266 if (env && env[0])
268 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
270 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
272 result = all_printenv[i];
273 break;
277 if (result == NULL) {
278 FIXME("unsupported Environment: %s\n", debugstr_w(env));
279 SetLastError(ERROR_INVALID_ENVIRONMENT);
281 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
283 else
285 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
287 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
289 return result;
293 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
294 if passed a NULL string. This returns NULLs to the result.
296 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
298 if ( (src) )
300 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
301 return usBufferPtr->Buffer;
303 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
304 return NULL;
307 static LPWSTR strdupW(LPCWSTR p)
309 LPWSTR ret;
310 DWORD len;
312 if(!p) return NULL;
313 len = (strlenW(p) + 1) * sizeof(WCHAR);
314 ret = HeapAlloc(GetProcessHeap(), 0, len);
315 memcpy(ret, p, len);
316 return ret;
319 static LPSTR strdupWtoA( LPCWSTR str )
321 LPSTR ret;
322 INT len;
324 if (!str) return NULL;
325 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
326 ret = HeapAlloc( GetProcessHeap(), 0, len );
327 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
328 return ret;
331 /******************************************************************
332 * verify, that the filename is a local file
335 static inline BOOL is_local_file(LPWSTR name)
337 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
340 /* ################################ */
342 static int multi_sz_lenA(const char *str)
344 const char *ptr = str;
345 if(!str) return 0;
348 ptr += lstrlenA(ptr) + 1;
349 } while(*ptr);
351 return ptr - str + 1;
354 static void
355 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
356 char qbuf[200];
358 /* If forcing, or no profile string entry for device yet, set the entry
360 * The always change entry if not WINEPS yet is discussable.
362 if (force ||
363 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
364 !strcmp(qbuf,"*") ||
365 !strstr(qbuf,"WINEPS.DRV")
367 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
368 HKEY hkey;
370 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
371 WriteProfileStringA("windows","device",buf);
372 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
373 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
374 RegCloseKey(hkey);
376 HeapFree(GetProcessHeap(),0,buf);
380 static BOOL add_printer_driver(const char *name)
382 DRIVER_INFO_3A di3a;
384 static char driver_9x[] = "wineps16.drv",
385 driver_nt[] = "wineps.drv",
386 env_9x[] = "Windows 4.0",
387 env_nt[] = "Windows NT x86",
388 data_file[] = "generic.ppd",
389 default_data_type[] = "RAW";
391 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
392 di3a.cVersion = 3;
393 di3a.pName = (char *)name;
394 di3a.pEnvironment = env_nt;
395 di3a.pDriverPath = driver_nt;
396 di3a.pDataFile = data_file;
397 di3a.pConfigFile = driver_nt;
398 di3a.pDefaultDataType = default_data_type;
400 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
401 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
403 di3a.cVersion = 0;
404 di3a.pEnvironment = env_9x;
405 di3a.pDriverPath = driver_9x;
406 di3a.pConfigFile = driver_9x;
407 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
408 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
410 return TRUE;
413 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
414 debugstr_a(di3a.pEnvironment), GetLastError());
415 return FALSE;
418 #ifdef SONAME_LIBCUPS
419 static typeof(cupsFreeDests) *pcupsFreeDests;
420 static typeof(cupsGetDests) *pcupsGetDests;
421 static typeof(cupsGetPPD) *pcupsGetPPD;
422 static typeof(cupsPrintFile) *pcupsPrintFile;
423 static void *cupshandle;
425 static BOOL CUPS_LoadPrinters(void)
427 int i, nrofdests;
428 BOOL hadprinter = FALSE, haddefault = FALSE;
429 cups_dest_t *dests;
430 PRINTER_INFO_2A pinfo2a;
431 char *port,*devline;
432 HKEY hkeyPrinter, hkeyPrinters, hkey;
433 char loaderror[256];
435 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
436 if (!cupshandle) {
437 TRACE("%s\n", loaderror);
438 return FALSE;
440 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
442 #define DYNCUPS(x) \
443 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
444 if (!p##x) return FALSE;
446 DYNCUPS(cupsFreeDests);
447 DYNCUPS(cupsGetPPD);
448 DYNCUPS(cupsGetDests);
449 DYNCUPS(cupsPrintFile);
450 #undef DYNCUPS
452 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
453 ERROR_SUCCESS) {
454 ERR("Can't create Printers key\n");
455 return FALSE;
458 nrofdests = pcupsGetDests(&dests);
459 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
460 for (i=0;i<nrofdests;i++) {
461 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
462 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
463 sprintf(port,"LPR:%s", dests[i].name);
464 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
465 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
466 sprintf(devline, "WINEPS.DRV,%s", port);
467 WriteProfileStringA("devices", dests[i].name, devline);
468 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
469 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
470 RegCloseKey(hkey);
473 lstrcatA(devline, ",15,45");
474 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
475 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
476 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
477 RegCloseKey(hkey);
480 HeapFree(GetProcessHeap(), 0, devline);
482 TRACE("Printer %d: %s\n", i, dests[i].name);
483 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
484 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
485 and continue */
486 TRACE("Printer already exists\n");
487 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
488 RegCloseKey(hkeyPrinter);
489 } else {
490 static CHAR data_type[] = "RAW",
491 print_proc[] = "WinPrint",
492 comment[] = "WINEPS Printer using CUPS",
493 location[] = "<physical location of printer>",
494 params[] = "<parameters?>",
495 share_name[] = "<share name?>",
496 sep_file[] = "<sep file?>";
498 add_printer_driver(dests[i].name);
500 memset(&pinfo2a,0,sizeof(pinfo2a));
501 pinfo2a.pPrinterName = dests[i].name;
502 pinfo2a.pDatatype = data_type;
503 pinfo2a.pPrintProcessor = print_proc;
504 pinfo2a.pDriverName = dests[i].name;
505 pinfo2a.pComment = comment;
506 pinfo2a.pLocation = location;
507 pinfo2a.pPortName = port;
508 pinfo2a.pParameters = params;
509 pinfo2a.pShareName = share_name;
510 pinfo2a.pSepFile = sep_file;
512 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
513 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
514 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
517 HeapFree(GetProcessHeap(),0,port);
519 hadprinter = TRUE;
520 if (dests[i].is_default) {
521 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
522 haddefault = TRUE;
525 if (hadprinter & !haddefault)
526 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
527 pcupsFreeDests(nrofdests, dests);
528 RegCloseKey(hkeyPrinters);
529 return hadprinter;
531 #endif
533 static BOOL
534 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
535 PRINTER_INFO_2A pinfo2a;
536 char *e,*s,*name,*prettyname,*devname;
537 BOOL ret = FALSE, set_default = FALSE;
538 char *port = NULL, *devline,*env_default;
539 HKEY hkeyPrinter, hkeyPrinters, hkey;
541 while (isspace(*pent)) pent++;
542 s = strchr(pent,':');
543 if(s) *s='\0';
544 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
545 strcpy(name,pent);
546 if(s) {
547 *s=':';
548 pent = s;
549 } else
550 pent = "";
552 TRACE("name=%s entry=%s\n",name, pent);
554 if(ispunct(*name)) { /* a tc entry, not a real printer */
555 TRACE("skipping tc entry\n");
556 goto end;
559 if(strstr(pent,":server")) { /* server only version so skip */
560 TRACE("skipping server entry\n");
561 goto end;
564 /* Determine whether this is a postscript printer. */
566 ret = TRUE;
567 env_default = getenv("PRINTER");
568 prettyname = name;
569 /* Get longest name, usually the one at the right for later display. */
570 while((s=strchr(prettyname,'|'))) {
571 *s = '\0';
572 e = s;
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;
576 for(prettyname = s+1; isspace(*prettyname); prettyname++)
579 e = prettyname + strlen(prettyname);
580 while(isspace(*--e)) *e = '\0';
581 TRACE("\t%s\n", debugstr_a(prettyname));
582 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
584 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
585 * if it is too long, we use it as comment below. */
586 devname = prettyname;
587 if (strlen(devname)>=CCHDEVICENAME-1)
588 devname = name;
589 if (strlen(devname)>=CCHDEVICENAME-1) {
590 ret = FALSE;
591 goto end;
594 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
595 sprintf(port,"LPR:%s",name);
597 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
598 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
599 sprintf(devline, "WINEPS.DRV,%s", port);
600 WriteProfileStringA("devices", devname, devline);
601 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
602 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
603 RegCloseKey(hkey);
606 lstrcatA(devline, ",15,45");
607 WriteProfileStringA("PrinterPorts", devname, devline);
608 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
609 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
610 RegCloseKey(hkey);
613 HeapFree(GetProcessHeap(),0,devline);
615 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
616 ERROR_SUCCESS) {
617 ERR("Can't create Printers key\n");
618 ret = FALSE;
619 goto end;
621 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
622 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
623 and continue */
624 TRACE("Printer already exists\n");
625 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
626 RegCloseKey(hkeyPrinter);
627 } else {
628 static CHAR data_type[] = "RAW",
629 print_proc[] = "WinPrint",
630 comment[] = "WINEPS Printer using LPR",
631 params[] = "<parameters?>",
632 share_name[] = "<share name?>",
633 sep_file[] = "<sep file?>";
635 add_printer_driver(devname);
637 memset(&pinfo2a,0,sizeof(pinfo2a));
638 pinfo2a.pPrinterName = devname;
639 pinfo2a.pDatatype = data_type;
640 pinfo2a.pPrintProcessor = print_proc;
641 pinfo2a.pDriverName = devname;
642 pinfo2a.pComment = comment;
643 pinfo2a.pLocation = prettyname;
644 pinfo2a.pPortName = port;
645 pinfo2a.pParameters = params;
646 pinfo2a.pShareName = share_name;
647 pinfo2a.pSepFile = sep_file;
649 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
650 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
651 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
654 RegCloseKey(hkeyPrinters);
656 if (isfirst || set_default)
657 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
659 end:
660 HeapFree(GetProcessHeap(), 0, port);
661 HeapFree(GetProcessHeap(), 0, name);
662 return ret;
665 static BOOL
666 PRINTCAP_LoadPrinters(void) {
667 BOOL hadprinter = FALSE;
668 char buf[200];
669 FILE *f;
670 char *pent = NULL;
671 BOOL had_bash = FALSE;
673 f = fopen("/etc/printcap","r");
674 if (!f)
675 return FALSE;
677 while(fgets(buf,sizeof(buf),f)) {
678 char *start, *end;
680 end=strchr(buf,'\n');
681 if (end) *end='\0';
683 start = buf;
684 while(isspace(*start)) start++;
685 if(*start == '#' || *start == '\0')
686 continue;
688 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
689 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
690 HeapFree(GetProcessHeap(),0,pent);
691 pent = NULL;
694 if (end && *--end == '\\') {
695 *end = '\0';
696 had_bash = TRUE;
697 } else
698 had_bash = FALSE;
700 if (pent) {
701 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
702 strcat(pent,start);
703 } else {
704 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
705 strcpy(pent,start);
709 if(pent) {
710 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
711 HeapFree(GetProcessHeap(),0,pent);
713 fclose(f);
714 return hadprinter;
717 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
719 if (value)
720 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
721 (lstrlenW(value) + 1) * sizeof(WCHAR));
722 else
723 return ERROR_FILE_NOT_FOUND;
726 /******************************************************************
727 * get_servername_from_name (internal)
729 * for an external server, a copy of the serverpart from the full name is returned
732 static LPWSTR get_servername_from_name(LPCWSTR name)
734 LPWSTR server;
735 LPWSTR ptr;
736 WCHAR buffer[MAX_PATH];
737 DWORD len;
739 if (name == NULL) return NULL;
740 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
742 server = strdupW(&name[2]); /* skip over both backslash */
743 if (server == NULL) return NULL;
745 /* strip '\' and the printername */
746 ptr = strchrW(server, '\\');
747 if (ptr) ptr[0] = '\0';
749 TRACE("found %s\n", debugstr_w(server));
751 len = sizeof(buffer)/sizeof(buffer[0]);
752 if (GetComputerNameW(buffer, &len)) {
753 if (lstrcmpW(buffer, server) == 0) {
754 /* The requested Servername is our computername */
755 HeapFree(GetProcessHeap(), 0, server);
756 return NULL;
759 return server;
762 /******************************************************************
763 * get_basename_from_name (internal)
765 * skip over the serverpart from the full name
768 static LPCWSTR get_basename_from_name(LPCWSTR name)
770 if (name == NULL) return NULL;
771 if ((name[0] == '\\') && (name[1] == '\\')) {
772 /* skip over the servername and search for the following '\' */
773 name = strchrW(&name[2], '\\');
774 if ((name) && (name[1])) {
775 /* found a separator ('\') followed by a name:
776 skip over the separator and return the rest */
777 name++;
779 else
781 /* no basename present (we found only a servername) */
782 return NULL;
785 return name;
788 /******************************************************************
789 * get_opened_printer_entry
790 * Get the first place empty in the opened printer table
792 * ToDo:
793 * - pDefault is ignored
795 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
797 UINT_PTR handle = nb_printer_handles, i;
798 jobqueue_t *queue = NULL;
799 opened_printer_t *printer = NULL;
800 LPWSTR servername;
801 LPCWSTR printername;
803 if ((backend == NULL) && !load_backend()) return NULL;
805 servername = get_servername_from_name(name);
806 if (servername) {
807 FIXME("server %s not supported\n", debugstr_w(servername));
808 HeapFree(GetProcessHeap(), 0, servername);
809 SetLastError(ERROR_INVALID_PRINTER_NAME);
810 return NULL;
813 printername = get_basename_from_name(name);
814 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
816 /* an empty printername is invalid */
817 if (printername && (!printername[0])) {
818 SetLastError(ERROR_INVALID_PARAMETER);
819 return NULL;
822 EnterCriticalSection(&printer_handles_cs);
824 for (i = 0; i < nb_printer_handles; i++)
826 if (!printer_handles[i])
828 if(handle == nb_printer_handles)
829 handle = i;
831 else
833 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
834 queue = printer_handles[i]->queue;
838 if (handle >= nb_printer_handles)
840 opened_printer_t **new_array;
841 if (printer_handles)
842 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
843 (nb_printer_handles + 16) * sizeof(*new_array) );
844 else
845 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
846 (nb_printer_handles + 16) * sizeof(*new_array) );
848 if (!new_array)
850 handle = 0;
851 goto end;
853 printer_handles = new_array;
854 nb_printer_handles += 16;
857 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
859 handle = 0;
860 goto end;
863 /* get a printer handle from the backend */
864 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
865 handle = 0;
866 goto end;
869 /* clone the base name. This is NULL for the printserver */
870 printer->printername = strdupW(printername);
872 /* clone the full name */
873 printer->name = strdupW(name);
874 if (name && (!printer->name)) {
875 handle = 0;
876 goto end;
879 if(queue)
880 printer->queue = queue;
881 else
883 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
884 if (!printer->queue) {
885 handle = 0;
886 goto end;
888 list_init(&printer->queue->jobs);
889 printer->queue->ref = 0;
891 InterlockedIncrement(&printer->queue->ref);
893 printer_handles[handle] = printer;
894 handle++;
895 end:
896 LeaveCriticalSection(&printer_handles_cs);
897 if (!handle && printer) {
898 /* Something failed: Free all resources */
899 HeapFree(GetProcessHeap(), 0, printer->printername);
900 HeapFree(GetProcessHeap(), 0, printer->name);
901 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
902 HeapFree(GetProcessHeap(), 0, printer);
905 return (HANDLE)handle;
908 /******************************************************************
909 * get_opened_printer
910 * Get the pointer to the opened printer referred by the handle
912 static opened_printer_t *get_opened_printer(HANDLE hprn)
914 UINT_PTR idx = (UINT_PTR)hprn;
915 opened_printer_t *ret = NULL;
917 EnterCriticalSection(&printer_handles_cs);
919 if ((idx > 0) && (idx <= nb_printer_handles)) {
920 ret = printer_handles[idx - 1];
922 LeaveCriticalSection(&printer_handles_cs);
923 return ret;
926 /******************************************************************
927 * get_opened_printer_name
928 * Get the pointer to the opened printer name referred by the handle
930 static LPCWSTR get_opened_printer_name(HANDLE hprn)
932 opened_printer_t *printer = get_opened_printer(hprn);
933 if(!printer) return NULL;
934 return printer->name;
937 /******************************************************************
938 * WINSPOOL_GetOpenedPrinterRegKey
941 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
943 LPCWSTR name = get_opened_printer_name(hPrinter);
944 DWORD ret;
945 HKEY hkeyPrinters;
947 if(!name) return ERROR_INVALID_HANDLE;
949 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
950 ERROR_SUCCESS)
951 return ret;
953 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
955 ERR("Can't find opened printer %s in registry\n",
956 debugstr_w(name));
957 RegCloseKey(hkeyPrinters);
958 return ERROR_INVALID_PRINTER_NAME; /* ? */
960 RegCloseKey(hkeyPrinters);
961 return ERROR_SUCCESS;
964 void WINSPOOL_LoadSystemPrinters(void)
966 HKEY hkey, hkeyPrinters;
967 HANDLE hprn;
968 DWORD needed, num, i;
969 WCHAR PrinterName[256];
970 BOOL done = FALSE;
972 /* This ensures that all printer entries have a valid Name value. If causes
973 problems later if they don't. If one is found to be missed we create one
974 and set it equal to the name of the key */
975 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
976 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
977 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
978 for(i = 0; i < num; i++) {
979 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
980 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
981 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
982 set_reg_szW(hkey, NameW, PrinterName);
984 RegCloseKey(hkey);
989 RegCloseKey(hkeyPrinters);
992 /* We want to avoid calling AddPrinter on printers as much as
993 possible, because on cups printers this will (eventually) lead
994 to a call to cupsGetPPD which takes forever, even with non-cups
995 printers AddPrinter takes a while. So we'll tag all printers that
996 were automatically added last time around, if they still exist
997 we'll leave them be otherwise we'll delete them. */
998 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
999 if(needed) {
1000 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1001 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1002 for(i = 0; i < num; i++) {
1003 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1004 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1005 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1006 DWORD dw = 1;
1007 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1008 RegCloseKey(hkey);
1010 ClosePrinter(hprn);
1015 HeapFree(GetProcessHeap(), 0, pi);
1019 #ifdef SONAME_LIBCUPS
1020 done = CUPS_LoadPrinters();
1021 #endif
1023 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1024 PRINTCAP_LoadPrinters();
1026 /* Now enumerate the list again and delete any printers that are still tagged */
1027 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1028 if(needed) {
1029 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1030 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1031 for(i = 0; i < num; i++) {
1032 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1033 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1034 BOOL delete_driver = FALSE;
1035 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1036 DWORD dw, type, size = sizeof(dw);
1037 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1038 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1039 DeletePrinter(hprn);
1040 delete_driver = TRUE;
1042 RegCloseKey(hkey);
1044 ClosePrinter(hprn);
1045 if(delete_driver)
1046 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1051 HeapFree(GetProcessHeap(), 0, pi);
1054 return;
1058 /******************************************************************
1059 * get_job
1061 * Get the pointer to the specified job.
1062 * Should hold the printer_handles_cs before calling.
1064 static job_t *get_job(HANDLE hprn, DWORD JobId)
1066 opened_printer_t *printer = get_opened_printer(hprn);
1067 job_t *job;
1069 if(!printer) return NULL;
1070 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1072 if(job->job_id == JobId)
1073 return job;
1075 return NULL;
1078 /***********************************************************
1079 * DEVMODEcpyAtoW
1081 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1083 BOOL Formname;
1084 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1085 DWORD size;
1087 Formname = (dmA->dmSize > off_formname);
1088 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1089 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1090 dmW->dmDeviceName, CCHDEVICENAME);
1091 if(!Formname) {
1092 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1093 dmA->dmSize - CCHDEVICENAME);
1094 } else {
1095 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1096 off_formname - CCHDEVICENAME);
1097 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1098 dmW->dmFormName, CCHFORMNAME);
1099 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1100 (off_formname + CCHFORMNAME));
1102 dmW->dmSize = size;
1103 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1104 dmA->dmDriverExtra);
1105 return dmW;
1108 /***********************************************************
1109 * DEVMODEdupWtoA
1110 * Creates an ansi copy of supplied devmode
1112 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1114 LPDEVMODEA dmA;
1115 DWORD size;
1117 if (!dmW) return NULL;
1118 size = dmW->dmSize - CCHDEVICENAME -
1119 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1121 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1122 if (!dmA) return NULL;
1124 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1125 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1127 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1128 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1129 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1131 else
1133 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1134 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1135 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1136 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1138 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1141 dmA->dmSize = size;
1142 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1143 return dmA;
1146 /******************************************************************
1147 * convert_printerinfo_W_to_A [internal]
1150 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1151 DWORD level, DWORD outlen, DWORD numentries)
1153 DWORD id = 0;
1154 LPSTR ptr;
1155 INT len;
1157 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1159 len = pi_sizeof[level] * numentries;
1160 ptr = (LPSTR) out + len;
1161 outlen -= len;
1163 /* copy the numbers of all PRINTER_INFO_* first */
1164 memcpy(out, pPrintersW, len);
1166 while (id < numentries) {
1167 switch (level) {
1168 case 1:
1170 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1171 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1173 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1174 if (piW->pDescription) {
1175 piA->pDescription = ptr;
1176 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1177 ptr, outlen, NULL, NULL);
1178 ptr += len;
1179 outlen -= len;
1181 if (piW->pName) {
1182 piA->pName = ptr;
1183 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1184 ptr, outlen, NULL, NULL);
1185 ptr += len;
1186 outlen -= len;
1188 if (piW->pComment) {
1189 piA->pComment = ptr;
1190 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1191 ptr, outlen, NULL, NULL);
1192 ptr += len;
1193 outlen -= len;
1195 break;
1198 case 2:
1200 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1201 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1202 LPDEVMODEA dmA;
1204 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1205 if (piW->pServerName) {
1206 piA->pServerName = ptr;
1207 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1208 ptr, outlen, NULL, NULL);
1209 ptr += len;
1210 outlen -= len;
1212 if (piW->pPrinterName) {
1213 piA->pPrinterName = ptr;
1214 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1215 ptr, outlen, NULL, NULL);
1216 ptr += len;
1217 outlen -= len;
1219 if (piW->pShareName) {
1220 piA->pShareName = ptr;
1221 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1222 ptr, outlen, NULL, NULL);
1223 ptr += len;
1224 outlen -= len;
1226 if (piW->pPortName) {
1227 piA->pPortName = ptr;
1228 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1229 ptr, outlen, NULL, NULL);
1230 ptr += len;
1231 outlen -= len;
1233 if (piW->pDriverName) {
1234 piA->pDriverName = ptr;
1235 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1236 ptr, outlen, NULL, NULL);
1237 ptr += len;
1238 outlen -= len;
1240 if (piW->pComment) {
1241 piA->pComment = ptr;
1242 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1243 ptr, outlen, NULL, NULL);
1244 ptr += len;
1245 outlen -= len;
1247 if (piW->pLocation) {
1248 piA->pLocation = ptr;
1249 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1250 ptr, outlen, NULL, NULL);
1251 ptr += len;
1252 outlen -= len;
1255 dmA = DEVMODEdupWtoA(piW->pDevMode);
1256 if (dmA) {
1257 /* align DEVMODEA to a DWORD boundary */
1258 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1259 ptr += len;
1260 outlen -= len;
1262 piA->pDevMode = (LPDEVMODEA) ptr;
1263 len = dmA->dmSize + dmA->dmDriverExtra;
1264 memcpy(ptr, dmA, len);
1265 HeapFree(GetProcessHeap(), 0, dmA);
1267 ptr += len;
1268 outlen -= len;
1271 if (piW->pSepFile) {
1272 piA->pSepFile = ptr;
1273 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1274 ptr, outlen, NULL, NULL);
1275 ptr += len;
1276 outlen -= len;
1278 if (piW->pPrintProcessor) {
1279 piA->pPrintProcessor = ptr;
1280 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1281 ptr, outlen, NULL, NULL);
1282 ptr += len;
1283 outlen -= len;
1285 if (piW->pDatatype) {
1286 piA->pDatatype = ptr;
1287 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1288 ptr, outlen, NULL, NULL);
1289 ptr += len;
1290 outlen -= len;
1292 if (piW->pParameters) {
1293 piA->pParameters = ptr;
1294 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1295 ptr, outlen, NULL, NULL);
1296 ptr += len;
1297 outlen -= len;
1299 if (piW->pSecurityDescriptor) {
1300 piA->pSecurityDescriptor = NULL;
1301 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1303 break;
1306 case 4:
1308 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1309 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1311 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1313 if (piW->pPrinterName) {
1314 piA->pPrinterName = ptr;
1315 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1316 ptr, outlen, NULL, NULL);
1317 ptr += len;
1318 outlen -= len;
1320 if (piW->pServerName) {
1321 piA->pServerName = ptr;
1322 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1323 ptr, outlen, NULL, NULL);
1324 ptr += len;
1325 outlen -= len;
1327 break;
1330 case 5:
1332 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1333 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1335 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1337 if (piW->pPrinterName) {
1338 piA->pPrinterName = ptr;
1339 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1340 ptr, outlen, NULL, NULL);
1341 ptr += len;
1342 outlen -= len;
1344 if (piW->pPortName) {
1345 piA->pPortName = ptr;
1346 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1347 ptr, outlen, NULL, NULL);
1348 ptr += len;
1349 outlen -= len;
1351 break;
1354 case 6: /* 6A and 6W are the same structure */
1355 break;
1357 case 7:
1359 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1360 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1362 TRACE("(%u) #%u\n", level, id);
1363 if (piW->pszObjectGUID) {
1364 piA->pszObjectGUID = ptr;
1365 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1366 ptr, outlen, NULL, NULL);
1367 ptr += len;
1368 outlen -= len;
1370 break;
1373 case 9:
1375 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1376 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1377 LPDEVMODEA dmA;
1379 TRACE("(%u) #%u\n", level, id);
1380 dmA = DEVMODEdupWtoA(piW->pDevMode);
1381 if (dmA) {
1382 /* align DEVMODEA to a DWORD boundary */
1383 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1384 ptr += len;
1385 outlen -= len;
1387 piA->pDevMode = (LPDEVMODEA) ptr;
1388 len = dmA->dmSize + dmA->dmDriverExtra;
1389 memcpy(ptr, dmA, len);
1390 HeapFree(GetProcessHeap(), 0, dmA);
1392 ptr += len;
1393 outlen -= len;
1396 break;
1399 default:
1400 FIXME("for level %u\n", level);
1402 pPrintersW += pi_sizeof[level];
1403 out += pi_sizeof[level];
1404 id++;
1408 /******************************************************************
1409 * convert_driverinfo_W_to_A [internal]
1412 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1413 DWORD level, DWORD outlen, DWORD numentries)
1415 DWORD id = 0;
1416 LPSTR ptr;
1417 INT len;
1419 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1421 len = di_sizeof[level] * numentries;
1422 ptr = (LPSTR) out + len;
1423 outlen -= len;
1425 /* copy the numbers of all PRINTER_INFO_* first */
1426 memcpy(out, pDriversW, len);
1428 #define COPY_STRING(fld) \
1429 { if (diW->fld){ \
1430 diA->fld = ptr; \
1431 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1432 ptr += len; outlen -= len;\
1434 #define COPY_MULTIZ_STRING(fld) \
1435 { LPWSTR p = diW->fld; if (p){ \
1436 diA->fld = ptr; \
1437 do {\
1438 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1439 ptr += len; outlen -= len; p += len;\
1441 while(len > 1 && outlen > 0); \
1444 while (id < numentries)
1446 switch (level)
1448 case 1:
1450 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1451 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1453 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1455 COPY_STRING(pName);
1456 break;
1458 case 2:
1460 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1461 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1463 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1465 COPY_STRING(pName);
1466 COPY_STRING(pEnvironment);
1467 COPY_STRING(pDriverPath);
1468 COPY_STRING(pDataFile);
1469 COPY_STRING(pConfigFile);
1470 break;
1472 case 3:
1474 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1475 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1477 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1479 COPY_STRING(pName);
1480 COPY_STRING(pEnvironment);
1481 COPY_STRING(pDriverPath);
1482 COPY_STRING(pDataFile);
1483 COPY_STRING(pConfigFile);
1484 COPY_STRING(pHelpFile);
1485 COPY_MULTIZ_STRING(pDependentFiles);
1486 COPY_STRING(pMonitorName);
1487 COPY_STRING(pDefaultDataType);
1488 break;
1490 case 4:
1492 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1493 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1495 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1497 COPY_STRING(pName);
1498 COPY_STRING(pEnvironment);
1499 COPY_STRING(pDriverPath);
1500 COPY_STRING(pDataFile);
1501 COPY_STRING(pConfigFile);
1502 COPY_STRING(pHelpFile);
1503 COPY_MULTIZ_STRING(pDependentFiles);
1504 COPY_STRING(pMonitorName);
1505 COPY_STRING(pDefaultDataType);
1506 COPY_MULTIZ_STRING(pszzPreviousNames);
1507 break;
1509 case 5:
1511 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1512 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1514 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1516 COPY_STRING(pName);
1517 COPY_STRING(pEnvironment);
1518 COPY_STRING(pDriverPath);
1519 COPY_STRING(pDataFile);
1520 COPY_STRING(pConfigFile);
1521 break;
1523 case 6:
1525 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1526 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) 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 break;
1546 case 8:
1548 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1549 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1551 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1553 COPY_STRING(pName);
1554 COPY_STRING(pEnvironment);
1555 COPY_STRING(pDriverPath);
1556 COPY_STRING(pDataFile);
1557 COPY_STRING(pConfigFile);
1558 COPY_STRING(pHelpFile);
1559 COPY_MULTIZ_STRING(pDependentFiles);
1560 COPY_STRING(pMonitorName);
1561 COPY_STRING(pDefaultDataType);
1562 COPY_MULTIZ_STRING(pszzPreviousNames);
1563 COPY_STRING(pszMfgName);
1564 COPY_STRING(pszOEMUrl);
1565 COPY_STRING(pszHardwareID);
1566 COPY_STRING(pszProvider);
1567 COPY_STRING(pszPrintProcessor);
1568 COPY_STRING(pszVendorSetup);
1569 COPY_MULTIZ_STRING(pszzColorProfiles);
1570 COPY_STRING(pszInfPath);
1571 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1572 break;
1576 default:
1577 FIXME("for level %u\n", level);
1580 pDriversW += di_sizeof[level];
1581 out += di_sizeof[level];
1582 id++;
1585 #undef COPY_STRING
1586 #undef COPY_MULTIZ_STRING
1590 /***********************************************************
1591 * PRINTER_INFO_2AtoW
1592 * Creates a unicode copy of PRINTER_INFO_2A on heap
1594 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1596 LPPRINTER_INFO_2W piW;
1597 UNICODE_STRING usBuffer;
1599 if(!piA) return NULL;
1600 piW = HeapAlloc(heap, 0, sizeof(*piW));
1601 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1603 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1604 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1605 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1606 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1607 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1608 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1609 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1610 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1611 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1612 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1613 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1614 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1615 return piW;
1618 /***********************************************************
1619 * FREE_PRINTER_INFO_2W
1620 * Free PRINTER_INFO_2W and all strings
1622 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1624 if(!piW) return;
1626 HeapFree(heap,0,piW->pServerName);
1627 HeapFree(heap,0,piW->pPrinterName);
1628 HeapFree(heap,0,piW->pShareName);
1629 HeapFree(heap,0,piW->pPortName);
1630 HeapFree(heap,0,piW->pDriverName);
1631 HeapFree(heap,0,piW->pComment);
1632 HeapFree(heap,0,piW->pLocation);
1633 HeapFree(heap,0,piW->pDevMode);
1634 HeapFree(heap,0,piW->pSepFile);
1635 HeapFree(heap,0,piW->pPrintProcessor);
1636 HeapFree(heap,0,piW->pDatatype);
1637 HeapFree(heap,0,piW->pParameters);
1638 HeapFree(heap,0,piW);
1639 return;
1642 /******************************************************************
1643 * DeviceCapabilities [WINSPOOL.@]
1644 * DeviceCapabilitiesA [WINSPOOL.@]
1647 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1648 LPSTR pOutput, LPDEVMODEA lpdm)
1650 INT ret;
1652 if (!GDI_CallDeviceCapabilities16)
1654 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1655 (LPCSTR)104 );
1656 if (!GDI_CallDeviceCapabilities16) return -1;
1658 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1660 /* If DC_PAPERSIZE map POINT16s to POINTs */
1661 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1662 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1663 POINT *pt = (POINT *)pOutput;
1664 INT i;
1665 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1666 for(i = 0; i < ret; i++, pt++)
1668 pt->x = tmp[i].x;
1669 pt->y = tmp[i].y;
1671 HeapFree( GetProcessHeap(), 0, tmp );
1673 return ret;
1677 /*****************************************************************************
1678 * DeviceCapabilitiesW [WINSPOOL.@]
1680 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1683 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1684 WORD fwCapability, LPWSTR pOutput,
1685 const DEVMODEW *pDevMode)
1687 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1688 LPSTR pDeviceA = strdupWtoA(pDevice);
1689 LPSTR pPortA = strdupWtoA(pPort);
1690 INT ret;
1692 if(pOutput && (fwCapability == DC_BINNAMES ||
1693 fwCapability == DC_FILEDEPENDENCIES ||
1694 fwCapability == DC_PAPERNAMES)) {
1695 /* These need A -> W translation */
1696 INT size = 0, i;
1697 LPSTR pOutputA;
1698 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1699 dmA);
1700 if(ret == -1)
1701 return ret;
1702 switch(fwCapability) {
1703 case DC_BINNAMES:
1704 size = 24;
1705 break;
1706 case DC_PAPERNAMES:
1707 case DC_FILEDEPENDENCIES:
1708 size = 64;
1709 break;
1711 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1712 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1713 dmA);
1714 for(i = 0; i < ret; i++)
1715 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1716 pOutput + (i * size), size);
1717 HeapFree(GetProcessHeap(), 0, pOutputA);
1718 } else {
1719 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1720 (LPSTR)pOutput, dmA);
1722 HeapFree(GetProcessHeap(),0,pPortA);
1723 HeapFree(GetProcessHeap(),0,pDeviceA);
1724 HeapFree(GetProcessHeap(),0,dmA);
1725 return ret;
1728 /******************************************************************
1729 * DocumentPropertiesA [WINSPOOL.@]
1731 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1733 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1734 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1735 LPDEVMODEA pDevModeInput,DWORD fMode )
1737 LPSTR lpName = pDeviceName;
1738 static CHAR port[] = "LPT1:";
1739 LONG ret;
1741 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1742 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1745 if(!pDeviceName) {
1746 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1747 if(!lpNameW) {
1748 ERR("no name from hPrinter?\n");
1749 SetLastError(ERROR_INVALID_HANDLE);
1750 return -1;
1752 lpName = strdupWtoA(lpNameW);
1755 if (!GDI_CallExtDeviceMode16)
1757 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1758 (LPCSTR)102 );
1759 if (!GDI_CallExtDeviceMode16) {
1760 ERR("No CallExtDeviceMode16?\n");
1761 return -1;
1764 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1765 pDevModeInput, NULL, fMode);
1767 if(!pDeviceName)
1768 HeapFree(GetProcessHeap(),0,lpName);
1769 return ret;
1773 /*****************************************************************************
1774 * DocumentPropertiesW (WINSPOOL.@)
1776 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1778 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1779 LPWSTR pDeviceName,
1780 LPDEVMODEW pDevModeOutput,
1781 LPDEVMODEW pDevModeInput, DWORD fMode)
1784 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1785 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1786 LPDEVMODEA pDevModeOutputA = NULL;
1787 LONG ret;
1789 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1790 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1791 fMode);
1792 if(pDevModeOutput) {
1793 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1794 if(ret < 0) return ret;
1795 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1797 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1798 pDevModeInputA, fMode);
1799 if(pDevModeOutput) {
1800 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1801 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1803 if(fMode == 0 && ret > 0)
1804 ret += (CCHDEVICENAME + CCHFORMNAME);
1805 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1806 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1807 return ret;
1810 /******************************************************************
1811 * OpenPrinterA [WINSPOOL.@]
1813 * See OpenPrinterW.
1816 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1817 LPPRINTER_DEFAULTSA pDefault)
1819 UNICODE_STRING lpPrinterNameW;
1820 UNICODE_STRING usBuffer;
1821 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1822 PWSTR pwstrPrinterNameW;
1823 BOOL ret;
1825 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1827 if(pDefault) {
1828 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1829 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1830 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1831 pDefaultW = &DefaultW;
1833 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1834 if(pDefault) {
1835 RtlFreeUnicodeString(&usBuffer);
1836 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1838 RtlFreeUnicodeString(&lpPrinterNameW);
1839 return ret;
1842 /******************************************************************
1843 * OpenPrinterW [WINSPOOL.@]
1845 * Open a Printer / Printserver or a Printer-Object
1847 * PARAMS
1848 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1849 * phPrinter [O] The resulting Handle is stored here
1850 * pDefault [I] PTR to Default Printer Settings or NULL
1852 * RETURNS
1853 * Success: TRUE
1854 * Failure: FALSE
1856 * NOTES
1857 * lpPrinterName is one of:
1858 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1859 *| Printer: "PrinterName"
1860 *| Printer-Object: "PrinterName,Job xxx"
1861 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1862 *| XcvPort: "Servername,XcvPort PortName"
1864 * BUGS
1865 *| Printer-Object not supported
1866 *| pDefaults is ignored
1869 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1872 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1873 if (pDefault) {
1874 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1875 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1878 if(!phPrinter) {
1879 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1880 SetLastError(ERROR_INVALID_PARAMETER);
1881 return FALSE;
1884 /* Get the unique handle of the printer or Printserver */
1885 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1886 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1887 return (*phPrinter != 0);
1890 /******************************************************************
1891 * AddMonitorA [WINSPOOL.@]
1893 * See AddMonitorW.
1896 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1898 LPWSTR nameW = NULL;
1899 INT len;
1900 BOOL res;
1901 LPMONITOR_INFO_2A mi2a;
1902 MONITOR_INFO_2W mi2w;
1904 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1905 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1906 debugstr_a(mi2a ? mi2a->pName : NULL),
1907 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1908 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1910 if (Level != 2) {
1911 SetLastError(ERROR_INVALID_LEVEL);
1912 return FALSE;
1915 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1916 if (mi2a == NULL) {
1917 return FALSE;
1920 if (pName) {
1921 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1922 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1923 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1926 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1927 if (mi2a->pName) {
1928 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1929 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1930 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1932 if (mi2a->pEnvironment) {
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1934 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1937 if (mi2a->pDLLName) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1939 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1943 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1945 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1946 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1947 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1949 HeapFree(GetProcessHeap(), 0, nameW);
1950 return (res);
1953 /******************************************************************************
1954 * AddMonitorW [WINSPOOL.@]
1956 * Install a Printmonitor
1958 * PARAMS
1959 * pName [I] Servername or NULL (local Computer)
1960 * Level [I] Structure-Level (Must be 2)
1961 * pMonitors [I] PTR to MONITOR_INFO_2
1963 * RETURNS
1964 * Success: TRUE
1965 * Failure: FALSE
1967 * NOTES
1968 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1971 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1973 LPMONITOR_INFO_2W mi2w;
1975 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1976 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1977 debugstr_w(mi2w ? mi2w->pName : NULL),
1978 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1979 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1981 if ((backend == NULL) && !load_backend()) return FALSE;
1983 if (Level != 2) {
1984 SetLastError(ERROR_INVALID_LEVEL);
1985 return FALSE;
1988 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1989 if (mi2w == NULL) {
1990 return FALSE;
1993 return backend->fpAddMonitor(pName, Level, pMonitors);
1996 /******************************************************************
1997 * DeletePrinterDriverA [WINSPOOL.@]
2000 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2002 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2005 /******************************************************************
2006 * DeletePrinterDriverW [WINSPOOL.@]
2009 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2011 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2014 /******************************************************************
2015 * DeleteMonitorA [WINSPOOL.@]
2017 * See DeleteMonitorW.
2020 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2022 LPWSTR nameW = NULL;
2023 LPWSTR EnvironmentW = NULL;
2024 LPWSTR MonitorNameW = NULL;
2025 BOOL res;
2026 INT len;
2028 if (pName) {
2029 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2030 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2031 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2034 if (pEnvironment) {
2035 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2036 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2039 if (pMonitorName) {
2040 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2041 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2045 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2047 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2048 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2049 HeapFree(GetProcessHeap(), 0, nameW);
2050 return (res);
2053 /******************************************************************
2054 * DeleteMonitorW [WINSPOOL.@]
2056 * Delete a specific Printmonitor from a Printing-Environment
2058 * PARAMS
2059 * pName [I] Servername or NULL (local Computer)
2060 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2061 * pMonitorName [I] Name of the Monitor, that should be deleted
2063 * RETURNS
2064 * Success: TRUE
2065 * Failure: FALSE
2067 * NOTES
2068 * pEnvironment is ignored in Windows for the local Computer.
2071 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2074 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2075 debugstr_w(pMonitorName));
2077 if ((backend == NULL) && !load_backend()) return FALSE;
2079 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2083 /******************************************************************
2084 * DeletePortA [WINSPOOL.@]
2086 * See DeletePortW.
2089 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2091 LPWSTR nameW = NULL;
2092 LPWSTR portW = NULL;
2093 INT len;
2094 DWORD res;
2096 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2098 /* convert servername to unicode */
2099 if (pName) {
2100 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2101 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2102 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2105 /* convert portname to unicode */
2106 if (pPortName) {
2107 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2108 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2109 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2112 res = DeletePortW(nameW, hWnd, portW);
2113 HeapFree(GetProcessHeap(), 0, nameW);
2114 HeapFree(GetProcessHeap(), 0, portW);
2115 return res;
2118 /******************************************************************
2119 * DeletePortW [WINSPOOL.@]
2121 * Delete a specific Port
2123 * PARAMS
2124 * pName [I] Servername or NULL (local Computer)
2125 * hWnd [I] Handle to parent Window for the Dialog-Box
2126 * pPortName [I] Name of the Port, that should be deleted
2128 * RETURNS
2129 * Success: TRUE
2130 * Failure: FALSE
2133 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2135 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2137 if ((backend == NULL) && !load_backend()) return FALSE;
2139 if (!pPortName) {
2140 SetLastError(RPC_X_NULL_REF_POINTER);
2141 return FALSE;
2144 return backend->fpDeletePort(pName, hWnd, pPortName);
2147 /******************************************************************************
2148 * SetPrinterW [WINSPOOL.@]
2150 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2152 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2154 return FALSE;
2157 /******************************************************************************
2158 * WritePrinter [WINSPOOL.@]
2160 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2162 opened_printer_t *printer;
2163 BOOL ret = FALSE;
2165 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2167 EnterCriticalSection(&printer_handles_cs);
2168 printer = get_opened_printer(hPrinter);
2169 if(!printer)
2171 SetLastError(ERROR_INVALID_HANDLE);
2172 goto end;
2175 if(!printer->doc)
2177 SetLastError(ERROR_SPL_NO_STARTDOC);
2178 goto end;
2181 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2182 end:
2183 LeaveCriticalSection(&printer_handles_cs);
2184 return ret;
2187 /*****************************************************************************
2188 * AddFormA [WINSPOOL.@]
2190 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2192 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2193 return 1;
2196 /*****************************************************************************
2197 * AddFormW [WINSPOOL.@]
2199 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2201 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2202 return 1;
2205 /*****************************************************************************
2206 * AddJobA [WINSPOOL.@]
2208 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2210 BOOL ret;
2211 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2212 DWORD needed;
2214 if(Level != 1) {
2215 SetLastError(ERROR_INVALID_LEVEL);
2216 return FALSE;
2219 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2221 if(ret) {
2222 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2223 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2224 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2225 if(*pcbNeeded > cbBuf) {
2226 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2227 ret = FALSE;
2228 } else {
2229 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2230 addjobA->JobId = addjobW->JobId;
2231 addjobA->Path = (char *)(addjobA + 1);
2232 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2235 return ret;
2238 /*****************************************************************************
2239 * AddJobW [WINSPOOL.@]
2241 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2243 opened_printer_t *printer;
2244 job_t *job;
2245 BOOL ret = FALSE;
2246 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2247 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2248 WCHAR path[MAX_PATH], filename[MAX_PATH];
2249 DWORD len;
2250 ADDJOB_INFO_1W *addjob;
2252 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2254 EnterCriticalSection(&printer_handles_cs);
2256 printer = get_opened_printer(hPrinter);
2258 if(!printer) {
2259 SetLastError(ERROR_INVALID_HANDLE);
2260 goto end;
2263 if(Level != 1) {
2264 SetLastError(ERROR_INVALID_LEVEL);
2265 goto end;
2268 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2269 if(!job)
2270 goto end;
2272 job->job_id = InterlockedIncrement(&next_job_id);
2274 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2275 if(path[len - 1] != '\\')
2276 path[len++] = '\\';
2277 memcpy(path + len, spool_path, sizeof(spool_path));
2278 sprintfW(filename, fmtW, path, job->job_id);
2280 len = strlenW(filename);
2281 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2282 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2283 job->document_title = strdupW(default_doc_title);
2284 job->printer_name = strdupW(printer->name);
2285 job->devmode = NULL;
2286 list_add_tail(&printer->queue->jobs, &job->entry);
2288 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2289 if(*pcbNeeded <= cbBuf) {
2290 addjob = (ADDJOB_INFO_1W*)pData;
2291 addjob->JobId = job->job_id;
2292 addjob->Path = (WCHAR *)(addjob + 1);
2293 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2294 ret = TRUE;
2295 } else
2296 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2298 end:
2299 LeaveCriticalSection(&printer_handles_cs);
2300 return ret;
2303 /*****************************************************************************
2304 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2306 * Return the PATH for the Print-Processors
2308 * See GetPrintProcessorDirectoryW.
2312 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2313 DWORD level, LPBYTE Info,
2314 DWORD cbBuf, LPDWORD pcbNeeded)
2316 LPWSTR serverW = NULL;
2317 LPWSTR envW = NULL;
2318 BOOL ret;
2319 INT len;
2321 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2322 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2325 if (server) {
2326 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2327 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2328 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2331 if (env) {
2332 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2333 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2334 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2337 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2338 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2340 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2341 cbBuf, pcbNeeded);
2343 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2344 cbBuf, NULL, NULL) > 0;
2347 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2348 HeapFree(GetProcessHeap(), 0, envW);
2349 HeapFree(GetProcessHeap(), 0, serverW);
2350 return ret;
2353 /*****************************************************************************
2354 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2356 * Return the PATH for the Print-Processors
2358 * PARAMS
2359 * server [I] Servername (NT only) or NULL (local Computer)
2360 * env [I] Printing-Environment (see below) or NULL (Default)
2361 * level [I] Structure-Level (must be 1)
2362 * Info [O] PTR to Buffer that receives the Result
2363 * cbBuf [I] Size of Buffer at "Info"
2364 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2365 * required for the Buffer at "Info"
2367 * RETURNS
2368 * Success: TRUE and in pcbNeeded the Bytes used in Info
2369 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2370 * if cbBuf is too small
2372 * Native Values returned in Info on Success:
2373 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2374 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2375 *| win9x(Windows 4.0): "%winsysdir%"
2377 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2379 * BUGS
2380 * Only NULL or "" is supported for server
2383 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2384 DWORD level, LPBYTE Info,
2385 DWORD cbBuf, LPDWORD pcbNeeded)
2388 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2389 Info, cbBuf, pcbNeeded);
2391 if ((backend == NULL) && !load_backend()) return FALSE;
2393 if (level != 1) {
2394 /* (Level != 1) is ignored in win9x */
2395 SetLastError(ERROR_INVALID_LEVEL);
2396 return FALSE;
2399 if (pcbNeeded == NULL) {
2400 /* (pcbNeeded == NULL) is ignored in win9x */
2401 SetLastError(RPC_X_NULL_REF_POINTER);
2402 return FALSE;
2405 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2408 /*****************************************************************************
2409 * WINSPOOL_OpenDriverReg [internal]
2411 * opens the registry for the printer drivers depending on the given input
2412 * variable pEnvironment
2414 * RETURNS:
2415 * the opened hkey on success
2416 * NULL on error
2418 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2420 HKEY retval = NULL;
2421 LPWSTR buffer;
2422 const printenv_t * env;
2424 TRACE("(%s)\n", debugstr_w(pEnvironment));
2426 env = validate_envW(pEnvironment);
2427 if (!env) return NULL;
2429 buffer = HeapAlloc( GetProcessHeap(), 0,
2430 (strlenW(DriversW) + strlenW(env->envname) +
2431 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2432 if(buffer) {
2433 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2434 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2435 HeapFree(GetProcessHeap(), 0, buffer);
2437 return retval;
2440 /*****************************************************************************
2441 * AddPrinterW [WINSPOOL.@]
2443 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2445 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2446 LPDEVMODEA dmA;
2447 LPDEVMODEW dmW;
2448 HANDLE retval;
2449 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2450 LONG size;
2451 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2452 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2453 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2454 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2455 statusW[] = {'S','t','a','t','u','s',0},
2456 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2458 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2460 if(pName != NULL) {
2461 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2462 SetLastError(ERROR_INVALID_PARAMETER);
2463 return 0;
2465 if(Level != 2) {
2466 ERR("Level = %d, unsupported!\n", Level);
2467 SetLastError(ERROR_INVALID_LEVEL);
2468 return 0;
2470 if(!pPrinter) {
2471 SetLastError(ERROR_INVALID_PARAMETER);
2472 return 0;
2474 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2475 ERROR_SUCCESS) {
2476 ERR("Can't create Printers key\n");
2477 return 0;
2479 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2480 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2481 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2482 RegCloseKey(hkeyPrinter);
2483 RegCloseKey(hkeyPrinters);
2484 return 0;
2486 RegCloseKey(hkeyPrinter);
2488 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2489 if(!hkeyDrivers) {
2490 ERR("Can't create Drivers key\n");
2491 RegCloseKey(hkeyPrinters);
2492 return 0;
2494 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2495 ERROR_SUCCESS) {
2496 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2497 RegCloseKey(hkeyPrinters);
2498 RegCloseKey(hkeyDrivers);
2499 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2500 return 0;
2502 RegCloseKey(hkeyDriver);
2503 RegCloseKey(hkeyDrivers);
2505 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2506 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2507 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2508 RegCloseKey(hkeyPrinters);
2509 return 0;
2512 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2513 ERROR_SUCCESS) {
2514 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2515 SetLastError(ERROR_INVALID_PRINTER_NAME);
2516 RegCloseKey(hkeyPrinters);
2517 return 0;
2519 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2520 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2521 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2523 /* See if we can load the driver. We may need the devmode structure anyway
2525 * FIXME:
2526 * Note that DocumentPropertiesW will briefly try to open the printer we
2527 * just create to find a DEVMODEA struct (it will use the WINEPS default
2528 * one in case it is not there, so we are ok).
2530 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2532 if(size < 0) {
2533 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2534 size = sizeof(DEVMODEW);
2536 if(pi->pDevMode)
2537 dmW = pi->pDevMode;
2538 else
2540 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2541 dmW->dmSize = size;
2542 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2544 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2545 HeapFree(GetProcessHeap(),0,dmW);
2546 dmW=NULL;
2548 else
2550 /* set devmode to printer name */
2551 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2555 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2556 and we support these drivers. NT writes DEVMODEW so somehow
2557 we'll need to distinguish between these when we support NT
2558 drivers */
2559 if (dmW)
2561 dmA = DEVMODEdupWtoA(dmW);
2562 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2563 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2564 HeapFree(GetProcessHeap(), 0, dmA);
2565 if(!pi->pDevMode)
2566 HeapFree(GetProcessHeap(), 0, dmW);
2568 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2569 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2570 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2571 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2573 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2574 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2575 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2576 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2577 (LPBYTE)&pi->Priority, sizeof(DWORD));
2578 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2579 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2580 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2581 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2582 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2583 (LPBYTE)&pi->Status, sizeof(DWORD));
2584 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2585 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2587 RegCloseKey(hkeyPrinter);
2588 RegCloseKey(hkeyPrinters);
2589 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2590 ERR("OpenPrinter failing\n");
2591 return 0;
2593 return retval;
2596 /*****************************************************************************
2597 * AddPrinterA [WINSPOOL.@]
2599 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2601 UNICODE_STRING pNameW;
2602 PWSTR pwstrNameW;
2603 PRINTER_INFO_2W *piW;
2604 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2605 HANDLE ret;
2607 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2608 if(Level != 2) {
2609 ERR("Level = %d, unsupported!\n", Level);
2610 SetLastError(ERROR_INVALID_LEVEL);
2611 return 0;
2613 pwstrNameW = asciitounicode(&pNameW,pName);
2614 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2616 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2618 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2619 RtlFreeUnicodeString(&pNameW);
2620 return ret;
2624 /*****************************************************************************
2625 * ClosePrinter [WINSPOOL.@]
2627 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2629 UINT_PTR i = (UINT_PTR)hPrinter;
2630 opened_printer_t *printer = NULL;
2631 BOOL ret = FALSE;
2633 TRACE("(%p)\n", hPrinter);
2635 EnterCriticalSection(&printer_handles_cs);
2637 if ((i > 0) && (i <= nb_printer_handles))
2638 printer = printer_handles[i - 1];
2641 if(printer)
2643 struct list *cursor, *cursor2;
2645 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2647 if (printer->backend_printer) {
2648 backend->fpClosePrinter(printer->backend_printer);
2651 if(printer->doc)
2652 EndDocPrinter(hPrinter);
2654 if(InterlockedDecrement(&printer->queue->ref) == 0)
2656 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2658 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2659 ScheduleJob(hPrinter, job->job_id);
2661 HeapFree(GetProcessHeap(), 0, printer->queue);
2664 HeapFree(GetProcessHeap(), 0, printer->printername);
2665 HeapFree(GetProcessHeap(), 0, printer->name);
2666 HeapFree(GetProcessHeap(), 0, printer);
2667 printer_handles[i - 1] = NULL;
2668 ret = TRUE;
2670 LeaveCriticalSection(&printer_handles_cs);
2671 return ret;
2674 /*****************************************************************************
2675 * DeleteFormA [WINSPOOL.@]
2677 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2679 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2680 return 1;
2683 /*****************************************************************************
2684 * DeleteFormW [WINSPOOL.@]
2686 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2688 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2689 return 1;
2692 /*****************************************************************************
2693 * DeletePrinter [WINSPOOL.@]
2695 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2697 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2698 HKEY hkeyPrinters, hkey;
2700 if(!lpNameW) {
2701 SetLastError(ERROR_INVALID_HANDLE);
2702 return FALSE;
2704 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2705 RegDeleteTreeW(hkeyPrinters, lpNameW);
2706 RegCloseKey(hkeyPrinters);
2708 WriteProfileStringW(devicesW, lpNameW, NULL);
2709 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2711 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2712 RegDeleteValueW(hkey, lpNameW);
2713 RegCloseKey(hkey);
2716 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2717 RegDeleteValueW(hkey, lpNameW);
2718 RegCloseKey(hkey);
2720 return TRUE;
2723 /*****************************************************************************
2724 * SetPrinterA [WINSPOOL.@]
2726 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2727 DWORD Command)
2729 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2730 return FALSE;
2733 /*****************************************************************************
2734 * SetJobA [WINSPOOL.@]
2736 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2737 LPBYTE pJob, DWORD Command)
2739 BOOL ret;
2740 LPBYTE JobW;
2741 UNICODE_STRING usBuffer;
2743 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2745 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2746 are all ignored by SetJob, so we don't bother copying them */
2747 switch(Level)
2749 case 0:
2750 JobW = NULL;
2751 break;
2752 case 1:
2754 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2755 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2757 JobW = (LPBYTE)info1W;
2758 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2759 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2760 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2761 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2762 info1W->Status = info1A->Status;
2763 info1W->Priority = info1A->Priority;
2764 info1W->Position = info1A->Position;
2765 info1W->PagesPrinted = info1A->PagesPrinted;
2766 break;
2768 case 2:
2770 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2771 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2773 JobW = (LPBYTE)info2W;
2774 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2775 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2776 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2777 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2778 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2779 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2780 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2781 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2782 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2783 info2W->Status = info2A->Status;
2784 info2W->Priority = info2A->Priority;
2785 info2W->Position = info2A->Position;
2786 info2W->StartTime = info2A->StartTime;
2787 info2W->UntilTime = info2A->UntilTime;
2788 info2W->PagesPrinted = info2A->PagesPrinted;
2789 break;
2791 case 3:
2792 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2793 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2794 break;
2795 default:
2796 SetLastError(ERROR_INVALID_LEVEL);
2797 return FALSE;
2800 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2802 switch(Level)
2804 case 1:
2806 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2807 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2808 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2809 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2810 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2811 break;
2813 case 2:
2815 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2816 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2817 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2818 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2819 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2820 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2821 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2822 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2823 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2824 break;
2827 HeapFree(GetProcessHeap(), 0, JobW);
2829 return ret;
2832 /*****************************************************************************
2833 * SetJobW [WINSPOOL.@]
2835 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2836 LPBYTE pJob, DWORD Command)
2838 BOOL ret = FALSE;
2839 job_t *job;
2840 DWORD size;
2842 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2843 FIXME("Ignoring everything other than document title\n");
2845 EnterCriticalSection(&printer_handles_cs);
2846 job = get_job(hPrinter, JobId);
2847 if(!job)
2848 goto end;
2850 switch(Level)
2852 case 0:
2853 break;
2854 case 1:
2856 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2857 HeapFree(GetProcessHeap(), 0, job->document_title);
2858 job->document_title = strdupW(info1->pDocument);
2859 break;
2861 case 2:
2863 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2864 HeapFree(GetProcessHeap(), 0, job->document_title);
2865 job->document_title = strdupW(info2->pDocument);
2866 HeapFree(GetProcessHeap(), 0, job->devmode);
2867 if (info2->pDevMode)
2869 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2870 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2871 memcpy(job->devmode, info2->pDevMode, size);
2873 else
2874 job->devmode = NULL;
2875 break;
2877 case 3:
2878 break;
2879 default:
2880 SetLastError(ERROR_INVALID_LEVEL);
2881 goto end;
2883 ret = TRUE;
2884 end:
2885 LeaveCriticalSection(&printer_handles_cs);
2886 return ret;
2889 /*****************************************************************************
2890 * EndDocPrinter [WINSPOOL.@]
2892 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2894 opened_printer_t *printer;
2895 BOOL ret = FALSE;
2896 TRACE("(%p)\n", hPrinter);
2898 EnterCriticalSection(&printer_handles_cs);
2900 printer = get_opened_printer(hPrinter);
2901 if(!printer)
2903 SetLastError(ERROR_INVALID_HANDLE);
2904 goto end;
2907 if(!printer->doc)
2909 SetLastError(ERROR_SPL_NO_STARTDOC);
2910 goto end;
2913 CloseHandle(printer->doc->hf);
2914 ScheduleJob(hPrinter, printer->doc->job_id);
2915 HeapFree(GetProcessHeap(), 0, printer->doc);
2916 printer->doc = NULL;
2917 ret = TRUE;
2918 end:
2919 LeaveCriticalSection(&printer_handles_cs);
2920 return ret;
2923 /*****************************************************************************
2924 * EndPagePrinter [WINSPOOL.@]
2926 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2928 FIXME("(%p): stub\n", hPrinter);
2929 return TRUE;
2932 /*****************************************************************************
2933 * StartDocPrinterA [WINSPOOL.@]
2935 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2937 UNICODE_STRING usBuffer;
2938 DOC_INFO_2W doc2W;
2939 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2940 DWORD ret;
2942 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2943 or one (DOC_INFO_3) extra DWORDs */
2945 switch(Level) {
2946 case 2:
2947 doc2W.JobId = doc2->JobId;
2948 /* fall through */
2949 case 3:
2950 doc2W.dwMode = doc2->dwMode;
2951 /* fall through */
2952 case 1:
2953 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2954 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2955 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2956 break;
2958 default:
2959 SetLastError(ERROR_INVALID_LEVEL);
2960 return FALSE;
2963 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2965 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2966 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2967 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2969 return ret;
2972 /*****************************************************************************
2973 * StartDocPrinterW [WINSPOOL.@]
2975 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2977 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2978 opened_printer_t *printer;
2979 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2980 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2981 JOB_INFO_1W job_info;
2982 DWORD needed, ret = 0;
2983 HANDLE hf;
2984 WCHAR *filename;
2985 job_t *job;
2987 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2988 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2989 debugstr_w(doc->pDatatype));
2991 if(Level < 1 || Level > 3)
2993 SetLastError(ERROR_INVALID_LEVEL);
2994 return 0;
2997 EnterCriticalSection(&printer_handles_cs);
2998 printer = get_opened_printer(hPrinter);
2999 if(!printer)
3001 SetLastError(ERROR_INVALID_HANDLE);
3002 goto end;
3005 if(printer->doc)
3007 SetLastError(ERROR_INVALID_PRINTER_STATE);
3008 goto end;
3011 /* Even if we're printing to a file we still add a print job, we'll
3012 just ignore the spool file name */
3014 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3016 ERR("AddJob failed gle %u\n", GetLastError());
3017 goto end;
3020 /* use pOutputFile only, when it is a real filename */
3021 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3022 filename = doc->pOutputFile;
3023 else
3024 filename = addjob->Path;
3026 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3027 if(hf == INVALID_HANDLE_VALUE)
3028 goto end;
3030 memset(&job_info, 0, sizeof(job_info));
3031 job_info.pDocument = doc->pDocName;
3032 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3034 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3035 printer->doc->hf = hf;
3036 ret = printer->doc->job_id = addjob->JobId;
3037 job = get_job(hPrinter, ret);
3038 job->portname = strdupW(doc->pOutputFile);
3040 end:
3041 LeaveCriticalSection(&printer_handles_cs);
3043 return ret;
3046 /*****************************************************************************
3047 * StartPagePrinter [WINSPOOL.@]
3049 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3051 FIXME("(%p): stub\n", hPrinter);
3052 return TRUE;
3055 /*****************************************************************************
3056 * GetFormA [WINSPOOL.@]
3058 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3059 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3061 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3062 Level,pForm,cbBuf,pcbNeeded);
3063 return FALSE;
3066 /*****************************************************************************
3067 * GetFormW [WINSPOOL.@]
3069 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3070 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3072 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3073 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3074 return FALSE;
3077 /*****************************************************************************
3078 * SetFormA [WINSPOOL.@]
3080 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3081 LPBYTE pForm)
3083 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3084 return FALSE;
3087 /*****************************************************************************
3088 * SetFormW [WINSPOOL.@]
3090 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3091 LPBYTE pForm)
3093 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3094 return FALSE;
3097 /*****************************************************************************
3098 * ReadPrinter [WINSPOOL.@]
3100 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3101 LPDWORD pNoBytesRead)
3103 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3104 return FALSE;
3107 /*****************************************************************************
3108 * ResetPrinterA [WINSPOOL.@]
3110 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3112 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3113 return FALSE;
3116 /*****************************************************************************
3117 * ResetPrinterW [WINSPOOL.@]
3119 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3121 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3122 return FALSE;
3125 /*****************************************************************************
3126 * WINSPOOL_GetDWORDFromReg
3128 * Return DWORD associated with ValueName from hkey.
3130 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3132 DWORD sz = sizeof(DWORD), type, value = 0;
3133 LONG ret;
3135 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3137 if(ret != ERROR_SUCCESS) {
3138 WARN("Got ret = %d on name %s\n", ret, ValueName);
3139 return 0;
3141 if(type != REG_DWORD) {
3142 ERR("Got type %d\n", type);
3143 return 0;
3145 return value;
3149 /*****************************************************************************
3150 * get_filename_from_reg [internal]
3152 * Get ValueName from hkey storing result in out
3153 * when the Value in the registry has only a filename, use driverdir as prefix
3154 * outlen is space left in out
3155 * String is stored either as unicode or ascii
3159 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3160 LPBYTE out, DWORD outlen, LPDWORD needed)
3162 WCHAR filename[MAX_PATH];
3163 DWORD size;
3164 DWORD type;
3165 LONG ret;
3166 LPWSTR buffer = filename;
3167 LPWSTR ptr;
3169 *needed = 0;
3170 size = sizeof(filename);
3171 buffer[0] = '\0';
3172 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3173 if (ret == ERROR_MORE_DATA) {
3174 TRACE("need dynamic buffer: %u\n", size);
3175 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3176 if (!buffer) {
3177 /* No Memory is bad */
3178 return FALSE;
3180 buffer[0] = '\0';
3181 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3184 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3185 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3186 return FALSE;
3189 ptr = buffer;
3190 while (ptr) {
3191 /* do we have a full path ? */
3192 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3193 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3195 if (!ret) {
3196 /* we must build the full Path */
3197 *needed += dirlen;
3198 if ((out) && (outlen > dirlen)) {
3199 lstrcpyW((LPWSTR)out, driverdir);
3200 out += dirlen;
3201 outlen -= dirlen;
3203 else
3204 out = NULL;
3207 /* write the filename */
3208 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3209 if ((out) && (outlen >= size)) {
3210 lstrcpyW((LPWSTR)out, ptr);
3211 out += size;
3212 outlen -= size;
3214 else
3215 out = NULL;
3216 *needed += size;
3217 ptr += lstrlenW(ptr)+1;
3218 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3221 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3223 /* write the multisz-termination */
3224 if (type == REG_MULTI_SZ) {
3225 size = sizeof(WCHAR);
3227 *needed += size;
3228 if (out && (outlen >= size)) {
3229 memset (out, 0, size);
3232 return TRUE;
3235 /*****************************************************************************
3236 * WINSPOOL_GetStringFromReg
3238 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3239 * String is stored as unicode.
3241 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3242 DWORD buflen, DWORD *needed)
3244 DWORD sz = buflen, type;
3245 LONG ret;
3247 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3248 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3249 WARN("Got ret = %d\n", ret);
3250 *needed = 0;
3251 return FALSE;
3253 /* add space for terminating '\0' */
3254 sz += sizeof(WCHAR);
3255 *needed = sz;
3257 if (ptr)
3258 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3260 return TRUE;
3263 /*****************************************************************************
3264 * WINSPOOL_GetDefaultDevMode
3266 * Get a default DevMode values for wineps.
3267 * FIXME - use ppd.
3270 static void WINSPOOL_GetDefaultDevMode(
3271 LPBYTE ptr,
3272 DWORD buflen, DWORD *needed)
3274 DEVMODEW dm;
3275 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3277 /* fill default DEVMODE - should be read from ppd... */
3278 ZeroMemory( &dm, sizeof(dm) );
3279 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3280 dm.dmSpecVersion = DM_SPECVERSION;
3281 dm.dmDriverVersion = 1;
3282 dm.dmSize = sizeof(DEVMODEW);
3283 dm.dmDriverExtra = 0;
3284 dm.dmFields =
3285 DM_ORIENTATION | DM_PAPERSIZE |
3286 DM_PAPERLENGTH | DM_PAPERWIDTH |
3287 DM_SCALE |
3288 DM_COPIES |
3289 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3290 DM_YRESOLUTION | DM_TTOPTION;
3292 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3293 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3294 dm.u1.s1.dmPaperLength = 2970;
3295 dm.u1.s1.dmPaperWidth = 2100;
3297 dm.u1.s1.dmScale = 100;
3298 dm.u1.s1.dmCopies = 1;
3299 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3300 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3301 /* dm.dmColor */
3302 /* dm.dmDuplex */
3303 dm.dmYResolution = 300; /* 300dpi */
3304 dm.dmTTOption = DMTT_BITMAP;
3305 /* dm.dmCollate */
3306 /* dm.dmFormName */
3307 /* dm.dmLogPixels */
3308 /* dm.dmBitsPerPel */
3309 /* dm.dmPelsWidth */
3310 /* dm.dmPelsHeight */
3311 /* dm.u2.dmDisplayFlags */
3312 /* dm.dmDisplayFrequency */
3313 /* dm.dmICMMethod */
3314 /* dm.dmICMIntent */
3315 /* dm.dmMediaType */
3316 /* dm.dmDitherType */
3317 /* dm.dmReserved1 */
3318 /* dm.dmReserved2 */
3319 /* dm.dmPanningWidth */
3320 /* dm.dmPanningHeight */
3322 if(buflen >= sizeof(DEVMODEW))
3323 memcpy(ptr, &dm, sizeof(DEVMODEW));
3324 *needed = sizeof(DEVMODEW);
3327 /*****************************************************************************
3328 * WINSPOOL_GetDevModeFromReg
3330 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3331 * DevMode is stored either as unicode or ascii.
3333 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3334 LPBYTE ptr,
3335 DWORD buflen, DWORD *needed)
3337 DWORD sz = buflen, type;
3338 LONG ret;
3340 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3341 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3342 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3343 if (sz < sizeof(DEVMODEA))
3345 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3346 return FALSE;
3348 /* ensures that dmSize is not erratically bogus if registry is invalid */
3349 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3350 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3351 sz += (CCHDEVICENAME + CCHFORMNAME);
3352 if (ptr && (buflen >= sz)) {
3353 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3354 memcpy(ptr, dmW, sz);
3355 HeapFree(GetProcessHeap(),0,dmW);
3357 *needed = sz;
3358 return TRUE;
3361 /*********************************************************************
3362 * WINSPOOL_GetPrinter_1
3364 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3366 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3367 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3369 DWORD size, left = cbBuf;
3370 BOOL space = (cbBuf > 0);
3371 LPBYTE ptr = buf;
3373 *pcbNeeded = 0;
3375 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3376 if(space && size <= left) {
3377 pi1->pName = (LPWSTR)ptr;
3378 ptr += size;
3379 left -= size;
3380 } else
3381 space = FALSE;
3382 *pcbNeeded += size;
3385 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3386 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3387 if(space && size <= left) {
3388 pi1->pDescription = (LPWSTR)ptr;
3389 ptr += size;
3390 left -= size;
3391 } else
3392 space = FALSE;
3393 *pcbNeeded += size;
3396 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3397 if(space && size <= left) {
3398 pi1->pComment = (LPWSTR)ptr;
3399 ptr += size;
3400 left -= size;
3401 } else
3402 space = FALSE;
3403 *pcbNeeded += size;
3406 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3408 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3409 memset(pi1, 0, sizeof(*pi1));
3411 return space;
3413 /*********************************************************************
3414 * WINSPOOL_GetPrinter_2
3416 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3418 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3419 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3421 DWORD size, left = cbBuf;
3422 BOOL space = (cbBuf > 0);
3423 LPBYTE ptr = buf;
3425 *pcbNeeded = 0;
3427 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3428 if(space && size <= left) {
3429 pi2->pPrinterName = (LPWSTR)ptr;
3430 ptr += size;
3431 left -= size;
3432 } else
3433 space = FALSE;
3434 *pcbNeeded += size;
3436 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3437 if(space && size <= left) {
3438 pi2->pShareName = (LPWSTR)ptr;
3439 ptr += size;
3440 left -= size;
3441 } else
3442 space = FALSE;
3443 *pcbNeeded += size;
3445 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3446 if(space && size <= left) {
3447 pi2->pPortName = (LPWSTR)ptr;
3448 ptr += size;
3449 left -= size;
3450 } else
3451 space = FALSE;
3452 *pcbNeeded += size;
3454 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3455 if(space && size <= left) {
3456 pi2->pDriverName = (LPWSTR)ptr;
3457 ptr += size;
3458 left -= size;
3459 } else
3460 space = FALSE;
3461 *pcbNeeded += size;
3463 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3464 if(space && size <= left) {
3465 pi2->pComment = (LPWSTR)ptr;
3466 ptr += size;
3467 left -= size;
3468 } else
3469 space = FALSE;
3470 *pcbNeeded += size;
3472 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3473 if(space && size <= left) {
3474 pi2->pLocation = (LPWSTR)ptr;
3475 ptr += size;
3476 left -= size;
3477 } else
3478 space = FALSE;
3479 *pcbNeeded += size;
3481 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3482 if(space && size <= left) {
3483 pi2->pDevMode = (LPDEVMODEW)ptr;
3484 ptr += size;
3485 left -= size;
3486 } else
3487 space = FALSE;
3488 *pcbNeeded += size;
3490 else
3492 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3493 if(space && size <= left) {
3494 pi2->pDevMode = (LPDEVMODEW)ptr;
3495 ptr += size;
3496 left -= size;
3497 } else
3498 space = FALSE;
3499 *pcbNeeded += size;
3501 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3502 if(space && size <= left) {
3503 pi2->pSepFile = (LPWSTR)ptr;
3504 ptr += size;
3505 left -= size;
3506 } else
3507 space = FALSE;
3508 *pcbNeeded += size;
3510 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3511 if(space && size <= left) {
3512 pi2->pPrintProcessor = (LPWSTR)ptr;
3513 ptr += size;
3514 left -= size;
3515 } else
3516 space = FALSE;
3517 *pcbNeeded += size;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3520 if(space && size <= left) {
3521 pi2->pDatatype = (LPWSTR)ptr;
3522 ptr += size;
3523 left -= size;
3524 } else
3525 space = FALSE;
3526 *pcbNeeded += size;
3528 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3529 if(space && size <= left) {
3530 pi2->pParameters = (LPWSTR)ptr;
3531 ptr += size;
3532 left -= size;
3533 } else
3534 space = FALSE;
3535 *pcbNeeded += size;
3537 if(pi2) {
3538 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3539 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3540 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3541 "Default Priority");
3542 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3543 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3546 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3547 memset(pi2, 0, sizeof(*pi2));
3549 return space;
3552 /*********************************************************************
3553 * WINSPOOL_GetPrinter_4
3555 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3557 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3558 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3560 DWORD size, left = cbBuf;
3561 BOOL space = (cbBuf > 0);
3562 LPBYTE ptr = buf;
3564 *pcbNeeded = 0;
3566 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3567 if(space && size <= left) {
3568 pi4->pPrinterName = (LPWSTR)ptr;
3569 ptr += size;
3570 left -= size;
3571 } else
3572 space = FALSE;
3573 *pcbNeeded += size;
3575 if(pi4) {
3576 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3579 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3580 memset(pi4, 0, sizeof(*pi4));
3582 return space;
3585 /*********************************************************************
3586 * WINSPOOL_GetPrinter_5
3588 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3590 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3591 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3593 DWORD size, left = cbBuf;
3594 BOOL space = (cbBuf > 0);
3595 LPBYTE ptr = buf;
3597 *pcbNeeded = 0;
3599 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3600 if(space && size <= left) {
3601 pi5->pPrinterName = (LPWSTR)ptr;
3602 ptr += size;
3603 left -= size;
3604 } else
3605 space = FALSE;
3606 *pcbNeeded += size;
3608 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3609 if(space && size <= left) {
3610 pi5->pPortName = (LPWSTR)ptr;
3611 ptr += size;
3612 left -= size;
3613 } else
3614 space = FALSE;
3615 *pcbNeeded += size;
3617 if(pi5) {
3618 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3619 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3620 "dnsTimeout");
3621 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3622 "txTimeout");
3625 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3626 memset(pi5, 0, sizeof(*pi5));
3628 return space;
3631 /*********************************************************************
3632 * WINSPOOL_GetPrinter_7
3634 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3636 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3637 DWORD cbBuf, LPDWORD pcbNeeded)
3639 DWORD size, left = cbBuf;
3640 BOOL space = (cbBuf > 0);
3641 LPBYTE ptr = buf;
3643 *pcbNeeded = 0;
3645 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3647 ptr = NULL;
3648 size = sizeof(pi7->pszObjectGUID);
3650 if (space && size <= left) {
3651 pi7->pszObjectGUID = (LPWSTR)ptr;
3652 ptr += size;
3653 left -= size;
3654 } else
3655 space = FALSE;
3656 *pcbNeeded += size;
3657 if (pi7) {
3658 /* We do not have a Directory Service */
3659 pi7->dwAction = DSPRINT_UNPUBLISH;
3662 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3663 memset(pi7, 0, sizeof(*pi7));
3665 return space;
3668 /*********************************************************************
3669 * WINSPOOL_GetPrinter_9
3671 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3673 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3674 DWORD cbBuf, LPDWORD pcbNeeded)
3676 DWORD size;
3677 BOOL space = (cbBuf > 0);
3679 *pcbNeeded = 0;
3681 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3682 if(space && size <= cbBuf) {
3683 pi9->pDevMode = (LPDEVMODEW)buf;
3684 } else
3685 space = FALSE;
3686 *pcbNeeded += size;
3688 else
3690 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3691 if(space && size <= cbBuf) {
3692 pi9->pDevMode = (LPDEVMODEW)buf;
3693 } else
3694 space = FALSE;
3695 *pcbNeeded += size;
3698 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3699 memset(pi9, 0, sizeof(*pi9));
3701 return space;
3704 /*****************************************************************************
3705 * GetPrinterW [WINSPOOL.@]
3707 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3708 DWORD cbBuf, LPDWORD pcbNeeded)
3710 LPCWSTR name;
3711 DWORD size, needed = 0;
3712 LPBYTE ptr = NULL;
3713 HKEY hkeyPrinter, hkeyPrinters;
3714 BOOL ret;
3716 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3718 if (!(name = get_opened_printer_name(hPrinter))) {
3719 SetLastError(ERROR_INVALID_HANDLE);
3720 return FALSE;
3723 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3724 ERROR_SUCCESS) {
3725 ERR("Can't create Printers key\n");
3726 return FALSE;
3728 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3730 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3731 RegCloseKey(hkeyPrinters);
3732 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3733 return FALSE;
3736 switch(Level) {
3737 case 2:
3739 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3741 size = sizeof(PRINTER_INFO_2W);
3742 if(size <= cbBuf) {
3743 ptr = pPrinter + size;
3744 cbBuf -= size;
3745 memset(pPrinter, 0, size);
3746 } else {
3747 pi2 = NULL;
3748 cbBuf = 0;
3750 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3751 needed += size;
3752 break;
3755 case 4:
3757 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3759 size = sizeof(PRINTER_INFO_4W);
3760 if(size <= cbBuf) {
3761 ptr = pPrinter + size;
3762 cbBuf -= size;
3763 memset(pPrinter, 0, size);
3764 } else {
3765 pi4 = NULL;
3766 cbBuf = 0;
3768 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3769 needed += size;
3770 break;
3774 case 5:
3776 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3778 size = sizeof(PRINTER_INFO_5W);
3779 if(size <= cbBuf) {
3780 ptr = pPrinter + size;
3781 cbBuf -= size;
3782 memset(pPrinter, 0, size);
3783 } else {
3784 pi5 = NULL;
3785 cbBuf = 0;
3788 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3789 needed += size;
3790 break;
3794 case 6:
3796 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3798 size = sizeof(PRINTER_INFO_6);
3799 if (size <= cbBuf) {
3800 /* FIXME: We do not update the status yet */
3801 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3802 ret = TRUE;
3803 } else {
3804 ret = FALSE;
3807 needed += size;
3808 break;
3811 case 7:
3813 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3815 size = sizeof(PRINTER_INFO_7W);
3816 if (size <= cbBuf) {
3817 ptr = pPrinter + size;
3818 cbBuf -= size;
3819 memset(pPrinter, 0, size);
3820 } else {
3821 pi7 = NULL;
3822 cbBuf = 0;
3825 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3826 needed += size;
3827 break;
3831 case 9:
3833 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3835 size = sizeof(PRINTER_INFO_9W);
3836 if(size <= cbBuf) {
3837 ptr = pPrinter + size;
3838 cbBuf -= size;
3839 memset(pPrinter, 0, size);
3840 } else {
3841 pi9 = NULL;
3842 cbBuf = 0;
3845 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3846 needed += size;
3847 break;
3851 default:
3852 FIXME("Unimplemented level %d\n", Level);
3853 SetLastError(ERROR_INVALID_LEVEL);
3854 RegCloseKey(hkeyPrinters);
3855 RegCloseKey(hkeyPrinter);
3856 return FALSE;
3859 RegCloseKey(hkeyPrinter);
3860 RegCloseKey(hkeyPrinters);
3862 TRACE("returning %d needed = %d\n", ret, needed);
3863 if(pcbNeeded) *pcbNeeded = needed;
3864 if(!ret)
3865 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3866 return ret;
3869 /*****************************************************************************
3870 * GetPrinterA [WINSPOOL.@]
3872 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3873 DWORD cbBuf, LPDWORD pcbNeeded)
3875 BOOL ret;
3876 LPBYTE buf = NULL;
3878 if (cbBuf)
3879 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3881 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3882 if (ret)
3883 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3884 HeapFree(GetProcessHeap(), 0, buf);
3886 return ret;
3889 /*****************************************************************************
3890 * WINSPOOL_EnumPrintersW
3892 * Implementation of EnumPrintersW
3894 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3895 DWORD dwLevel, LPBYTE lpbPrinters,
3896 DWORD cbBuf, LPDWORD lpdwNeeded,
3897 LPDWORD lpdwReturned)
3900 HKEY hkeyPrinters, hkeyPrinter;
3901 WCHAR PrinterName[255];
3902 DWORD needed = 0, number = 0;
3903 DWORD used, i, left;
3904 PBYTE pi, buf;
3906 if(lpbPrinters)
3907 memset(lpbPrinters, 0, cbBuf);
3908 if(lpdwReturned)
3909 *lpdwReturned = 0;
3910 if(lpdwNeeded)
3911 *lpdwNeeded = 0;
3913 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3914 if(dwType == PRINTER_ENUM_DEFAULT)
3915 return TRUE;
3917 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3918 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3919 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3920 if (!dwType) {
3921 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3922 return TRUE;
3927 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3928 FIXME("dwType = %08x\n", dwType);
3929 SetLastError(ERROR_INVALID_FLAGS);
3930 return FALSE;
3933 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3934 ERROR_SUCCESS) {
3935 ERR("Can't create Printers key\n");
3936 return FALSE;
3939 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3940 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3941 RegCloseKey(hkeyPrinters);
3942 ERR("Can't query Printers key\n");
3943 return FALSE;
3945 TRACE("Found %d printers\n", number);
3947 switch(dwLevel) {
3948 case 1:
3949 used = number * sizeof(PRINTER_INFO_1W);
3950 break;
3951 case 2:
3952 used = number * sizeof(PRINTER_INFO_2W);
3953 break;
3954 case 4:
3955 used = number * sizeof(PRINTER_INFO_4W);
3956 break;
3957 case 5:
3958 used = number * sizeof(PRINTER_INFO_5W);
3959 break;
3961 default:
3962 SetLastError(ERROR_INVALID_LEVEL);
3963 RegCloseKey(hkeyPrinters);
3964 return FALSE;
3966 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3968 for(i = 0; i < number; i++) {
3969 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3970 ERROR_SUCCESS) {
3971 ERR("Can't enum key number %d\n", i);
3972 RegCloseKey(hkeyPrinters);
3973 return FALSE;
3975 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3976 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3977 ERROR_SUCCESS) {
3978 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3979 RegCloseKey(hkeyPrinters);
3980 return FALSE;
3983 if(cbBuf > used) {
3984 buf = lpbPrinters + used;
3985 left = cbBuf - used;
3986 } else {
3987 buf = NULL;
3988 left = 0;
3991 switch(dwLevel) {
3992 case 1:
3993 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3994 left, &needed);
3995 used += needed;
3996 if(pi) pi += sizeof(PRINTER_INFO_1W);
3997 break;
3998 case 2:
3999 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4000 left, &needed);
4001 used += needed;
4002 if(pi) pi += sizeof(PRINTER_INFO_2W);
4003 break;
4004 case 4:
4005 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4006 left, &needed);
4007 used += needed;
4008 if(pi) pi += sizeof(PRINTER_INFO_4W);
4009 break;
4010 case 5:
4011 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4012 left, &needed);
4013 used += needed;
4014 if(pi) pi += sizeof(PRINTER_INFO_5W);
4015 break;
4016 default:
4017 ERR("Shouldn't be here!\n");
4018 RegCloseKey(hkeyPrinter);
4019 RegCloseKey(hkeyPrinters);
4020 return FALSE;
4022 RegCloseKey(hkeyPrinter);
4024 RegCloseKey(hkeyPrinters);
4026 if(lpdwNeeded)
4027 *lpdwNeeded = used;
4029 if(used > cbBuf) {
4030 if(lpbPrinters)
4031 memset(lpbPrinters, 0, cbBuf);
4032 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4033 return FALSE;
4035 if(lpdwReturned)
4036 *lpdwReturned = number;
4037 SetLastError(ERROR_SUCCESS);
4038 return TRUE;
4042 /******************************************************************
4043 * EnumPrintersW [WINSPOOL.@]
4045 * Enumerates the available printers, print servers and print
4046 * providers, depending on the specified flags, name and level.
4048 * RETURNS:
4050 * If level is set to 1:
4051 * Returns an array of PRINTER_INFO_1 data structures in the
4052 * lpbPrinters buffer.
4054 * If level is set to 2:
4055 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4056 * Returns an array of PRINTER_INFO_2 data structures in the
4057 * lpbPrinters buffer. Note that according to MSDN also an
4058 * OpenPrinter should be performed on every remote printer.
4060 * If level is set to 4 (officially WinNT only):
4061 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4062 * Fast: Only the registry is queried to retrieve printer names,
4063 * no connection to the driver is made.
4064 * Returns an array of PRINTER_INFO_4 data structures in the
4065 * lpbPrinters buffer.
4067 * If level is set to 5 (officially WinNT4/Win9x only):
4068 * Fast: Only the registry is queried to retrieve printer names,
4069 * no connection to the driver is made.
4070 * Returns an array of PRINTER_INFO_5 data structures in the
4071 * lpbPrinters buffer.
4073 * If level set to 3 or 6+:
4074 * returns zero (failure!)
4076 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4077 * for information.
4079 * BUGS:
4080 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4081 * - Only levels 2, 4 and 5 are implemented at the moment.
4082 * - 16-bit printer drivers are not enumerated.
4083 * - Returned amount of bytes used/needed does not match the real Windoze
4084 * implementation (as in this implementation, all strings are part
4085 * of the buffer, whereas Win32 keeps them somewhere else)
4086 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4088 * NOTE:
4089 * - In a regular Wine installation, no registry settings for printers
4090 * exist, which makes this function return an empty list.
4092 BOOL WINAPI EnumPrintersW(
4093 DWORD dwType, /* [in] Types of print objects to enumerate */
4094 LPWSTR lpszName, /* [in] name of objects to enumerate */
4095 DWORD dwLevel, /* [in] type of printer info structure */
4096 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4097 DWORD cbBuf, /* [in] max size of buffer in bytes */
4098 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4099 LPDWORD lpdwReturned /* [out] number of entries returned */
4102 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4103 lpdwNeeded, lpdwReturned);
4106 /******************************************************************
4107 * EnumPrintersA [WINSPOOL.@]
4109 * See EnumPrintersW
4112 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4113 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4115 BOOL ret;
4116 UNICODE_STRING pNameU;
4117 LPWSTR pNameW;
4118 LPBYTE pPrintersW;
4120 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4121 pPrinters, cbBuf, pcbNeeded, pcReturned);
4123 pNameW = asciitounicode(&pNameU, pName);
4125 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4126 MS Office need this */
4127 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4129 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4131 RtlFreeUnicodeString(&pNameU);
4132 if (ret) {
4133 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4135 HeapFree(GetProcessHeap(), 0, pPrintersW);
4136 return ret;
4139 /*****************************************************************************
4140 * WINSPOOL_GetDriverInfoFromReg [internal]
4142 * Enters the information from the registry into the DRIVER_INFO struct
4144 * RETURNS
4145 * zero if the printer driver does not exist in the registry
4146 * (only if Level > 1) otherwise nonzero
4148 static BOOL WINSPOOL_GetDriverInfoFromReg(
4149 HKEY hkeyDrivers,
4150 LPWSTR DriverName,
4151 const printenv_t * env,
4152 DWORD Level,
4153 LPBYTE ptr, /* DRIVER_INFO */
4154 LPBYTE pDriverStrings, /* strings buffer */
4155 DWORD cbBuf, /* size of string buffer */
4156 LPDWORD pcbNeeded) /* space needed for str. */
4158 DWORD size, tmp;
4159 HKEY hkeyDriver;
4160 WCHAR driverdir[MAX_PATH];
4161 DWORD dirlen;
4162 LPBYTE strPtr = pDriverStrings;
4163 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4165 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4166 debugstr_w(DriverName), env,
4167 Level, di, pDriverStrings, cbBuf);
4169 if (di) ZeroMemory(di, di_sizeof[Level]);
4171 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4172 if (*pcbNeeded <= cbBuf)
4173 strcpyW((LPWSTR)strPtr, DriverName);
4175 /* pName for level 1 has a different offset! */
4176 if (Level == 1) {
4177 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4178 return TRUE;
4181 /* .cVersion and .pName for level > 1 */
4182 if (di) {
4183 di->cVersion = env->driverversion;
4184 di->pName = (LPWSTR) strPtr;
4185 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4188 /* Reserve Space for the largest subdir and a Backslash*/
4189 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4190 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4191 /* Should never Fail */
4192 return FALSE;
4194 lstrcatW(driverdir, env->versionsubdir);
4195 lstrcatW(driverdir, backslashW);
4197 /* dirlen must not include the terminating zero */
4198 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4200 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4201 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4202 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4203 return FALSE;
4206 /* pEnvironment */
4207 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4209 *pcbNeeded += size;
4210 if (*pcbNeeded <= cbBuf) {
4211 lstrcpyW((LPWSTR)strPtr, env->envname);
4212 if (di) di->pEnvironment = (LPWSTR)strPtr;
4213 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4216 /* .pDriverPath is the Graphics rendering engine.
4217 The full Path is required to avoid a crash in some apps */
4218 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4219 *pcbNeeded += size;
4220 if (*pcbNeeded <= cbBuf)
4221 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4223 if (di) di->pDriverPath = (LPWSTR)strPtr;
4224 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4227 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4228 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4229 *pcbNeeded += size;
4230 if (*pcbNeeded <= cbBuf)
4231 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4233 if (di) di->pDataFile = (LPWSTR)strPtr;
4234 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4237 /* .pConfigFile is the Driver user Interface */
4238 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4239 *pcbNeeded += size;
4240 if (*pcbNeeded <= cbBuf)
4241 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4243 if (di) di->pConfigFile = (LPWSTR)strPtr;
4244 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4247 if (Level == 2 ) {
4248 RegCloseKey(hkeyDriver);
4249 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4250 return TRUE;
4253 if (Level == 5 ) {
4254 RegCloseKey(hkeyDriver);
4255 FIXME("level 5: incomplete\n");
4256 return TRUE;
4259 /* .pHelpFile */
4260 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4261 *pcbNeeded += size;
4262 if (*pcbNeeded <= cbBuf)
4263 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4265 if (di) di->pHelpFile = (LPWSTR)strPtr;
4266 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4269 /* .pDependentFiles */
4270 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4271 *pcbNeeded += size;
4272 if (*pcbNeeded <= cbBuf)
4273 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4275 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4276 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4278 else if (GetVersion() & 0x80000000) {
4279 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4280 size = 2 * sizeof(WCHAR);
4281 *pcbNeeded += size;
4282 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4284 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4285 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4288 /* .pMonitorName is the optional Language Monitor */
4289 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4290 *pcbNeeded += size;
4291 if (*pcbNeeded <= cbBuf)
4292 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4294 if (di) di->pMonitorName = (LPWSTR)strPtr;
4295 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4298 /* .pDefaultDataType */
4299 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4300 *pcbNeeded += size;
4301 if(*pcbNeeded <= cbBuf)
4302 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4304 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4305 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4308 if (Level == 3 ) {
4309 RegCloseKey(hkeyDriver);
4310 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4311 return TRUE;
4314 /* .pszzPreviousNames */
4315 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4316 *pcbNeeded += size;
4317 if(*pcbNeeded <= cbBuf)
4318 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4320 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4321 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4324 if (Level == 4 ) {
4325 RegCloseKey(hkeyDriver);
4326 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4327 return TRUE;
4330 /* support is missing, but not important enough for a FIXME */
4331 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4333 /* .pszMfgName */
4334 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4335 *pcbNeeded += size;
4336 if(*pcbNeeded <= cbBuf)
4337 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4339 if (di) di->pszMfgName = (LPWSTR)strPtr;
4340 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4343 /* .pszOEMUrl */
4344 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4345 *pcbNeeded += size;
4346 if(*pcbNeeded <= cbBuf)
4347 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4349 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4350 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4353 /* .pszHardwareID */
4354 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4355 *pcbNeeded += size;
4356 if(*pcbNeeded <= cbBuf)
4357 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4359 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4360 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4363 /* .pszProvider */
4364 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4365 *pcbNeeded += size;
4366 if(*pcbNeeded <= cbBuf)
4367 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4369 if (di) di->pszProvider = (LPWSTR)strPtr;
4370 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4373 if (Level == 6 ) {
4374 RegCloseKey(hkeyDriver);
4375 return TRUE;
4378 /* support is missing, but not important enough for a FIXME */
4379 TRACE("level 8: incomplete\n");
4381 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4382 RegCloseKey(hkeyDriver);
4383 return TRUE;
4386 /*****************************************************************************
4387 * GetPrinterDriverW [WINSPOOL.@]
4389 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4390 DWORD Level, LPBYTE pDriverInfo,
4391 DWORD cbBuf, LPDWORD pcbNeeded)
4393 LPCWSTR name;
4394 WCHAR DriverName[100];
4395 DWORD ret, type, size, needed = 0;
4396 LPBYTE ptr = NULL;
4397 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4398 const printenv_t * env;
4400 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4401 Level,pDriverInfo,cbBuf, pcbNeeded);
4403 if (cbBuf > 0)
4404 ZeroMemory(pDriverInfo, cbBuf);
4406 if (!(name = get_opened_printer_name(hPrinter))) {
4407 SetLastError(ERROR_INVALID_HANDLE);
4408 return FALSE;
4411 if (Level < 1 || Level == 7 || Level > 8) {
4412 SetLastError(ERROR_INVALID_LEVEL);
4413 return FALSE;
4416 env = validate_envW(pEnvironment);
4417 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4419 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4420 ERROR_SUCCESS) {
4421 ERR("Can't create Printers key\n");
4422 return FALSE;
4424 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4425 != ERROR_SUCCESS) {
4426 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4427 RegCloseKey(hkeyPrinters);
4428 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4429 return FALSE;
4431 size = sizeof(DriverName);
4432 DriverName[0] = 0;
4433 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4434 (LPBYTE)DriverName, &size);
4435 RegCloseKey(hkeyPrinter);
4436 RegCloseKey(hkeyPrinters);
4437 if(ret != ERROR_SUCCESS) {
4438 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4439 return FALSE;
4442 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4443 if(!hkeyDrivers) {
4444 ERR("Can't create Drivers key\n");
4445 return FALSE;
4448 size = di_sizeof[Level];
4449 if ((size <= cbBuf) && pDriverInfo)
4450 ptr = pDriverInfo + size;
4452 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4453 env, Level, pDriverInfo, ptr,
4454 (cbBuf < size) ? 0 : cbBuf - size,
4455 &needed)) {
4456 RegCloseKey(hkeyDrivers);
4457 return FALSE;
4460 RegCloseKey(hkeyDrivers);
4462 if(pcbNeeded) *pcbNeeded = size + needed;
4463 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4464 if(cbBuf >= size + needed) return TRUE;
4465 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4466 return FALSE;
4469 /*****************************************************************************
4470 * GetPrinterDriverA [WINSPOOL.@]
4472 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4473 DWORD Level, LPBYTE pDriverInfo,
4474 DWORD cbBuf, LPDWORD pcbNeeded)
4476 BOOL ret;
4477 UNICODE_STRING pEnvW;
4478 PWSTR pwstrEnvW;
4479 LPBYTE buf = NULL;
4481 if (cbBuf)
4483 ZeroMemory(pDriverInfo, cbBuf);
4484 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4487 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4488 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4489 cbBuf, pcbNeeded);
4490 if (ret)
4491 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4493 HeapFree(GetProcessHeap(), 0, buf);
4495 RtlFreeUnicodeString(&pEnvW);
4496 return ret;
4499 /*****************************************************************************
4500 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4502 * Return the PATH for the Printer-Drivers (UNICODE)
4504 * PARAMS
4505 * pName [I] Servername (NT only) or NULL (local Computer)
4506 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4507 * Level [I] Structure-Level (must be 1)
4508 * pDriverDirectory [O] PTR to Buffer that receives the Result
4509 * cbBuf [I] Size of Buffer at pDriverDirectory
4510 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4511 * required for pDriverDirectory
4513 * RETURNS
4514 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4515 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4516 * if cbBuf is too small
4518 * Native Values returned in pDriverDirectory on Success:
4519 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4520 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4521 *| win9x(Windows 4.0): "%winsysdir%"
4523 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4525 * FIXME
4526 *- Only NULL or "" is supported for pName
4529 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4530 DWORD Level, LPBYTE pDriverDirectory,
4531 DWORD cbBuf, LPDWORD pcbNeeded)
4533 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4534 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4536 if ((backend == NULL) && !load_backend()) return FALSE;
4538 if (Level != 1) {
4539 /* (Level != 1) is ignored in win9x */
4540 SetLastError(ERROR_INVALID_LEVEL);
4541 return FALSE;
4543 if (pcbNeeded == NULL) {
4544 /* (pcbNeeded == NULL) is ignored in win9x */
4545 SetLastError(RPC_X_NULL_REF_POINTER);
4546 return FALSE;
4549 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4550 pDriverDirectory, cbBuf, pcbNeeded);
4555 /*****************************************************************************
4556 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4558 * Return the PATH for the Printer-Drivers (ANSI)
4560 * See GetPrinterDriverDirectoryW.
4562 * NOTES
4563 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4566 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4567 DWORD Level, LPBYTE pDriverDirectory,
4568 DWORD cbBuf, LPDWORD pcbNeeded)
4570 UNICODE_STRING nameW, environmentW;
4571 BOOL ret;
4572 DWORD pcbNeededW;
4573 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4574 WCHAR *driverDirectoryW = NULL;
4576 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4577 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4579 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4581 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4582 else nameW.Buffer = NULL;
4583 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4584 else environmentW.Buffer = NULL;
4586 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4587 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4588 if (ret) {
4589 DWORD needed;
4590 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4591 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4592 if(pcbNeeded)
4593 *pcbNeeded = needed;
4594 ret = (needed <= cbBuf) ? TRUE : FALSE;
4595 } else
4596 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4598 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4600 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4601 RtlFreeUnicodeString(&environmentW);
4602 RtlFreeUnicodeString(&nameW);
4604 return ret;
4607 /*****************************************************************************
4608 * AddPrinterDriverA [WINSPOOL.@]
4610 * See AddPrinterDriverW.
4613 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4615 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4616 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4619 /******************************************************************************
4620 * AddPrinterDriverW (WINSPOOL.@)
4622 * Install a Printer Driver
4624 * PARAMS
4625 * pName [I] Servername or NULL (local Computer)
4626 * level [I] Level for the supplied DRIVER_INFO_*W struct
4627 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4629 * RESULTS
4630 * Success: TRUE
4631 * Failure: FALSE
4634 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4636 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4637 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4640 /*****************************************************************************
4641 * AddPrintProcessorA [WINSPOOL.@]
4643 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4644 LPSTR pPrintProcessorName)
4646 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4647 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4648 return FALSE;
4651 /*****************************************************************************
4652 * AddPrintProcessorW [WINSPOOL.@]
4654 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4655 LPWSTR pPrintProcessorName)
4657 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4658 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4659 return FALSE;
4662 /*****************************************************************************
4663 * AddPrintProvidorA [WINSPOOL.@]
4665 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4667 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4668 return FALSE;
4671 /*****************************************************************************
4672 * AddPrintProvidorW [WINSPOOL.@]
4674 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4676 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4677 return FALSE;
4680 /*****************************************************************************
4681 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4683 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4684 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4686 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4687 pDevModeOutput, pDevModeInput);
4688 return 0;
4691 /*****************************************************************************
4692 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4694 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4695 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4697 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4698 pDevModeOutput, pDevModeInput);
4699 return 0;
4702 /*****************************************************************************
4703 * PrinterProperties [WINSPOOL.@]
4705 * Displays a dialog to set the properties of the printer.
4707 * RETURNS
4708 * nonzero on success or zero on failure
4710 * BUGS
4711 * implemented as stub only
4713 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4714 HANDLE hPrinter /* [in] handle to printer object */
4716 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4717 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4718 return FALSE;
4721 /*****************************************************************************
4722 * EnumJobsA [WINSPOOL.@]
4725 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4726 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4727 LPDWORD pcReturned)
4729 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4730 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4732 if(pcbNeeded) *pcbNeeded = 0;
4733 if(pcReturned) *pcReturned = 0;
4734 return FALSE;
4738 /*****************************************************************************
4739 * EnumJobsW [WINSPOOL.@]
4742 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4743 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4744 LPDWORD pcReturned)
4746 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4747 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4749 if(pcbNeeded) *pcbNeeded = 0;
4750 if(pcReturned) *pcReturned = 0;
4751 return FALSE;
4754 /*****************************************************************************
4755 * WINSPOOL_EnumPrinterDrivers [internal]
4757 * Delivers information about all printer drivers installed on the
4758 * localhost or a given server
4760 * RETURNS
4761 * nonzero on success or zero on failure. If the buffer for the returned
4762 * information is too small the function will return an error
4764 * BUGS
4765 * - only implemented for localhost, foreign hosts will return an error
4767 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4768 DWORD Level, LPBYTE pDriverInfo,
4769 DWORD driver_index,
4770 DWORD cbBuf, LPDWORD pcbNeeded,
4771 LPDWORD pcFound, DWORD data_offset)
4773 { HKEY hkeyDrivers;
4774 DWORD i, size = 0;
4775 const printenv_t * env;
4777 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4778 debugstr_w(pName), debugstr_w(pEnvironment),
4779 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4781 env = validate_envW(pEnvironment);
4782 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4784 *pcFound = 0;
4786 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4787 if(!hkeyDrivers) {
4788 ERR("Can't open Drivers key\n");
4789 return FALSE;
4792 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4793 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4794 RegCloseKey(hkeyDrivers);
4795 ERR("Can't query Drivers key\n");
4796 return FALSE;
4798 TRACE("Found %d Drivers\n", *pcFound);
4800 /* get size of single struct
4801 * unicode and ascii structure have the same size
4803 size = di_sizeof[Level];
4805 if (data_offset == 0)
4806 data_offset = size * (*pcFound);
4807 *pcbNeeded = data_offset;
4809 for( i = 0; i < *pcFound; i++) {
4810 WCHAR DriverNameW[255];
4811 PBYTE table_ptr = NULL;
4812 PBYTE data_ptr = NULL;
4813 DWORD needed = 0;
4815 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4816 != ERROR_SUCCESS) {
4817 ERR("Can't enum key number %d\n", i);
4818 RegCloseKey(hkeyDrivers);
4819 return FALSE;
4822 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4823 table_ptr = pDriverInfo + (driver_index + i) * size;
4824 if (pDriverInfo && *pcbNeeded <= cbBuf)
4825 data_ptr = pDriverInfo + *pcbNeeded;
4827 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4828 env, Level, table_ptr, data_ptr,
4829 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4830 &needed)) {
4831 RegCloseKey(hkeyDrivers);
4832 return FALSE;
4835 *pcbNeeded += needed;
4838 RegCloseKey(hkeyDrivers);
4840 if(cbBuf < *pcbNeeded){
4841 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4842 return FALSE;
4845 return TRUE;
4848 /*****************************************************************************
4849 * EnumPrinterDriversW [WINSPOOL.@]
4851 * see function EnumPrinterDrivers for RETURNS, BUGS
4853 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4854 LPBYTE pDriverInfo, DWORD cbBuf,
4855 LPDWORD pcbNeeded, LPDWORD pcReturned)
4857 static const WCHAR allW[] = {'a','l','l',0};
4858 BOOL ret;
4859 DWORD found;
4861 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4863 SetLastError(RPC_X_NULL_REF_POINTER);
4864 return FALSE;
4867 /* check for local drivers */
4868 if((pName) && (pName[0])) {
4869 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4870 SetLastError(ERROR_ACCESS_DENIED);
4871 return FALSE;
4874 /* check input parameter */
4875 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4876 SetLastError(ERROR_INVALID_LEVEL);
4877 return FALSE;
4880 if(pDriverInfo && cbBuf > 0)
4881 memset( pDriverInfo, 0, cbBuf);
4883 /* Exception: pull all printers */
4884 if (pEnvironment && !strcmpW(pEnvironment, allW))
4886 DWORD i, needed, bufsize = cbBuf;
4887 DWORD total_needed = 0;
4888 DWORD total_found = 0;
4889 DWORD data_offset;
4891 /* Precompute the overall total; we need this to know
4892 where pointers end and data begins (i.e. data_offset) */
4893 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4895 needed = found = 0;
4896 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4897 NULL, 0, 0, &needed, &found, 0);
4898 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4899 total_needed += needed;
4900 total_found += found;
4903 data_offset = di_sizeof[Level] * total_found;
4905 *pcReturned = 0;
4906 *pcbNeeded = 0;
4907 total_found = 0;
4908 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4910 needed = found = 0;
4911 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4912 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4913 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4914 else if (ret)
4915 *pcReturned += found;
4916 *pcbNeeded = needed;
4917 data_offset = needed;
4918 total_found += found;
4920 return ret;
4923 /* Normal behavior */
4924 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4925 0, cbBuf, pcbNeeded, &found, 0);
4926 if (ret)
4927 *pcReturned = found;
4929 return ret;
4932 /*****************************************************************************
4933 * EnumPrinterDriversA [WINSPOOL.@]
4935 * see function EnumPrinterDrivers for RETURNS, BUGS
4937 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4938 LPBYTE pDriverInfo, DWORD cbBuf,
4939 LPDWORD pcbNeeded, LPDWORD pcReturned)
4941 BOOL ret;
4942 UNICODE_STRING pNameW, pEnvironmentW;
4943 PWSTR pwstrNameW, pwstrEnvironmentW;
4944 LPBYTE buf = NULL;
4946 if (cbBuf)
4947 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4949 pwstrNameW = asciitounicode(&pNameW, pName);
4950 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4952 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4953 buf, cbBuf, pcbNeeded, pcReturned);
4954 if (ret)
4955 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4957 HeapFree(GetProcessHeap(), 0, buf);
4959 RtlFreeUnicodeString(&pNameW);
4960 RtlFreeUnicodeString(&pEnvironmentW);
4962 return ret;
4965 /******************************************************************************
4966 * EnumPortsA (WINSPOOL.@)
4968 * See EnumPortsW.
4971 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4972 LPDWORD pcbNeeded, LPDWORD pcReturned)
4974 BOOL res;
4975 LPBYTE bufferW = NULL;
4976 LPWSTR nameW = NULL;
4977 DWORD needed = 0;
4978 DWORD numentries = 0;
4979 INT len;
4981 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4982 cbBuf, pcbNeeded, pcReturned);
4984 /* convert servername to unicode */
4985 if (pName) {
4986 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4987 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4988 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4990 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4991 needed = cbBuf * sizeof(WCHAR);
4992 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4993 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4995 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4996 if (pcbNeeded) needed = *pcbNeeded;
4997 /* HeapReAlloc return NULL, when bufferW was NULL */
4998 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4999 HeapAlloc(GetProcessHeap(), 0, needed);
5001 /* Try again with the large Buffer */
5002 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5004 needed = pcbNeeded ? *pcbNeeded : 0;
5005 numentries = pcReturned ? *pcReturned : 0;
5008 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5009 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5011 if (res) {
5012 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5013 DWORD entrysize = 0;
5014 DWORD index;
5015 LPSTR ptr;
5016 LPPORT_INFO_2W pi2w;
5017 LPPORT_INFO_2A pi2a;
5019 needed = 0;
5020 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5022 /* First pass: calculate the size for all Entries */
5023 pi2w = (LPPORT_INFO_2W) bufferW;
5024 pi2a = (LPPORT_INFO_2A) pPorts;
5025 index = 0;
5026 while (index < numentries) {
5027 index++;
5028 needed += entrysize; /* PORT_INFO_?A */
5029 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5031 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5032 NULL, 0, NULL, NULL);
5033 if (Level > 1) {
5034 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5035 NULL, 0, NULL, NULL);
5036 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5037 NULL, 0, NULL, NULL);
5039 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5040 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5041 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5044 /* check for errors and quit on failure */
5045 if (cbBuf < needed) {
5046 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5047 res = FALSE;
5048 goto cleanup;
5050 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5051 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5052 cbBuf -= len ; /* free Bytes in the user-Buffer */
5053 pi2w = (LPPORT_INFO_2W) bufferW;
5054 pi2a = (LPPORT_INFO_2A) pPorts;
5055 index = 0;
5056 /* Second Pass: Fill the User Buffer (if we have one) */
5057 while ((index < numentries) && pPorts) {
5058 index++;
5059 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5060 pi2a->pPortName = ptr;
5061 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5062 ptr, cbBuf , NULL, NULL);
5063 ptr += len;
5064 cbBuf -= len;
5065 if (Level > 1) {
5066 pi2a->pMonitorName = ptr;
5067 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5068 ptr, cbBuf, NULL, NULL);
5069 ptr += len;
5070 cbBuf -= len;
5072 pi2a->pDescription = ptr;
5073 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5074 ptr, cbBuf, NULL, NULL);
5075 ptr += len;
5076 cbBuf -= len;
5078 pi2a->fPortType = pi2w->fPortType;
5079 pi2a->Reserved = 0; /* documented: "must be zero" */
5082 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5083 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5084 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5088 cleanup:
5089 if (pcbNeeded) *pcbNeeded = needed;
5090 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5092 HeapFree(GetProcessHeap(), 0, nameW);
5093 HeapFree(GetProcessHeap(), 0, bufferW);
5095 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5096 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5098 return (res);
5102 /******************************************************************************
5103 * EnumPortsW (WINSPOOL.@)
5105 * Enumerate available Ports
5107 * PARAMS
5108 * pName [I] Servername or NULL (local Computer)
5109 * Level [I] Structure-Level (1 or 2)
5110 * pPorts [O] PTR to Buffer that receives the Result
5111 * cbBuf [I] Size of Buffer at pPorts
5112 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5113 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5115 * RETURNS
5116 * Success: TRUE
5117 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5120 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5123 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5124 cbBuf, pcbNeeded, pcReturned);
5126 if ((backend == NULL) && !load_backend()) return FALSE;
5128 /* Level is not checked in win9x */
5129 if (!Level || (Level > 2)) {
5130 WARN("level (%d) is ignored in win9x\n", Level);
5131 SetLastError(ERROR_INVALID_LEVEL);
5132 return FALSE;
5134 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5135 SetLastError(RPC_X_NULL_REF_POINTER);
5136 return FALSE;
5139 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5142 /******************************************************************************
5143 * GetDefaultPrinterW (WINSPOOL.@)
5145 * FIXME
5146 * This function must read the value from data 'device' of key
5147 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5149 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5151 BOOL retval = TRUE;
5152 DWORD insize, len;
5153 WCHAR *buffer, *ptr;
5155 if (!namesize)
5157 SetLastError(ERROR_INVALID_PARAMETER);
5158 return FALSE;
5161 /* make the buffer big enough for the stuff from the profile/registry,
5162 * the content must fit into the local buffer to compute the correct
5163 * size even if the extern buffer is too small or not given.
5164 * (20 for ,driver,port) */
5165 insize = *namesize;
5166 len = max(100, (insize + 20));
5167 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5169 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5171 SetLastError (ERROR_FILE_NOT_FOUND);
5172 retval = FALSE;
5173 goto end;
5175 TRACE("%s\n", debugstr_w(buffer));
5177 if ((ptr = strchrW(buffer, ',')) == NULL)
5179 SetLastError(ERROR_INVALID_NAME);
5180 retval = FALSE;
5181 goto end;
5184 *ptr = 0;
5185 *namesize = strlenW(buffer) + 1;
5186 if(!name || (*namesize > insize))
5188 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5189 retval = FALSE;
5190 goto end;
5192 strcpyW(name, buffer);
5194 end:
5195 HeapFree( GetProcessHeap(), 0, buffer);
5196 return retval;
5200 /******************************************************************************
5201 * GetDefaultPrinterA (WINSPOOL.@)
5203 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5205 BOOL retval = TRUE;
5206 DWORD insize = 0;
5207 WCHAR *bufferW = NULL;
5209 if (!namesize)
5211 SetLastError(ERROR_INVALID_PARAMETER);
5212 return FALSE;
5215 if(name && *namesize) {
5216 insize = *namesize;
5217 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5220 if(!GetDefaultPrinterW( bufferW, namesize)) {
5221 retval = FALSE;
5222 goto end;
5225 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5226 NULL, NULL);
5227 if (!*namesize)
5229 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5230 retval = FALSE;
5232 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5234 end:
5235 HeapFree( GetProcessHeap(), 0, bufferW);
5236 return retval;
5240 /******************************************************************************
5241 * SetDefaultPrinterW (WINSPOOL.204)
5243 * Set the Name of the Default Printer
5245 * PARAMS
5246 * pszPrinter [I] Name of the Printer or NULL
5248 * RETURNS
5249 * Success: True
5250 * Failure: FALSE
5252 * NOTES
5253 * When the Parameter is NULL or points to an Empty String and
5254 * a Default Printer was already present, then this Function changes nothing.
5255 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5256 * the First enumerated local Printer is used.
5259 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5262 TRACE("(%s)\n", debugstr_w(pszPrinter));
5264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5265 return FALSE;
5268 /******************************************************************************
5269 * SetDefaultPrinterA (WINSPOOL.202)
5271 * See SetDefaultPrinterW.
5274 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5277 TRACE("(%s)\n", debugstr_a(pszPrinter));
5279 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5280 return FALSE;
5284 /******************************************************************************
5285 * SetPrinterDataExA (WINSPOOL.@)
5287 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5288 LPCSTR pValueName, DWORD Type,
5289 LPBYTE pData, DWORD cbData)
5291 HKEY hkeyPrinter, hkeySubkey;
5292 DWORD ret;
5294 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5295 debugstr_a(pValueName), Type, pData, cbData);
5297 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5298 != ERROR_SUCCESS)
5299 return ret;
5301 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5302 != ERROR_SUCCESS) {
5303 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5304 RegCloseKey(hkeyPrinter);
5305 return ret;
5307 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5308 RegCloseKey(hkeySubkey);
5309 RegCloseKey(hkeyPrinter);
5310 return ret;
5313 /******************************************************************************
5314 * SetPrinterDataExW (WINSPOOL.@)
5316 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5317 LPCWSTR pValueName, DWORD Type,
5318 LPBYTE pData, DWORD cbData)
5320 HKEY hkeyPrinter, hkeySubkey;
5321 DWORD ret;
5323 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5324 debugstr_w(pValueName), Type, pData, cbData);
5326 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5327 != ERROR_SUCCESS)
5328 return ret;
5330 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5331 != ERROR_SUCCESS) {
5332 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5333 RegCloseKey(hkeyPrinter);
5334 return ret;
5336 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5337 RegCloseKey(hkeySubkey);
5338 RegCloseKey(hkeyPrinter);
5339 return ret;
5342 /******************************************************************************
5343 * SetPrinterDataA (WINSPOOL.@)
5345 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5346 LPBYTE pData, DWORD cbData)
5348 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5349 pData, cbData);
5352 /******************************************************************************
5353 * SetPrinterDataW (WINSPOOL.@)
5355 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5356 LPBYTE pData, DWORD cbData)
5358 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5359 pData, cbData);
5362 /******************************************************************************
5363 * GetPrinterDataExA (WINSPOOL.@)
5365 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5366 LPCSTR pValueName, LPDWORD pType,
5367 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5369 opened_printer_t *printer;
5370 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5371 DWORD ret;
5373 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5374 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5376 printer = get_opened_printer(hPrinter);
5377 if(!printer) return ERROR_INVALID_HANDLE;
5379 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5380 if (ret) return ret;
5382 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5384 if (printer->name) {
5386 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5387 if (ret) {
5388 RegCloseKey(hkeyPrinters);
5389 return ret;
5391 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5392 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5393 RegCloseKey(hkeyPrinter);
5394 RegCloseKey(hkeyPrinters);
5395 return ret;
5398 *pcbNeeded = nSize;
5399 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5400 0, pType, pData, pcbNeeded);
5402 if (!ret && !pData) ret = ERROR_MORE_DATA;
5404 RegCloseKey(hkeySubkey);
5405 RegCloseKey(hkeyPrinter);
5406 RegCloseKey(hkeyPrinters);
5408 TRACE("--> %d\n", ret);
5409 return ret;
5412 /******************************************************************************
5413 * GetPrinterDataExW (WINSPOOL.@)
5415 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5416 LPCWSTR pValueName, LPDWORD pType,
5417 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5419 opened_printer_t *printer;
5420 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5421 DWORD ret;
5423 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5424 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5426 printer = get_opened_printer(hPrinter);
5427 if(!printer) return ERROR_INVALID_HANDLE;
5429 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5430 if (ret) return ret;
5432 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5434 if (printer->name) {
5436 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5437 if (ret) {
5438 RegCloseKey(hkeyPrinters);
5439 return ret;
5441 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5442 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5443 RegCloseKey(hkeyPrinter);
5444 RegCloseKey(hkeyPrinters);
5445 return ret;
5448 *pcbNeeded = nSize;
5449 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5450 0, pType, pData, pcbNeeded);
5452 if (!ret && !pData) ret = ERROR_MORE_DATA;
5454 RegCloseKey(hkeySubkey);
5455 RegCloseKey(hkeyPrinter);
5456 RegCloseKey(hkeyPrinters);
5458 TRACE("--> %d\n", ret);
5459 return ret;
5462 /******************************************************************************
5463 * GetPrinterDataA (WINSPOOL.@)
5465 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5466 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5468 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5469 pData, nSize, pcbNeeded);
5472 /******************************************************************************
5473 * GetPrinterDataW (WINSPOOL.@)
5475 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5476 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5478 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5479 pData, nSize, pcbNeeded);
5482 /*******************************************************************************
5483 * EnumPrinterDataExW [WINSPOOL.@]
5485 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5486 LPBYTE pEnumValues, DWORD cbEnumValues,
5487 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5489 HKEY hkPrinter, hkSubKey;
5490 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5491 cbValueNameLen, cbMaxValueLen, cbValueLen,
5492 cbBufSize, dwType;
5493 LPWSTR lpValueName;
5494 HANDLE hHeap;
5495 PBYTE lpValue;
5496 PPRINTER_ENUM_VALUESW ppev;
5498 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5500 if (pKeyName == NULL || *pKeyName == 0)
5501 return ERROR_INVALID_PARAMETER;
5503 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5504 if (ret != ERROR_SUCCESS)
5506 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5507 hPrinter, ret);
5508 return ret;
5511 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5512 if (ret != ERROR_SUCCESS)
5514 r = RegCloseKey (hkPrinter);
5515 if (r != ERROR_SUCCESS)
5516 WARN ("RegCloseKey returned %i\n", r);
5517 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5518 debugstr_w (pKeyName), ret);
5519 return ret;
5522 ret = RegCloseKey (hkPrinter);
5523 if (ret != ERROR_SUCCESS)
5525 ERR ("RegCloseKey returned %i\n", ret);
5526 r = RegCloseKey (hkSubKey);
5527 if (r != ERROR_SUCCESS)
5528 WARN ("RegCloseKey returned %i\n", r);
5529 return ret;
5532 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5533 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5534 if (ret != ERROR_SUCCESS)
5536 r = RegCloseKey (hkSubKey);
5537 if (r != ERROR_SUCCESS)
5538 WARN ("RegCloseKey returned %i\n", r);
5539 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5540 return ret;
5543 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5544 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5546 if (cValues == 0) /* empty key */
5548 r = RegCloseKey (hkSubKey);
5549 if (r != ERROR_SUCCESS)
5550 WARN ("RegCloseKey returned %i\n", r);
5551 *pcbEnumValues = *pnEnumValues = 0;
5552 return ERROR_SUCCESS;
5555 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5557 hHeap = GetProcessHeap ();
5558 if (hHeap == NULL)
5560 ERR ("GetProcessHeap failed\n");
5561 r = RegCloseKey (hkSubKey);
5562 if (r != ERROR_SUCCESS)
5563 WARN ("RegCloseKey returned %i\n", r);
5564 return ERROR_OUTOFMEMORY;
5567 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5568 if (lpValueName == NULL)
5570 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5571 r = RegCloseKey (hkSubKey);
5572 if (r != ERROR_SUCCESS)
5573 WARN ("RegCloseKey returned %i\n", r);
5574 return ERROR_OUTOFMEMORY;
5577 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5578 if (lpValue == NULL)
5580 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5581 if (HeapFree (hHeap, 0, lpValueName) == 0)
5582 WARN ("HeapFree failed with code %i\n", GetLastError ());
5583 r = RegCloseKey (hkSubKey);
5584 if (r != ERROR_SUCCESS)
5585 WARN ("RegCloseKey returned %i\n", r);
5586 return ERROR_OUTOFMEMORY;
5589 TRACE ("pass 1: calculating buffer required for all names and values\n");
5591 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5593 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5595 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5597 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5598 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5599 NULL, NULL, lpValue, &cbValueLen);
5600 if (ret != ERROR_SUCCESS)
5602 if (HeapFree (hHeap, 0, lpValue) == 0)
5603 WARN ("HeapFree failed with code %i\n", GetLastError ());
5604 if (HeapFree (hHeap, 0, lpValueName) == 0)
5605 WARN ("HeapFree failed with code %i\n", GetLastError ());
5606 r = RegCloseKey (hkSubKey);
5607 if (r != ERROR_SUCCESS)
5608 WARN ("RegCloseKey returned %i\n", r);
5609 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5610 return ret;
5613 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5614 debugstr_w (lpValueName), dwIndex,
5615 cbValueNameLen + 1, cbValueLen);
5617 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5618 cbBufSize += cbValueLen;
5621 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5623 *pcbEnumValues = cbBufSize;
5624 *pnEnumValues = cValues;
5626 if (cbEnumValues < cbBufSize) /* buffer too small */
5628 if (HeapFree (hHeap, 0, lpValue) == 0)
5629 WARN ("HeapFree failed with code %i\n", GetLastError ());
5630 if (HeapFree (hHeap, 0, lpValueName) == 0)
5631 WARN ("HeapFree failed with code %i\n", GetLastError ());
5632 r = RegCloseKey (hkSubKey);
5633 if (r != ERROR_SUCCESS)
5634 WARN ("RegCloseKey returned %i\n", r);
5635 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5636 return ERROR_MORE_DATA;
5639 TRACE ("pass 2: copying all names and values to buffer\n");
5641 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5642 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5644 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5646 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5647 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5648 NULL, &dwType, lpValue, &cbValueLen);
5649 if (ret != ERROR_SUCCESS)
5651 if (HeapFree (hHeap, 0, lpValue) == 0)
5652 WARN ("HeapFree failed with code %i\n", GetLastError ());
5653 if (HeapFree (hHeap, 0, lpValueName) == 0)
5654 WARN ("HeapFree failed with code %i\n", GetLastError ());
5655 r = RegCloseKey (hkSubKey);
5656 if (r != ERROR_SUCCESS)
5657 WARN ("RegCloseKey returned %i\n", r);
5658 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5659 return ret;
5662 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5663 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5664 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5665 pEnumValues += cbValueNameLen;
5667 /* return # of *bytes* (including trailing \0), not # of chars */
5668 ppev[dwIndex].cbValueName = cbValueNameLen;
5670 ppev[dwIndex].dwType = dwType;
5672 memcpy (pEnumValues, lpValue, cbValueLen);
5673 ppev[dwIndex].pData = pEnumValues;
5674 pEnumValues += cbValueLen;
5676 ppev[dwIndex].cbData = cbValueLen;
5678 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5679 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5682 if (HeapFree (hHeap, 0, lpValue) == 0)
5684 ret = GetLastError ();
5685 ERR ("HeapFree failed with code %i\n", ret);
5686 if (HeapFree (hHeap, 0, lpValueName) == 0)
5687 WARN ("HeapFree failed with code %i\n", GetLastError ());
5688 r = RegCloseKey (hkSubKey);
5689 if (r != ERROR_SUCCESS)
5690 WARN ("RegCloseKey returned %i\n", r);
5691 return ret;
5694 if (HeapFree (hHeap, 0, lpValueName) == 0)
5696 ret = GetLastError ();
5697 ERR ("HeapFree failed with code %i\n", ret);
5698 r = RegCloseKey (hkSubKey);
5699 if (r != ERROR_SUCCESS)
5700 WARN ("RegCloseKey returned %i\n", r);
5701 return ret;
5704 ret = RegCloseKey (hkSubKey);
5705 if (ret != ERROR_SUCCESS)
5707 ERR ("RegCloseKey returned %i\n", ret);
5708 return ret;
5711 return ERROR_SUCCESS;
5714 /*******************************************************************************
5715 * EnumPrinterDataExA [WINSPOOL.@]
5717 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5718 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5719 * what Windows 2000 SP1 does.
5722 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5723 LPBYTE pEnumValues, DWORD cbEnumValues,
5724 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5726 INT len;
5727 LPWSTR pKeyNameW;
5728 DWORD ret, dwIndex, dwBufSize;
5729 HANDLE hHeap;
5730 LPSTR pBuffer;
5732 TRACE ("%p %s\n", hPrinter, pKeyName);
5734 if (pKeyName == NULL || *pKeyName == 0)
5735 return ERROR_INVALID_PARAMETER;
5737 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5738 if (len == 0)
5740 ret = GetLastError ();
5741 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5742 return ret;
5745 hHeap = GetProcessHeap ();
5746 if (hHeap == NULL)
5748 ERR ("GetProcessHeap failed\n");
5749 return ERROR_OUTOFMEMORY;
5752 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5753 if (pKeyNameW == NULL)
5755 ERR ("Failed to allocate %i bytes from process heap\n",
5756 (LONG)(len * sizeof (WCHAR)));
5757 return ERROR_OUTOFMEMORY;
5760 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5762 ret = GetLastError ();
5763 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5764 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5765 WARN ("HeapFree failed with code %i\n", GetLastError ());
5766 return ret;
5769 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5770 pcbEnumValues, pnEnumValues);
5771 if (ret != ERROR_SUCCESS)
5773 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5774 WARN ("HeapFree failed with code %i\n", GetLastError ());
5775 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5776 return ret;
5779 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5781 ret = GetLastError ();
5782 ERR ("HeapFree failed with code %i\n", ret);
5783 return ret;
5786 if (*pnEnumValues == 0) /* empty key */
5787 return ERROR_SUCCESS;
5789 dwBufSize = 0;
5790 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5792 PPRINTER_ENUM_VALUESW ppev =
5793 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5795 if (dwBufSize < ppev->cbValueName)
5796 dwBufSize = ppev->cbValueName;
5798 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5799 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5800 dwBufSize = ppev->cbData;
5803 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5805 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5806 if (pBuffer == NULL)
5808 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5809 return ERROR_OUTOFMEMORY;
5812 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5814 PPRINTER_ENUM_VALUESW ppev =
5815 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5817 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5818 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5819 NULL);
5820 if (len == 0)
5822 ret = GetLastError ();
5823 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5824 if (HeapFree (hHeap, 0, pBuffer) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5826 return ret;
5829 memcpy (ppev->pValueName, pBuffer, len);
5831 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5833 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5834 ppev->dwType != REG_MULTI_SZ)
5835 continue;
5837 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5838 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5839 if (len == 0)
5841 ret = GetLastError ();
5842 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5843 if (HeapFree (hHeap, 0, pBuffer) == 0)
5844 WARN ("HeapFree failed with code %i\n", GetLastError ());
5845 return ret;
5848 memcpy (ppev->pData, pBuffer, len);
5850 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5851 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5854 if (HeapFree (hHeap, 0, pBuffer) == 0)
5856 ret = GetLastError ();
5857 ERR ("HeapFree failed with code %i\n", ret);
5858 return ret;
5861 return ERROR_SUCCESS;
5864 /******************************************************************************
5865 * AbortPrinter (WINSPOOL.@)
5867 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5869 FIXME("(%p), stub!\n", hPrinter);
5870 return TRUE;
5873 /******************************************************************************
5874 * AddPortA (WINSPOOL.@)
5876 * See AddPortW.
5879 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5881 LPWSTR nameW = NULL;
5882 LPWSTR monitorW = NULL;
5883 DWORD len;
5884 BOOL res;
5886 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5888 if (pName) {
5889 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5890 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5891 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5894 if (pMonitorName) {
5895 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5896 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5897 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5899 res = AddPortW(nameW, hWnd, monitorW);
5900 HeapFree(GetProcessHeap(), 0, nameW);
5901 HeapFree(GetProcessHeap(), 0, monitorW);
5902 return res;
5905 /******************************************************************************
5906 * AddPortW (WINSPOOL.@)
5908 * Add a Port for a specific Monitor
5910 * PARAMS
5911 * pName [I] Servername or NULL (local Computer)
5912 * hWnd [I] Handle to parent Window for the Dialog-Box
5913 * pMonitorName [I] Name of the Monitor that manage the Port
5915 * RETURNS
5916 * Success: TRUE
5917 * Failure: FALSE
5920 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5922 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5924 if ((backend == NULL) && !load_backend()) return FALSE;
5926 if (!pMonitorName) {
5927 SetLastError(RPC_X_NULL_REF_POINTER);
5928 return FALSE;
5931 return backend->fpAddPort(pName, hWnd, pMonitorName);
5934 /******************************************************************************
5935 * AddPortExA (WINSPOOL.@)
5937 * See AddPortExW.
5940 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5942 PORT_INFO_2W pi2W;
5943 PORT_INFO_2A * pi2A;
5944 LPWSTR nameW = NULL;
5945 LPWSTR monitorW = NULL;
5946 DWORD len;
5947 BOOL res;
5949 pi2A = (PORT_INFO_2A *) pBuffer;
5951 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5952 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5954 if ((level < 1) || (level > 2)) {
5955 SetLastError(ERROR_INVALID_LEVEL);
5956 return FALSE;
5959 if (!pi2A) {
5960 SetLastError(ERROR_INVALID_PARAMETER);
5961 return FALSE;
5964 if (pName) {
5965 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5966 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5967 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5970 if (pMonitorName) {
5971 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5972 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5973 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5976 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5978 if (pi2A->pPortName) {
5979 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5980 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5981 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5984 if (level > 1) {
5985 if (pi2A->pMonitorName) {
5986 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5987 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5988 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5991 if (pi2A->pDescription) {
5992 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5993 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5994 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5996 pi2W.fPortType = pi2A->fPortType;
5997 pi2W.Reserved = pi2A->Reserved;
6000 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6002 HeapFree(GetProcessHeap(), 0, nameW);
6003 HeapFree(GetProcessHeap(), 0, monitorW);
6004 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6005 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6006 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6007 return res;
6011 /******************************************************************************
6012 * AddPortExW (WINSPOOL.@)
6014 * Add a Port for a specific Monitor, without presenting a user interface
6016 * PARAMS
6017 * pName [I] Servername or NULL (local Computer)
6018 * level [I] Structure-Level (1 or 2) for pBuffer
6019 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6020 * pMonitorName [I] Name of the Monitor that manage the Port
6022 * RETURNS
6023 * Success: TRUE
6024 * Failure: FALSE
6027 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6029 PORT_INFO_2W * pi2;
6031 pi2 = (PORT_INFO_2W *) pBuffer;
6033 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6034 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6035 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6036 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6038 if ((backend == NULL) && !load_backend()) return FALSE;
6040 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6041 SetLastError(ERROR_INVALID_PARAMETER);
6042 return FALSE;
6045 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6048 /******************************************************************************
6049 * AddPrinterConnectionA (WINSPOOL.@)
6051 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6053 FIXME("%s\n", debugstr_a(pName));
6054 return FALSE;
6057 /******************************************************************************
6058 * AddPrinterConnectionW (WINSPOOL.@)
6060 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6062 FIXME("%s\n", debugstr_w(pName));
6063 return FALSE;
6066 /******************************************************************************
6067 * AddPrinterDriverExW (WINSPOOL.@)
6069 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6071 * PARAMS
6072 * pName [I] Servername or NULL (local Computer)
6073 * level [I] Level for the supplied DRIVER_INFO_*W struct
6074 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6075 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6077 * RESULTS
6078 * Success: TRUE
6079 * Failure: FALSE
6082 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6084 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6086 if ((backend == NULL) && !load_backend()) return FALSE;
6088 if (level < 2 || level == 5 || level == 7 || level > 8) {
6089 SetLastError(ERROR_INVALID_LEVEL);
6090 return FALSE;
6093 if (!pDriverInfo) {
6094 SetLastError(ERROR_INVALID_PARAMETER);
6095 return FALSE;
6098 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6101 /******************************************************************************
6102 * AddPrinterDriverExA (WINSPOOL.@)
6104 * See AddPrinterDriverExW.
6107 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6109 DRIVER_INFO_8A *diA;
6110 DRIVER_INFO_8W diW;
6111 LPWSTR nameW = NULL;
6112 DWORD lenA;
6113 DWORD len;
6114 DWORD res = FALSE;
6116 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6118 diA = (DRIVER_INFO_8A *) pDriverInfo;
6119 ZeroMemory(&diW, sizeof(diW));
6121 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6122 SetLastError(ERROR_INVALID_LEVEL);
6123 return FALSE;
6126 if (diA == NULL) {
6127 SetLastError(ERROR_INVALID_PARAMETER);
6128 return FALSE;
6131 /* convert servername to unicode */
6132 if (pName) {
6133 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6134 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6135 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6138 /* common fields */
6139 diW.cVersion = diA->cVersion;
6141 if (diA->pName) {
6142 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6143 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6144 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6147 if (diA->pEnvironment) {
6148 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6149 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6150 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6153 if (diA->pDriverPath) {
6154 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6155 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6156 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6159 if (diA->pDataFile) {
6160 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6161 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6162 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6165 if (diA->pConfigFile) {
6166 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6167 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6168 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6171 if ((Level > 2) && diA->pDependentFiles) {
6172 lenA = multi_sz_lenA(diA->pDependentFiles);
6173 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6174 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6175 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6178 if ((Level > 2) && diA->pMonitorName) {
6179 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6180 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6181 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6184 if ((Level > 3) && diA->pDefaultDataType) {
6185 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6186 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6187 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6190 if ((Level > 3) && diA->pszzPreviousNames) {
6191 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6192 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6193 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6194 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6197 if ((Level > 5) && diA->pszMfgName) {
6198 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6199 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6200 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6203 if ((Level > 5) && diA->pszOEMUrl) {
6204 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6205 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6206 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6209 if ((Level > 5) && diA->pszHardwareID) {
6210 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6211 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6212 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6215 if ((Level > 5) && diA->pszProvider) {
6216 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6217 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6218 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6221 if (Level > 7) {
6222 FIXME("level %u is incomplete\n", Level);
6225 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6226 TRACE("got %u with %u\n", res, GetLastError());
6227 HeapFree(GetProcessHeap(), 0, nameW);
6228 HeapFree(GetProcessHeap(), 0, diW.pName);
6229 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6230 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6231 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6232 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6233 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6234 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6235 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6236 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6237 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6238 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6239 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6240 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6242 TRACE("=> %u with %u\n", res, GetLastError());
6243 return res;
6246 /******************************************************************************
6247 * ConfigurePortA (WINSPOOL.@)
6249 * See ConfigurePortW.
6252 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6254 LPWSTR nameW = NULL;
6255 LPWSTR portW = NULL;
6256 INT len;
6257 DWORD res;
6259 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6261 /* convert servername to unicode */
6262 if (pName) {
6263 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6264 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6265 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6268 /* convert portname to unicode */
6269 if (pPortName) {
6270 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6271 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6272 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6275 res = ConfigurePortW(nameW, hWnd, portW);
6276 HeapFree(GetProcessHeap(), 0, nameW);
6277 HeapFree(GetProcessHeap(), 0, portW);
6278 return res;
6281 /******************************************************************************
6282 * ConfigurePortW (WINSPOOL.@)
6284 * Display the Configuration-Dialog for a specific Port
6286 * PARAMS
6287 * pName [I] Servername or NULL (local Computer)
6288 * hWnd [I] Handle to parent Window for the Dialog-Box
6289 * pPortName [I] Name of the Port, that should be configured
6291 * RETURNS
6292 * Success: TRUE
6293 * Failure: FALSE
6296 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6299 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6301 if ((backend == NULL) && !load_backend()) return FALSE;
6303 if (!pPortName) {
6304 SetLastError(RPC_X_NULL_REF_POINTER);
6305 return FALSE;
6308 return backend->fpConfigurePort(pName, hWnd, pPortName);
6311 /******************************************************************************
6312 * ConnectToPrinterDlg (WINSPOOL.@)
6314 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6316 FIXME("%p %x\n", hWnd, Flags);
6317 return NULL;
6320 /******************************************************************************
6321 * DeletePrinterConnectionA (WINSPOOL.@)
6323 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6325 FIXME("%s\n", debugstr_a(pName));
6326 return TRUE;
6329 /******************************************************************************
6330 * DeletePrinterConnectionW (WINSPOOL.@)
6332 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6334 FIXME("%s\n", debugstr_w(pName));
6335 return TRUE;
6338 /******************************************************************************
6339 * DeletePrinterDriverExW (WINSPOOL.@)
6341 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6342 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6344 HKEY hkey_drivers;
6345 BOOL ret = FALSE;
6347 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6348 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6350 if(pName && pName[0])
6352 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6353 SetLastError(ERROR_INVALID_PARAMETER);
6354 return FALSE;
6357 if(dwDeleteFlag)
6359 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6360 SetLastError(ERROR_INVALID_PARAMETER);
6361 return FALSE;
6364 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6366 if(!hkey_drivers)
6368 ERR("Can't open drivers key\n");
6369 return FALSE;
6372 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6373 ret = TRUE;
6375 RegCloseKey(hkey_drivers);
6377 return ret;
6380 /******************************************************************************
6381 * DeletePrinterDriverExA (WINSPOOL.@)
6383 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6384 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6386 UNICODE_STRING NameW, EnvW, DriverW;
6387 BOOL ret;
6389 asciitounicode(&NameW, pName);
6390 asciitounicode(&EnvW, pEnvironment);
6391 asciitounicode(&DriverW, pDriverName);
6393 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6395 RtlFreeUnicodeString(&DriverW);
6396 RtlFreeUnicodeString(&EnvW);
6397 RtlFreeUnicodeString(&NameW);
6399 return ret;
6402 /******************************************************************************
6403 * DeletePrinterDataExW (WINSPOOL.@)
6405 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6406 LPCWSTR pValueName)
6408 FIXME("%p %s %s\n", hPrinter,
6409 debugstr_w(pKeyName), debugstr_w(pValueName));
6410 return ERROR_INVALID_PARAMETER;
6413 /******************************************************************************
6414 * DeletePrinterDataExA (WINSPOOL.@)
6416 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6417 LPCSTR pValueName)
6419 FIXME("%p %s %s\n", hPrinter,
6420 debugstr_a(pKeyName), debugstr_a(pValueName));
6421 return ERROR_INVALID_PARAMETER;
6424 /******************************************************************************
6425 * DeletePrintProcessorA (WINSPOOL.@)
6427 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6429 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6430 debugstr_a(pPrintProcessorName));
6431 return TRUE;
6434 /******************************************************************************
6435 * DeletePrintProcessorW (WINSPOOL.@)
6437 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6439 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6440 debugstr_w(pPrintProcessorName));
6441 return TRUE;
6444 /******************************************************************************
6445 * DeletePrintProvidorA (WINSPOOL.@)
6447 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6449 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6450 debugstr_a(pPrintProviderName));
6451 return TRUE;
6454 /******************************************************************************
6455 * DeletePrintProvidorW (WINSPOOL.@)
6457 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6459 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6460 debugstr_w(pPrintProviderName));
6461 return TRUE;
6464 /******************************************************************************
6465 * EnumFormsA (WINSPOOL.@)
6467 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6468 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6470 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6471 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6472 return FALSE;
6475 /******************************************************************************
6476 * EnumFormsW (WINSPOOL.@)
6478 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6479 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6481 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6482 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6483 return FALSE;
6486 /*****************************************************************************
6487 * EnumMonitorsA [WINSPOOL.@]
6489 * See EnumMonitorsW.
6492 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6493 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6495 BOOL res;
6496 LPBYTE bufferW = NULL;
6497 LPWSTR nameW = NULL;
6498 DWORD needed = 0;
6499 DWORD numentries = 0;
6500 INT len;
6502 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6503 cbBuf, pcbNeeded, pcReturned);
6505 /* convert servername to unicode */
6506 if (pName) {
6507 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6508 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6509 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6511 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6512 needed = cbBuf * sizeof(WCHAR);
6513 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6514 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6516 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6517 if (pcbNeeded) needed = *pcbNeeded;
6518 /* HeapReAlloc return NULL, when bufferW was NULL */
6519 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6520 HeapAlloc(GetProcessHeap(), 0, needed);
6522 /* Try again with the large Buffer */
6523 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6525 numentries = pcReturned ? *pcReturned : 0;
6526 needed = 0;
6528 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6529 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6531 if (res) {
6532 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6533 DWORD entrysize = 0;
6534 DWORD index;
6535 LPSTR ptr;
6536 LPMONITOR_INFO_2W mi2w;
6537 LPMONITOR_INFO_2A mi2a;
6539 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6540 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6542 /* First pass: calculate the size for all Entries */
6543 mi2w = (LPMONITOR_INFO_2W) bufferW;
6544 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6545 index = 0;
6546 while (index < numentries) {
6547 index++;
6548 needed += entrysize; /* MONITOR_INFO_?A */
6549 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6551 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6552 NULL, 0, NULL, NULL);
6553 if (Level > 1) {
6554 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6555 NULL, 0, NULL, NULL);
6556 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6557 NULL, 0, NULL, NULL);
6559 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6560 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6561 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6564 /* check for errors and quit on failure */
6565 if (cbBuf < needed) {
6566 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6567 res = FALSE;
6568 goto emA_cleanup;
6570 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6571 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6572 cbBuf -= len ; /* free Bytes in the user-Buffer */
6573 mi2w = (LPMONITOR_INFO_2W) bufferW;
6574 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6575 index = 0;
6576 /* Second Pass: Fill the User Buffer (if we have one) */
6577 while ((index < numentries) && pMonitors) {
6578 index++;
6579 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6580 mi2a->pName = ptr;
6581 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6582 ptr, cbBuf , NULL, NULL);
6583 ptr += len;
6584 cbBuf -= len;
6585 if (Level > 1) {
6586 mi2a->pEnvironment = ptr;
6587 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6588 ptr, cbBuf, NULL, NULL);
6589 ptr += len;
6590 cbBuf -= len;
6592 mi2a->pDLLName = ptr;
6593 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6594 ptr, cbBuf, NULL, NULL);
6595 ptr += len;
6596 cbBuf -= len;
6598 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6599 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6600 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6603 emA_cleanup:
6604 if (pcbNeeded) *pcbNeeded = needed;
6605 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6607 HeapFree(GetProcessHeap(), 0, nameW);
6608 HeapFree(GetProcessHeap(), 0, bufferW);
6610 TRACE("returning %d with %d (%d byte for %d entries)\n",
6611 (res), GetLastError(), needed, numentries);
6613 return (res);
6617 /*****************************************************************************
6618 * EnumMonitorsW [WINSPOOL.@]
6620 * Enumerate available Port-Monitors
6622 * PARAMS
6623 * pName [I] Servername or NULL (local Computer)
6624 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6625 * pMonitors [O] PTR to Buffer that receives the Result
6626 * cbBuf [I] Size of Buffer at pMonitors
6627 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6628 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6630 * RETURNS
6631 * Success: TRUE
6632 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6635 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6636 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6639 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6640 cbBuf, pcbNeeded, pcReturned);
6642 if ((backend == NULL) && !load_backend()) return FALSE;
6644 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6645 SetLastError(RPC_X_NULL_REF_POINTER);
6646 return FALSE;
6649 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6652 /******************************************************************************
6653 * SpoolerInit (WINSPOOL.@)
6655 * Initialize the Spooler
6657 * RETURNS
6658 * Success: TRUE
6659 * Failure: FALSE
6661 * NOTES
6662 * The function fails on windows, when the spooler service is not running
6665 BOOL WINAPI SpoolerInit(void)
6668 if ((backend == NULL) && !load_backend()) return FALSE;
6669 return TRUE;
6672 /******************************************************************************
6673 * XcvDataW (WINSPOOL.@)
6675 * Execute commands in the Printmonitor DLL
6677 * PARAMS
6678 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6679 * pszDataName [i] Name of the command to execute
6680 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6681 * cbInputData [i] Size in Bytes of Buffer at pInputData
6682 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6683 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6684 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6685 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6687 * RETURNS
6688 * Success: TRUE
6689 * Failure: FALSE
6691 * NOTES
6692 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6693 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6695 * Minimal List of commands, that a Printmonitor DLL should support:
6697 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6698 *| "AddPort" : Add a Port
6699 *| "DeletePort": Delete a Port
6701 * Many Printmonitors support additional commands. Examples for localspl.dll:
6702 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6703 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6706 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6707 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6708 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6710 opened_printer_t *printer;
6712 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6713 pInputData, cbInputData, pOutputData,
6714 cbOutputData, pcbOutputNeeded, pdwStatus);
6716 if ((backend == NULL) && !load_backend()) return FALSE;
6718 printer = get_opened_printer(hXcv);
6719 if (!printer || (!printer->backend_printer)) {
6720 SetLastError(ERROR_INVALID_HANDLE);
6721 return FALSE;
6724 if (!pcbOutputNeeded) {
6725 SetLastError(ERROR_INVALID_PARAMETER);
6726 return FALSE;
6729 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6730 SetLastError(RPC_X_NULL_REF_POINTER);
6731 return FALSE;
6734 *pcbOutputNeeded = 0;
6736 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6737 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6741 /*****************************************************************************
6742 * EnumPrinterDataA [WINSPOOL.@]
6745 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6746 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6747 DWORD cbData, LPDWORD pcbData )
6749 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6750 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6751 return ERROR_NO_MORE_ITEMS;
6754 /*****************************************************************************
6755 * EnumPrinterDataW [WINSPOOL.@]
6758 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6759 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6760 DWORD cbData, LPDWORD pcbData )
6762 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6763 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6764 return ERROR_NO_MORE_ITEMS;
6767 /*****************************************************************************
6768 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6771 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6772 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6773 LPDWORD pcbNeeded, LPDWORD pcReturned)
6775 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6776 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6777 pcbNeeded, pcReturned);
6778 return FALSE;
6781 /*****************************************************************************
6782 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6785 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6786 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6787 LPDWORD pcbNeeded, LPDWORD pcReturned)
6789 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6790 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6791 pcbNeeded, pcReturned);
6792 return FALSE;
6795 /*****************************************************************************
6796 * EnumPrintProcessorsA [WINSPOOL.@]
6798 * See EnumPrintProcessorsW.
6801 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6802 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6804 BOOL res;
6805 LPBYTE bufferW = NULL;
6806 LPWSTR nameW = NULL;
6807 LPWSTR envW = NULL;
6808 DWORD needed = 0;
6809 DWORD numentries = 0;
6810 INT len;
6812 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6813 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6815 /* convert names to unicode */
6816 if (pName) {
6817 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6818 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6819 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6821 if (pEnvironment) {
6822 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6823 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6824 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6827 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6828 needed = cbBuf * sizeof(WCHAR);
6829 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6830 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6832 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6833 if (pcbNeeded) needed = *pcbNeeded;
6834 /* HeapReAlloc return NULL, when bufferW was NULL */
6835 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6836 HeapAlloc(GetProcessHeap(), 0, needed);
6838 /* Try again with the large Buffer */
6839 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6841 numentries = pcReturned ? *pcReturned : 0;
6842 needed = 0;
6844 if (res) {
6845 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6846 DWORD index;
6847 LPSTR ptr;
6848 PPRINTPROCESSOR_INFO_1W ppiw;
6849 PPRINTPROCESSOR_INFO_1A ppia;
6851 /* First pass: calculate the size for all Entries */
6852 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6853 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6854 index = 0;
6855 while (index < numentries) {
6856 index++;
6857 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6858 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6860 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6861 NULL, 0, NULL, NULL);
6863 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6864 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6867 /* check for errors and quit on failure */
6868 if (cbBuf < needed) {
6869 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6870 res = FALSE;
6871 goto epp_cleanup;
6874 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6875 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6876 cbBuf -= len ; /* free Bytes in the user-Buffer */
6877 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6878 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6879 index = 0;
6880 /* Second Pass: Fill the User Buffer (if we have one) */
6881 while ((index < numentries) && pPPInfo) {
6882 index++;
6883 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6884 ppia->pName = ptr;
6885 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6886 ptr, cbBuf , NULL, NULL);
6887 ptr += len;
6888 cbBuf -= len;
6890 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6891 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6895 epp_cleanup:
6896 if (pcbNeeded) *pcbNeeded = needed;
6897 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6899 HeapFree(GetProcessHeap(), 0, nameW);
6900 HeapFree(GetProcessHeap(), 0, envW);
6901 HeapFree(GetProcessHeap(), 0, bufferW);
6903 TRACE("returning %d with %d (%d byte for %d entries)\n",
6904 (res), GetLastError(), needed, numentries);
6906 return (res);
6909 /*****************************************************************************
6910 * EnumPrintProcessorsW [WINSPOOL.@]
6912 * Enumerate available Print Processors
6914 * PARAMS
6915 * pName [I] Servername or NULL (local Computer)
6916 * pEnvironment [I] Printing-Environment or NULL (Default)
6917 * Level [I] Structure-Level (Only 1 is allowed)
6918 * pPPInfo [O] PTR to Buffer that receives the Result
6919 * cbBuf [I] Size of Buffer at pPPInfo
6920 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6921 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6923 * RETURNS
6924 * Success: TRUE
6925 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6928 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6929 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6932 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6933 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6935 if ((backend == NULL) && !load_backend()) return FALSE;
6937 if (!pcbNeeded || !pcReturned) {
6938 SetLastError(RPC_X_NULL_REF_POINTER);
6939 return FALSE;
6942 if (!pPPInfo && (cbBuf > 0)) {
6943 SetLastError(ERROR_INVALID_USER_BUFFER);
6944 return FALSE;
6947 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6948 cbBuf, pcbNeeded, pcReturned);
6951 /*****************************************************************************
6952 * ExtDeviceMode [WINSPOOL.@]
6955 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6956 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6957 DWORD fMode)
6959 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6960 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6961 debugstr_a(pProfile), fMode);
6962 return -1;
6965 /*****************************************************************************
6966 * FindClosePrinterChangeNotification [WINSPOOL.@]
6969 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6971 FIXME("Stub: %p\n", hChange);
6972 return TRUE;
6975 /*****************************************************************************
6976 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6979 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6980 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6982 FIXME("Stub: %p %x %x %p\n",
6983 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6984 return INVALID_HANDLE_VALUE;
6987 /*****************************************************************************
6988 * FindNextPrinterChangeNotification [WINSPOOL.@]
6991 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6992 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6994 FIXME("Stub: %p %p %p %p\n",
6995 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6996 return FALSE;
6999 /*****************************************************************************
7000 * FreePrinterNotifyInfo [WINSPOOL.@]
7003 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7005 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7006 return TRUE;
7009 /*****************************************************************************
7010 * string_to_buf
7012 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7013 * ansi depending on the unicode parameter.
7015 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7017 if(!str)
7019 *size = 0;
7020 return TRUE;
7023 if(unicode)
7025 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7026 if(*size <= cb)
7028 memcpy(ptr, str, *size);
7029 return TRUE;
7031 return FALSE;
7033 else
7035 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7036 if(*size <= cb)
7038 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7039 return TRUE;
7041 return FALSE;
7045 /*****************************************************************************
7046 * get_job_info_1
7048 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7049 LPDWORD pcbNeeded, BOOL unicode)
7051 DWORD size, left = cbBuf;
7052 BOOL space = (cbBuf > 0);
7053 LPBYTE ptr = buf;
7055 *pcbNeeded = 0;
7057 if(space)
7059 ji1->JobId = job->job_id;
7062 string_to_buf(job->document_title, ptr, left, &size, unicode);
7063 if(space && size <= left)
7065 ji1->pDocument = (LPWSTR)ptr;
7066 ptr += size;
7067 left -= size;
7069 else
7070 space = FALSE;
7071 *pcbNeeded += size;
7073 if (job->printer_name)
7075 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7076 if(space && size <= left)
7078 ji1->pPrinterName = (LPWSTR)ptr;
7079 ptr += size;
7080 left -= size;
7082 else
7083 space = FALSE;
7084 *pcbNeeded += size;
7087 return space;
7090 /*****************************************************************************
7091 * get_job_info_2
7093 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7094 LPDWORD pcbNeeded, BOOL unicode)
7096 DWORD size, left = cbBuf;
7097 DWORD shift;
7098 BOOL space = (cbBuf > 0);
7099 LPBYTE ptr = buf;
7100 LPDEVMODEA dmA;
7101 LPDEVMODEW devmode;
7103 *pcbNeeded = 0;
7105 if(space)
7107 ji2->JobId = job->job_id;
7110 string_to_buf(job->document_title, ptr, left, &size, unicode);
7111 if(space && size <= left)
7113 ji2->pDocument = (LPWSTR)ptr;
7114 ptr += size;
7115 left -= size;
7117 else
7118 space = FALSE;
7119 *pcbNeeded += size;
7121 if (job->printer_name)
7123 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7124 if(space && size <= left)
7126 ji2->pPrinterName = (LPWSTR)ptr;
7127 ptr += size;
7128 left -= size;
7130 else
7131 space = FALSE;
7132 *pcbNeeded += size;
7135 if (job->devmode)
7137 if (!unicode)
7139 dmA = DEVMODEdupWtoA(job->devmode);
7140 devmode = (LPDEVMODEW) dmA;
7141 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7143 else
7145 devmode = job->devmode;
7146 size = devmode->dmSize + devmode->dmDriverExtra;
7149 if (!devmode)
7150 FIXME("Can't convert DEVMODE W to A\n");
7151 else
7153 /* align DEVMODE to a DWORD boundary */
7154 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7155 size += shift;
7157 if (size <= left)
7159 ptr += shift;
7160 memcpy(ptr, devmode, size-shift);
7161 ji2->pDevMode = (LPDEVMODEW)ptr;
7162 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7163 ptr += size;
7164 left -= size;
7166 else
7167 space = FALSE;
7168 *pcbNeeded +=size;
7172 return space;
7175 /*****************************************************************************
7176 * get_job_info
7178 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7179 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7181 BOOL ret = FALSE;
7182 DWORD needed = 0, size;
7183 job_t *job;
7184 LPBYTE ptr = pJob;
7186 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7188 EnterCriticalSection(&printer_handles_cs);
7189 job = get_job(hPrinter, JobId);
7190 if(!job)
7191 goto end;
7193 switch(Level)
7195 case 1:
7196 size = sizeof(JOB_INFO_1W);
7197 if(cbBuf >= size)
7199 cbBuf -= size;
7200 ptr += size;
7201 memset(pJob, 0, size);
7203 else
7204 cbBuf = 0;
7205 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7206 needed += size;
7207 break;
7209 case 2:
7210 size = sizeof(JOB_INFO_2W);
7211 if(cbBuf >= size)
7213 cbBuf -= size;
7214 ptr += size;
7215 memset(pJob, 0, size);
7217 else
7218 cbBuf = 0;
7219 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7220 needed += size;
7221 break;
7223 case 3:
7224 size = sizeof(JOB_INFO_3);
7225 if(cbBuf >= size)
7227 cbBuf -= size;
7228 memset(pJob, 0, size);
7229 ret = TRUE;
7231 else
7232 cbBuf = 0;
7233 needed = size;
7234 break;
7236 default:
7237 SetLastError(ERROR_INVALID_LEVEL);
7238 goto end;
7240 if(pcbNeeded)
7241 *pcbNeeded = needed;
7242 end:
7243 LeaveCriticalSection(&printer_handles_cs);
7244 return ret;
7247 /*****************************************************************************
7248 * GetJobA [WINSPOOL.@]
7251 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7252 DWORD cbBuf, LPDWORD pcbNeeded)
7254 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7257 /*****************************************************************************
7258 * GetJobW [WINSPOOL.@]
7261 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7262 DWORD cbBuf, LPDWORD pcbNeeded)
7264 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7267 /*****************************************************************************
7268 * schedule_lpr
7270 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7272 char *unixname, *queue, *cmd;
7273 char fmt[] = "lpr -P'%s' '%s'";
7274 DWORD len;
7275 int r;
7277 if(!(unixname = wine_get_unix_file_name(filename)))
7278 return FALSE;
7280 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7281 queue = HeapAlloc(GetProcessHeap(), 0, len);
7282 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7284 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7285 sprintf(cmd, fmt, queue, unixname);
7287 TRACE("printing with: %s\n", cmd);
7288 r = system(cmd);
7290 HeapFree(GetProcessHeap(), 0, cmd);
7291 HeapFree(GetProcessHeap(), 0, queue);
7292 HeapFree(GetProcessHeap(), 0, unixname);
7293 return (r == 0);
7296 /*****************************************************************************
7297 * schedule_cups
7299 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7301 #ifdef SONAME_LIBCUPS
7302 if(pcupsPrintFile)
7304 char *unixname, *queue, *unix_doc_title;
7305 DWORD len;
7306 BOOL ret;
7308 if(!(unixname = wine_get_unix_file_name(filename)))
7309 return FALSE;
7311 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7312 queue = HeapAlloc(GetProcessHeap(), 0, len);
7313 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7315 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7316 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7317 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7319 TRACE("printing via cups\n");
7320 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7321 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7322 HeapFree(GetProcessHeap(), 0, queue);
7323 HeapFree(GetProcessHeap(), 0, unixname);
7324 return ret;
7326 else
7327 #endif
7329 return schedule_lpr(printer_name, filename);
7333 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7335 LPWSTR filename;
7337 switch(msg)
7339 case WM_INITDIALOG:
7340 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7341 return TRUE;
7343 case WM_COMMAND:
7344 if(HIWORD(wparam) == BN_CLICKED)
7346 if(LOWORD(wparam) == IDOK)
7348 HANDLE hf;
7349 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7350 LPWSTR *output;
7352 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7353 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7355 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7357 WCHAR caption[200], message[200];
7358 int mb_ret;
7360 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7361 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7362 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7363 if(mb_ret == IDCANCEL)
7365 HeapFree(GetProcessHeap(), 0, filename);
7366 return TRUE;
7369 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7370 if(hf == INVALID_HANDLE_VALUE)
7372 WCHAR caption[200], message[200];
7374 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7375 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7376 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7377 HeapFree(GetProcessHeap(), 0, filename);
7378 return TRUE;
7380 CloseHandle(hf);
7381 DeleteFileW(filename);
7382 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7383 *output = filename;
7384 EndDialog(hwnd, IDOK);
7385 return TRUE;
7387 if(LOWORD(wparam) == IDCANCEL)
7389 EndDialog(hwnd, IDCANCEL);
7390 return TRUE;
7393 return FALSE;
7395 return FALSE;
7398 /*****************************************************************************
7399 * get_filename
7401 static BOOL get_filename(LPWSTR *filename)
7403 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7404 file_dlg_proc, (LPARAM)filename) == IDOK;
7407 /*****************************************************************************
7408 * schedule_file
7410 static BOOL schedule_file(LPCWSTR filename)
7412 LPWSTR output = NULL;
7414 if(get_filename(&output))
7416 BOOL r;
7417 TRACE("copy to %s\n", debugstr_w(output));
7418 r = CopyFileW(filename, output, FALSE);
7419 HeapFree(GetProcessHeap(), 0, output);
7420 return r;
7422 return FALSE;
7425 /*****************************************************************************
7426 * schedule_pipe
7428 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7430 #ifdef HAVE_FORK
7431 char *unixname, *cmdA;
7432 DWORD len;
7433 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7434 BOOL ret = FALSE;
7435 char buf[1024];
7437 if(!(unixname = wine_get_unix_file_name(filename)))
7438 return FALSE;
7440 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7441 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7442 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7444 TRACE("printing with: %s\n", cmdA);
7446 if((file_fd = open(unixname, O_RDONLY)) == -1)
7447 goto end;
7449 if (pipe(fds))
7451 ERR("pipe() failed!\n");
7452 goto end;
7455 if (fork() == 0)
7457 close(0);
7458 dup2(fds[0], 0);
7459 close(fds[1]);
7461 /* reset signals that we previously set to SIG_IGN */
7462 signal(SIGPIPE, SIG_DFL);
7463 signal(SIGCHLD, SIG_DFL);
7465 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7466 _exit(1);
7469 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7470 write(fds[1], buf, no_read);
7472 ret = TRUE;
7474 end:
7475 if(file_fd != -1) close(file_fd);
7476 if(fds[0] != -1) close(fds[0]);
7477 if(fds[1] != -1) close(fds[1]);
7479 HeapFree(GetProcessHeap(), 0, cmdA);
7480 HeapFree(GetProcessHeap(), 0, unixname);
7481 return ret;
7482 #else
7483 return FALSE;
7484 #endif
7487 /*****************************************************************************
7488 * schedule_unixfile
7490 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7492 int in_fd, out_fd, no_read;
7493 char buf[1024];
7494 BOOL ret = FALSE;
7495 char *unixname, *outputA;
7496 DWORD len;
7498 if(!(unixname = wine_get_unix_file_name(filename)))
7499 return FALSE;
7501 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7502 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7503 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7505 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7506 in_fd = open(unixname, O_RDONLY);
7507 if(out_fd == -1 || in_fd == -1)
7508 goto end;
7510 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7511 write(out_fd, buf, no_read);
7513 ret = TRUE;
7514 end:
7515 if(in_fd != -1) close(in_fd);
7516 if(out_fd != -1) close(out_fd);
7517 HeapFree(GetProcessHeap(), 0, outputA);
7518 HeapFree(GetProcessHeap(), 0, unixname);
7519 return ret;
7522 /*****************************************************************************
7523 * ScheduleJob [WINSPOOL.@]
7526 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7528 opened_printer_t *printer;
7529 BOOL ret = FALSE;
7530 struct list *cursor, *cursor2;
7532 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7533 EnterCriticalSection(&printer_handles_cs);
7534 printer = get_opened_printer(hPrinter);
7535 if(!printer)
7536 goto end;
7538 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7540 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7541 HANDLE hf;
7543 if(job->job_id != dwJobID) continue;
7545 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7546 if(hf != INVALID_HANDLE_VALUE)
7548 PRINTER_INFO_5W *pi5 = NULL;
7549 LPWSTR portname = job->portname;
7550 DWORD needed;
7551 HKEY hkey;
7552 WCHAR output[1024];
7553 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7554 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7556 if (!portname)
7558 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7559 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7560 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7561 portname = pi5->pPortName;
7563 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7564 debugstr_w(portname));
7566 output[0] = 0;
7568 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7569 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7571 DWORD type, count = sizeof(output);
7572 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7573 RegCloseKey(hkey);
7575 if(output[0] == '|')
7577 ret = schedule_pipe(output + 1, job->filename);
7579 else if(output[0])
7581 ret = schedule_unixfile(output, job->filename);
7583 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7585 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7587 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7589 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7591 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7593 ret = schedule_file(job->filename);
7595 else
7597 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7599 HeapFree(GetProcessHeap(), 0, pi5);
7600 CloseHandle(hf);
7601 DeleteFileW(job->filename);
7603 list_remove(cursor);
7604 HeapFree(GetProcessHeap(), 0, job->document_title);
7605 HeapFree(GetProcessHeap(), 0, job->printer_name);
7606 HeapFree(GetProcessHeap(), 0, job->portname);
7607 HeapFree(GetProcessHeap(), 0, job->filename);
7608 HeapFree(GetProcessHeap(), 0, job->devmode);
7609 HeapFree(GetProcessHeap(), 0, job);
7610 break;
7612 end:
7613 LeaveCriticalSection(&printer_handles_cs);
7614 return ret;
7617 /*****************************************************************************
7618 * StartDocDlgA [WINSPOOL.@]
7620 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7622 UNICODE_STRING usBuffer;
7623 DOCINFOW docW;
7624 LPWSTR retW;
7625 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7626 LPSTR ret = NULL;
7628 docW.cbSize = sizeof(docW);
7629 if (doc->lpszDocName)
7631 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7632 if (!(docW.lpszDocName = docnameW)) return NULL;
7634 if (doc->lpszOutput)
7636 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7637 if (!(docW.lpszOutput = outputW)) return NULL;
7639 if (doc->lpszDatatype)
7641 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7642 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7644 docW.fwType = doc->fwType;
7646 retW = StartDocDlgW(hPrinter, &docW);
7648 if(retW)
7650 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7651 ret = HeapAlloc(GetProcessHeap(), 0, len);
7652 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7653 HeapFree(GetProcessHeap(), 0, retW);
7656 HeapFree(GetProcessHeap(), 0, datatypeW);
7657 HeapFree(GetProcessHeap(), 0, outputW);
7658 HeapFree(GetProcessHeap(), 0, docnameW);
7660 return ret;
7663 /*****************************************************************************
7664 * StartDocDlgW [WINSPOOL.@]
7666 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7667 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7668 * port is "FILE:". Also returns the full path if passed a relative path.
7670 * The caller should free the returned string from the process heap.
7672 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7674 LPWSTR ret = NULL;
7675 DWORD len, attr;
7677 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7679 PRINTER_INFO_5W *pi5;
7680 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7681 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7682 return NULL;
7683 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7684 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7685 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7687 HeapFree(GetProcessHeap(), 0, pi5);
7688 return NULL;
7690 HeapFree(GetProcessHeap(), 0, pi5);
7693 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7695 LPWSTR name;
7697 if (get_filename(&name))
7699 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7701 HeapFree(GetProcessHeap(), 0, name);
7702 return NULL;
7704 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7705 GetFullPathNameW(name, len, ret, NULL);
7706 HeapFree(GetProcessHeap(), 0, name);
7708 return ret;
7711 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7712 return NULL;
7714 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7715 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7717 attr = GetFileAttributesW(ret);
7718 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7720 HeapFree(GetProcessHeap(), 0, ret);
7721 ret = NULL;
7723 return ret;