urlmon: Implemented CreateUriWithFragment.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob7bf1bcbb7cc968c2215b5d6c504a902c006e1195
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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 /* ############################### */
78 typedef struct {
79 DWORD job_id;
80 HANDLE hf;
81 } started_doc_t;
83 typedef struct {
84 struct list jobs;
85 LONG ref;
86 } jobqueue_t;
88 typedef struct {
89 LPWSTR name;
90 LPWSTR printername;
91 HANDLE backend_printer;
92 jobqueue_t *queue;
93 started_doc_t *doc;
94 } opened_printer_t;
96 typedef struct {
97 struct list entry;
98 DWORD job_id;
99 WCHAR *filename;
100 WCHAR *portname;
101 WCHAR *document_title;
102 } job_t;
105 typedef struct {
106 LPCWSTR envname;
107 LPCWSTR subdir;
108 DWORD driverversion;
109 LPCWSTR versionregpath;
110 LPCWSTR versionsubdir;
111 } printenv_t;
113 /* ############################### */
115 static opened_printer_t **printer_handles;
116 static UINT nb_printer_handles;
117 static LONG next_job_id = 1;
119 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
120 WORD fwCapability, LPSTR lpszOutput,
121 LPDEVMODEA lpdm );
122 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
123 LPSTR lpszDevice, LPSTR lpszPort,
124 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
125 DWORD fwMode );
127 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
128 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'c','o','n','t','r','o','l','\\',
130 'P','r','i','n','t','\\',
131 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
132 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
134 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
135 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
136 'C','o','n','t','r','o','l','\\',
137 'P','r','i','n','t','\\',
138 'P','r','i','n','t','e','r','s',0};
140 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
142 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
143 'M','i','c','r','o','s','o','f','t','\\',
144 'W','i','n','d','o','w','s',' ','N','T','\\',
145 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
146 'W','i','n','d','o','w','s',0};
148 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
149 'M','i','c','r','o','s','o','f','t','\\',
150 'W','i','n','d','o','w','s',' ','N','T','\\',
151 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
152 'D','e','v','i','c','e','s',0};
154 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
155 'M','i','c','r','o','s','o','f','t','\\',
156 'W','i','n','d','o','w','s',' ','N','T','\\',
157 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
158 'P','o','r','t','s',0};
160 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
161 'M','i','c','r','o','s','o','f','t','\\',
162 'W','i','n','d','o','w','s',' ','N','T','\\',
163 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
164 'P','r','i','n','t','e','r','P','o','r','t','s',0};
166 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
167 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
168 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
169 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
170 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
171 static const WCHAR subdir_x64W[] = {'x','6','4',0};
172 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
173 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
174 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
175 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
176 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
178 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
179 static const WCHAR backslashW[] = {'\\',0};
180 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
181 'i','o','n',' ','F','i','l','e',0};
182 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
183 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
184 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
185 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
186 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
187 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
188 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
189 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
190 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
191 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
192 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
193 static const WCHAR NameW[] = {'N','a','m','e',0};
194 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
195 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
196 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
197 static const WCHAR PortW[] = {'P','o','r','t',0};
198 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
199 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
200 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
201 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
202 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
203 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
204 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
205 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
206 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
207 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
208 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
209 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
210 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
211 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
212 static const WCHAR emptyStringW[] = {0};
214 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
216 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
217 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
218 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
220 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
221 'D','o','c','u','m','e','n','t',0};
223 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
224 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
225 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
226 0, sizeof(DRIVER_INFO_8W)};
229 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
230 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
231 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
232 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
233 sizeof(PRINTER_INFO_9W)};
235 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
236 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
237 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
239 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
241 /******************************************************************
242 * validate the user-supplied printing-environment [internal]
244 * PARAMS
245 * env [I] PTR to Environment-String or NULL
247 * RETURNS
248 * Failure: NULL
249 * Success: PTR to printenv_t
251 * NOTES
252 * An empty string is handled the same way as NULL.
253 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
257 static const printenv_t * validate_envW(LPCWSTR env)
259 const printenv_t *result = NULL;
260 unsigned int i;
262 TRACE("testing %s\n", debugstr_w(env));
263 if (env && env[0])
265 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
267 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
269 result = all_printenv[i];
270 break;
274 if (result == NULL) {
275 FIXME("unsupported Environment: %s\n", debugstr_w(env));
276 SetLastError(ERROR_INVALID_ENVIRONMENT);
278 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
280 else
282 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
284 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
286 return result;
290 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
291 if passed a NULL string. This returns NULLs to the result.
293 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
295 if ( (src) )
297 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
298 return usBufferPtr->Buffer;
300 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
301 return NULL;
304 static LPWSTR strdupW(LPCWSTR p)
306 LPWSTR ret;
307 DWORD len;
309 if(!p) return NULL;
310 len = (strlenW(p) + 1) * sizeof(WCHAR);
311 ret = HeapAlloc(GetProcessHeap(), 0, len);
312 memcpy(ret, p, len);
313 return ret;
316 static LPSTR strdupWtoA( LPCWSTR str )
318 LPSTR ret;
319 INT len;
321 if (!str) return NULL;
322 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
323 ret = HeapAlloc( GetProcessHeap(), 0, len );
324 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
325 return ret;
328 /******************************************************************
329 * verify, that the filename is a local file
332 static inline BOOL is_local_file(LPWSTR name)
334 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
337 /******************************************************************
338 * Return the number of bytes for an multi_sz string.
339 * The result includes all \0s
340 * (specifically the extra \0, that is needed as multi_sz terminator).
342 #if 0
343 static int multi_sz_lenW(const WCHAR *str)
345 const WCHAR *ptr = str;
346 if(!str) return 0;
349 ptr += lstrlenW(ptr) + 1;
350 } while(*ptr);
352 return (ptr - str + 1) * sizeof(WCHAR);
354 #endif
355 /* ################################ */
357 static int multi_sz_lenA(const char *str)
359 const char *ptr = str;
360 if(!str) return 0;
363 ptr += lstrlenA(ptr) + 1;
364 } while(*ptr);
366 return ptr - str + 1;
369 static void
370 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
371 char qbuf[200];
373 /* If forcing, or no profile string entry for device yet, set the entry
375 * The always change entry if not WINEPS yet is discussable.
377 if (force ||
378 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
379 !strcmp(qbuf,"*") ||
380 !strstr(qbuf,"WINEPS.DRV")
382 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
383 HKEY hkey;
385 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
386 WriteProfileStringA("windows","device",buf);
387 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
388 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
389 RegCloseKey(hkey);
391 HeapFree(GetProcessHeap(),0,buf);
395 static BOOL add_printer_driver(const char *name)
397 DRIVER_INFO_3A di3a;
399 static char driver_9x[] = "wineps16.drv",
400 driver_nt[] = "wineps.drv",
401 env_9x[] = "Windows 4.0",
402 env_nt[] = "Windows NT x86",
403 data_file[] = "generic.ppd",
404 default_data_type[] = "RAW";
406 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
407 di3a.cVersion = 3;
408 di3a.pName = (char *)name;
409 di3a.pEnvironment = env_nt;
410 di3a.pDriverPath = driver_nt;
411 di3a.pDataFile = data_file;
412 di3a.pConfigFile = driver_nt;
413 di3a.pDefaultDataType = default_data_type;
415 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
416 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
418 di3a.cVersion = 0;
419 di3a.pEnvironment = env_9x;
420 di3a.pDriverPath = driver_9x;
421 di3a.pConfigFile = driver_9x;
422 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
423 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
425 return TRUE;
428 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
429 debugstr_a(di3a.pEnvironment), GetLastError());
430 return FALSE;
433 #ifdef SONAME_LIBCUPS
434 static typeof(cupsFreeDests) *pcupsFreeDests;
435 static typeof(cupsGetDests) *pcupsGetDests;
436 static typeof(cupsGetPPD) *pcupsGetPPD;
437 static typeof(cupsPrintFile) *pcupsPrintFile;
438 static void *cupshandle;
440 static BOOL CUPS_LoadPrinters(void)
442 int i, nrofdests;
443 BOOL hadprinter = FALSE, haddefault = FALSE;
444 cups_dest_t *dests;
445 PRINTER_INFO_2A pinfo2a;
446 char *port,*devline;
447 HKEY hkeyPrinter, hkeyPrinters, hkey;
448 char loaderror[256];
450 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
451 if (!cupshandle) {
452 TRACE("%s\n", loaderror);
453 return FALSE;
455 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
457 #define DYNCUPS(x) \
458 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
459 if (!p##x) return FALSE;
461 DYNCUPS(cupsFreeDests);
462 DYNCUPS(cupsGetPPD);
463 DYNCUPS(cupsGetDests);
464 DYNCUPS(cupsPrintFile);
465 #undef DYNCUPS
467 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
468 ERROR_SUCCESS) {
469 ERR("Can't create Printers key\n");
470 return FALSE;
473 nrofdests = pcupsGetDests(&dests);
474 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
475 for (i=0;i<nrofdests;i++) {
476 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
477 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
478 sprintf(port,"LPR:%s", dests[i].name);
479 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
480 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
481 sprintf(devline, "WINEPS.DRV,%s", port);
482 WriteProfileStringA("devices", dests[i].name, devline);
483 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
484 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
485 RegCloseKey(hkey);
488 lstrcatA(devline, ",15,45");
489 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
490 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
491 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
492 RegCloseKey(hkey);
495 HeapFree(GetProcessHeap(), 0, devline);
497 TRACE("Printer %d: %s\n", i, dests[i].name);
498 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
499 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
500 and continue */
501 TRACE("Printer already exists\n");
502 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
503 RegCloseKey(hkeyPrinter);
504 } else {
505 static CHAR data_type[] = "RAW",
506 print_proc[] = "WinPrint",
507 comment[] = "WINEPS Printer using CUPS",
508 location[] = "<physical location of printer>",
509 params[] = "<parameters?>",
510 share_name[] = "<share name?>",
511 sep_file[] = "<sep file?>";
513 add_printer_driver(dests[i].name);
515 memset(&pinfo2a,0,sizeof(pinfo2a));
516 pinfo2a.pPrinterName = dests[i].name;
517 pinfo2a.pDatatype = data_type;
518 pinfo2a.pPrintProcessor = print_proc;
519 pinfo2a.pDriverName = dests[i].name;
520 pinfo2a.pComment = comment;
521 pinfo2a.pLocation = location;
522 pinfo2a.pPortName = port;
523 pinfo2a.pParameters = params;
524 pinfo2a.pShareName = share_name;
525 pinfo2a.pSepFile = sep_file;
527 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
528 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
529 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
532 HeapFree(GetProcessHeap(),0,port);
534 hadprinter = TRUE;
535 if (dests[i].is_default) {
536 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
537 haddefault = TRUE;
540 if (hadprinter & !haddefault)
541 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
542 pcupsFreeDests(nrofdests, dests);
543 RegCloseKey(hkeyPrinters);
544 return hadprinter;
546 #endif
548 static BOOL
549 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
550 PRINTER_INFO_2A pinfo2a;
551 char *e,*s,*name,*prettyname,*devname;
552 BOOL ret = FALSE, set_default = FALSE;
553 char *port = NULL, *devline,*env_default;
554 HKEY hkeyPrinter, hkeyPrinters, hkey;
556 while (isspace(*pent)) pent++;
557 s = strchr(pent,':');
558 if(s) *s='\0';
559 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
560 strcpy(name,pent);
561 if(s) {
562 *s=':';
563 pent = s;
564 } else
565 pent = "";
567 TRACE("name=%s entry=%s\n",name, pent);
569 if(ispunct(*name)) { /* a tc entry, not a real printer */
570 TRACE("skipping tc entry\n");
571 goto end;
574 if(strstr(pent,":server")) { /* server only version so skip */
575 TRACE("skipping server entry\n");
576 goto end;
579 /* Determine whether this is a postscript printer. */
581 ret = TRUE;
582 env_default = getenv("PRINTER");
583 prettyname = name;
584 /* Get longest name, usually the one at the right for later display. */
585 while((s=strchr(prettyname,'|'))) {
586 *s = '\0';
587 e = s;
588 while(isspace(*--e)) *e = '\0';
589 TRACE("\t%s\n", debugstr_a(prettyname));
590 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
591 for(prettyname = s+1; isspace(*prettyname); prettyname++)
594 e = prettyname + strlen(prettyname);
595 while(isspace(*--e)) *e = '\0';
596 TRACE("\t%s\n", debugstr_a(prettyname));
597 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
599 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
600 * if it is too long, we use it as comment below. */
601 devname = prettyname;
602 if (strlen(devname)>=CCHDEVICENAME-1)
603 devname = name;
604 if (strlen(devname)>=CCHDEVICENAME-1) {
605 ret = FALSE;
606 goto end;
609 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
610 sprintf(port,"LPR:%s",name);
612 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
613 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
614 sprintf(devline, "WINEPS.DRV,%s", port);
615 WriteProfileStringA("devices", devname, devline);
616 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
617 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
618 RegCloseKey(hkey);
621 lstrcatA(devline, ",15,45");
622 WriteProfileStringA("PrinterPorts", devname, devline);
623 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
624 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
625 RegCloseKey(hkey);
628 HeapFree(GetProcessHeap(),0,devline);
630 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
631 ERROR_SUCCESS) {
632 ERR("Can't create Printers key\n");
633 ret = FALSE;
634 goto end;
636 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
637 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
638 and continue */
639 TRACE("Printer already exists\n");
640 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
641 RegCloseKey(hkeyPrinter);
642 } else {
643 static CHAR data_type[] = "RAW",
644 print_proc[] = "WinPrint",
645 comment[] = "WINEPS Printer using LPR",
646 params[] = "<parameters?>",
647 share_name[] = "<share name?>",
648 sep_file[] = "<sep file?>";
650 add_printer_driver(devname);
652 memset(&pinfo2a,0,sizeof(pinfo2a));
653 pinfo2a.pPrinterName = devname;
654 pinfo2a.pDatatype = data_type;
655 pinfo2a.pPrintProcessor = print_proc;
656 pinfo2a.pDriverName = devname;
657 pinfo2a.pComment = comment;
658 pinfo2a.pLocation = prettyname;
659 pinfo2a.pPortName = port;
660 pinfo2a.pParameters = params;
661 pinfo2a.pShareName = share_name;
662 pinfo2a.pSepFile = sep_file;
664 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
665 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
666 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
669 RegCloseKey(hkeyPrinters);
671 if (isfirst || set_default)
672 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
674 end:
675 HeapFree(GetProcessHeap(), 0, port);
676 HeapFree(GetProcessHeap(), 0, name);
677 return ret;
680 static BOOL
681 PRINTCAP_LoadPrinters(void) {
682 BOOL hadprinter = FALSE;
683 char buf[200];
684 FILE *f;
685 char *pent = NULL;
686 BOOL had_bash = FALSE;
688 f = fopen("/etc/printcap","r");
689 if (!f)
690 return FALSE;
692 while(fgets(buf,sizeof(buf),f)) {
693 char *start, *end;
695 end=strchr(buf,'\n');
696 if (end) *end='\0';
698 start = buf;
699 while(isspace(*start)) start++;
700 if(*start == '#' || *start == '\0')
701 continue;
703 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
704 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
705 HeapFree(GetProcessHeap(),0,pent);
706 pent = NULL;
709 if (end && *--end == '\\') {
710 *end = '\0';
711 had_bash = TRUE;
712 } else
713 had_bash = FALSE;
715 if (pent) {
716 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
717 strcat(pent,start);
718 } else {
719 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
720 strcpy(pent,start);
724 if(pent) {
725 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
726 HeapFree(GetProcessHeap(),0,pent);
728 fclose(f);
729 return hadprinter;
732 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
734 if (value)
735 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
736 (lstrlenW(value) + 1) * sizeof(WCHAR));
737 else
738 return ERROR_FILE_NOT_FOUND;
741 /******************************************************************
742 * get_servername_from_name (internal)
744 * for an external server, a copy of the serverpart from the full name is returned
747 static LPWSTR get_servername_from_name(LPCWSTR name)
749 LPWSTR server;
750 LPWSTR ptr;
751 WCHAR buffer[MAX_PATH];
752 DWORD len;
754 if (name == NULL) return NULL;
755 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
757 server = strdupW(&name[2]); /* skip over both backslash */
758 if (server == NULL) return NULL;
760 /* strip '\' and the printername */
761 ptr = strchrW(server, '\\');
762 if (ptr) ptr[0] = '\0';
764 TRACE("found %s\n", debugstr_w(server));
766 len = sizeof(buffer)/sizeof(buffer[0]);
767 if (GetComputerNameW(buffer, &len)) {
768 if (lstrcmpW(buffer, server) == 0) {
769 /* The requested Servername is our computername */
770 HeapFree(GetProcessHeap(), 0, server);
771 return NULL;
774 return server;
777 /******************************************************************
778 * get_basename_from_name (internal)
780 * skip over the serverpart from the full name
783 static LPCWSTR get_basename_from_name(LPCWSTR name)
785 if (name == NULL) return NULL;
786 if ((name[0] == '\\') && (name[1] == '\\')) {
787 /* skip over the servername and search for the following '\' */
788 name = strchrW(&name[2], '\\');
789 if ((name) && (name[1])) {
790 /* found a separator ('\') followed by a name:
791 skip over the separator and return the rest */
792 name++;
794 else
796 /* no basename present (we found only a servername) */
797 return NULL;
800 return name;
803 /******************************************************************
804 * get_opened_printer_entry
805 * Get the first place empty in the opened printer table
807 * ToDo:
808 * - pDefault is ignored
810 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
812 UINT_PTR handle = nb_printer_handles, i;
813 jobqueue_t *queue = NULL;
814 opened_printer_t *printer = NULL;
815 LPWSTR servername;
816 LPCWSTR printername;
818 if ((backend == NULL) && !load_backend()) return NULL;
820 servername = get_servername_from_name(name);
821 if (servername) {
822 FIXME("server %s not supported\n", debugstr_w(servername));
823 HeapFree(GetProcessHeap(), 0, servername);
824 SetLastError(ERROR_INVALID_PRINTER_NAME);
825 return NULL;
828 printername = get_basename_from_name(name);
829 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
831 /* an empty printername is invalid */
832 if (printername && (!printername[0])) {
833 SetLastError(ERROR_INVALID_PARAMETER);
834 return NULL;
837 EnterCriticalSection(&printer_handles_cs);
839 for (i = 0; i < nb_printer_handles; i++)
841 if (!printer_handles[i])
843 if(handle == nb_printer_handles)
844 handle = i;
846 else
848 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
849 queue = printer_handles[i]->queue;
853 if (handle >= nb_printer_handles)
855 opened_printer_t **new_array;
856 if (printer_handles)
857 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
858 (nb_printer_handles + 16) * sizeof(*new_array) );
859 else
860 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
861 (nb_printer_handles + 16) * sizeof(*new_array) );
863 if (!new_array)
865 handle = 0;
866 goto end;
868 printer_handles = new_array;
869 nb_printer_handles += 16;
872 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
874 handle = 0;
875 goto end;
878 /* get a printer handle from the backend */
879 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
880 handle = 0;
881 goto end;
884 /* clone the base name. This is NULL for the printserver */
885 printer->printername = strdupW(printername);
887 /* clone the full name */
888 printer->name = strdupW(name);
889 if (name && (!printer->name)) {
890 handle = 0;
891 goto end;
894 if(queue)
895 printer->queue = queue;
896 else
898 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
899 if (!printer->queue) {
900 handle = 0;
901 goto end;
903 list_init(&printer->queue->jobs);
904 printer->queue->ref = 0;
906 InterlockedIncrement(&printer->queue->ref);
908 printer_handles[handle] = printer;
909 handle++;
910 end:
911 LeaveCriticalSection(&printer_handles_cs);
912 if (!handle && printer) {
913 /* Something failed: Free all resources */
914 HeapFree(GetProcessHeap(), 0, printer->printername);
915 HeapFree(GetProcessHeap(), 0, printer->name);
916 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
917 HeapFree(GetProcessHeap(), 0, printer);
920 return (HANDLE)handle;
923 /******************************************************************
924 * get_opened_printer
925 * Get the pointer to the opened printer referred by the handle
927 static opened_printer_t *get_opened_printer(HANDLE hprn)
929 UINT_PTR idx = (UINT_PTR)hprn;
930 opened_printer_t *ret = NULL;
932 EnterCriticalSection(&printer_handles_cs);
934 if ((idx > 0) && (idx <= nb_printer_handles)) {
935 ret = printer_handles[idx - 1];
937 LeaveCriticalSection(&printer_handles_cs);
938 return ret;
941 /******************************************************************
942 * get_opened_printer_name
943 * Get the pointer to the opened printer name referred by the handle
945 static LPCWSTR get_opened_printer_name(HANDLE hprn)
947 opened_printer_t *printer = get_opened_printer(hprn);
948 if(!printer) return NULL;
949 return printer->name;
952 /******************************************************************
953 * WINSPOOL_GetOpenedPrinterRegKey
956 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
958 LPCWSTR name = get_opened_printer_name(hPrinter);
959 DWORD ret;
960 HKEY hkeyPrinters;
962 if(!name) return ERROR_INVALID_HANDLE;
964 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
965 ERROR_SUCCESS)
966 return ret;
968 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
970 ERR("Can't find opened printer %s in registry\n",
971 debugstr_w(name));
972 RegCloseKey(hkeyPrinters);
973 return ERROR_INVALID_PRINTER_NAME; /* ? */
975 RegCloseKey(hkeyPrinters);
976 return ERROR_SUCCESS;
979 void WINSPOOL_LoadSystemPrinters(void)
981 HKEY hkey, hkeyPrinters;
982 HANDLE hprn;
983 DWORD needed, num, i;
984 WCHAR PrinterName[256];
985 BOOL done = FALSE;
987 /* This ensures that all printer entries have a valid Name value. If causes
988 problems later if they don't. If one is found to be missed we create one
989 and set it equal to the name of the key */
990 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
991 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
992 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
993 for(i = 0; i < num; i++) {
994 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
995 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
996 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
997 set_reg_szW(hkey, NameW, PrinterName);
999 RegCloseKey(hkey);
1004 RegCloseKey(hkeyPrinters);
1007 /* We want to avoid calling AddPrinter on printers as much as
1008 possible, because on cups printers this will (eventually) lead
1009 to a call to cupsGetPPD which takes forever, even with non-cups
1010 printers AddPrinter takes a while. So we'll tag all printers that
1011 were automatically added last time around, if they still exist
1012 we'll leave them be otherwise we'll delete them. */
1013 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1014 if(needed) {
1015 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1016 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1017 for(i = 0; i < num; i++) {
1018 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1019 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1020 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1021 DWORD dw = 1;
1022 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1023 RegCloseKey(hkey);
1025 ClosePrinter(hprn);
1030 HeapFree(GetProcessHeap(), 0, pi);
1034 #ifdef SONAME_LIBCUPS
1035 done = CUPS_LoadPrinters();
1036 #endif
1038 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1039 PRINTCAP_LoadPrinters();
1041 /* Now enumerate the list again and delete any printers that are still tagged */
1042 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1043 if(needed) {
1044 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1045 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1046 for(i = 0; i < num; i++) {
1047 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1048 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1049 BOOL delete_driver = FALSE;
1050 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1051 DWORD dw, type, size = sizeof(dw);
1052 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1053 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1054 DeletePrinter(hprn);
1055 delete_driver = TRUE;
1057 RegCloseKey(hkey);
1059 ClosePrinter(hprn);
1060 if(delete_driver)
1061 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1066 HeapFree(GetProcessHeap(), 0, pi);
1069 return;
1073 /******************************************************************
1074 * get_job
1076 * Get the pointer to the specified job.
1077 * Should hold the printer_handles_cs before calling.
1079 static job_t *get_job(HANDLE hprn, DWORD JobId)
1081 opened_printer_t *printer = get_opened_printer(hprn);
1082 job_t *job;
1084 if(!printer) return NULL;
1085 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1087 if(job->job_id == JobId)
1088 return job;
1090 return NULL;
1093 /***********************************************************
1094 * DEVMODEcpyAtoW
1096 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1098 BOOL Formname;
1099 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1100 DWORD size;
1102 Formname = (dmA->dmSize > off_formname);
1103 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1104 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1105 dmW->dmDeviceName, CCHDEVICENAME);
1106 if(!Formname) {
1107 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1108 dmA->dmSize - CCHDEVICENAME);
1109 } else {
1110 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1111 off_formname - CCHDEVICENAME);
1112 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1113 dmW->dmFormName, CCHFORMNAME);
1114 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1115 (off_formname + CCHFORMNAME));
1117 dmW->dmSize = size;
1118 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1119 dmA->dmDriverExtra);
1120 return dmW;
1123 /***********************************************************
1124 * DEVMODEdupWtoA
1125 * Creates an ansi copy of supplied devmode
1127 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1129 LPDEVMODEA dmA;
1130 DWORD size;
1132 if (!dmW) return NULL;
1133 size = dmW->dmSize - CCHDEVICENAME -
1134 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1136 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1137 if (!dmA) return NULL;
1139 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1140 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1142 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1143 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1144 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1146 else
1148 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1149 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1150 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1151 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1153 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1156 dmA->dmSize = size;
1157 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1158 return dmA;
1161 /******************************************************************
1162 * convert_printerinfo_W_to_A [internal]
1165 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1166 DWORD level, DWORD outlen, DWORD numentries)
1168 DWORD id = 0;
1169 LPSTR ptr;
1170 INT len;
1172 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1174 len = pi_sizeof[level] * numentries;
1175 ptr = (LPSTR) out + len;
1176 outlen -= len;
1178 /* copy the numbers of all PRINTER_INFO_* first */
1179 memcpy(out, pPrintersW, len);
1181 while (id < numentries) {
1182 switch (level) {
1183 case 1:
1185 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1186 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1188 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1189 if (piW->pDescription) {
1190 piA->pDescription = ptr;
1191 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1192 ptr, outlen, NULL, NULL);
1193 ptr += len;
1194 outlen -= len;
1196 if (piW->pName) {
1197 piA->pName = ptr;
1198 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1199 ptr, outlen, NULL, NULL);
1200 ptr += len;
1201 outlen -= len;
1203 if (piW->pComment) {
1204 piA->pComment = ptr;
1205 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1206 ptr, outlen, NULL, NULL);
1207 ptr += len;
1208 outlen -= len;
1210 break;
1213 case 2:
1215 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1216 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1217 LPDEVMODEA dmA;
1219 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1220 if (piW->pServerName) {
1221 piA->pServerName = ptr;
1222 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1223 ptr, outlen, NULL, NULL);
1224 ptr += len;
1225 outlen -= len;
1227 if (piW->pPrinterName) {
1228 piA->pPrinterName = ptr;
1229 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1230 ptr, outlen, NULL, NULL);
1231 ptr += len;
1232 outlen -= len;
1234 if (piW->pShareName) {
1235 piA->pShareName = ptr;
1236 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1237 ptr, outlen, NULL, NULL);
1238 ptr += len;
1239 outlen -= len;
1241 if (piW->pPortName) {
1242 piA->pPortName = ptr;
1243 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1244 ptr, outlen, NULL, NULL);
1245 ptr += len;
1246 outlen -= len;
1248 if (piW->pDriverName) {
1249 piA->pDriverName = ptr;
1250 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1251 ptr, outlen, NULL, NULL);
1252 ptr += len;
1253 outlen -= len;
1255 if (piW->pComment) {
1256 piA->pComment = ptr;
1257 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1258 ptr, outlen, NULL, NULL);
1259 ptr += len;
1260 outlen -= len;
1262 if (piW->pLocation) {
1263 piA->pLocation = ptr;
1264 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1265 ptr, outlen, NULL, NULL);
1266 ptr += len;
1267 outlen -= len;
1270 dmA = DEVMODEdupWtoA(piW->pDevMode);
1271 if (dmA) {
1272 /* align DEVMODEA to a DWORD boundary */
1273 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1274 ptr += len;
1275 outlen -= len;
1277 piA->pDevMode = (LPDEVMODEA) ptr;
1278 len = dmA->dmSize + dmA->dmDriverExtra;
1279 memcpy(ptr, dmA, len);
1280 HeapFree(GetProcessHeap(), 0, dmA);
1282 ptr += len;
1283 outlen -= len;
1286 if (piW->pSepFile) {
1287 piA->pSepFile = ptr;
1288 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1289 ptr, outlen, NULL, NULL);
1290 ptr += len;
1291 outlen -= len;
1293 if (piW->pPrintProcessor) {
1294 piA->pPrintProcessor = ptr;
1295 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1296 ptr, outlen, NULL, NULL);
1297 ptr += len;
1298 outlen -= len;
1300 if (piW->pDatatype) {
1301 piA->pDatatype = ptr;
1302 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1303 ptr, outlen, NULL, NULL);
1304 ptr += len;
1305 outlen -= len;
1307 if (piW->pParameters) {
1308 piA->pParameters = ptr;
1309 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1310 ptr, outlen, NULL, NULL);
1311 ptr += len;
1312 outlen -= len;
1314 if (piW->pSecurityDescriptor) {
1315 piA->pSecurityDescriptor = NULL;
1316 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1318 break;
1321 case 4:
1323 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1324 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1326 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1328 if (piW->pPrinterName) {
1329 piA->pPrinterName = ptr;
1330 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1331 ptr, outlen, NULL, NULL);
1332 ptr += len;
1333 outlen -= len;
1335 if (piW->pServerName) {
1336 piA->pServerName = ptr;
1337 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1338 ptr, outlen, NULL, NULL);
1339 ptr += len;
1340 outlen -= len;
1342 break;
1345 case 5:
1347 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1348 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1350 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1352 if (piW->pPrinterName) {
1353 piA->pPrinterName = ptr;
1354 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1355 ptr, outlen, NULL, NULL);
1356 ptr += len;
1357 outlen -= len;
1359 if (piW->pPortName) {
1360 piA->pPortName = ptr;
1361 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1362 ptr, outlen, NULL, NULL);
1363 ptr += len;
1364 outlen -= len;
1366 break;
1369 case 6: /* 6A and 6W are the same structure */
1370 break;
1372 case 7:
1374 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1375 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1377 TRACE("(%u) #%u\n", level, id);
1378 if (piW->pszObjectGUID) {
1379 piA->pszObjectGUID = ptr;
1380 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1381 ptr, outlen, NULL, NULL);
1382 ptr += len;
1383 outlen -= len;
1385 break;
1388 case 9:
1390 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1391 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1392 LPDEVMODEA dmA;
1394 TRACE("(%u) #%u\n", level, id);
1395 dmA = DEVMODEdupWtoA(piW->pDevMode);
1396 if (dmA) {
1397 /* align DEVMODEA to a DWORD boundary */
1398 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1399 ptr += len;
1400 outlen -= len;
1402 piA->pDevMode = (LPDEVMODEA) ptr;
1403 len = dmA->dmSize + dmA->dmDriverExtra;
1404 memcpy(ptr, dmA, len);
1405 HeapFree(GetProcessHeap(), 0, dmA);
1407 ptr += len;
1408 outlen -= len;
1411 break;
1414 default:
1415 FIXME("for level %u\n", level);
1417 pPrintersW += pi_sizeof[level];
1418 out += pi_sizeof[level];
1419 id++;
1423 /******************************************************************
1424 * convert_driverinfo_W_to_A [internal]
1427 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1428 DWORD level, DWORD outlen, DWORD numentries)
1430 DWORD id = 0;
1431 LPSTR ptr;
1432 INT len;
1434 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1436 len = di_sizeof[level] * numentries;
1437 ptr = (LPSTR) out + len;
1438 outlen -= len;
1440 /* copy the numbers of all PRINTER_INFO_* first */
1441 memcpy(out, pDriversW, len);
1443 #define COPY_STRING(fld) \
1444 { if (diW->fld){ \
1445 diA->fld = ptr; \
1446 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1447 ptr += len; outlen -= len;\
1449 #define COPY_MULTIZ_STRING(fld) \
1450 { LPWSTR p = diW->fld; if (p){ \
1451 diA->fld = ptr; \
1452 do {\
1453 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1454 ptr += len; outlen -= len; p += len;\
1456 while(len > 1 && outlen > 0); \
1459 while (id < numentries)
1461 switch (level)
1463 case 1:
1465 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1466 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1468 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1470 COPY_STRING(pName);
1471 break;
1473 case 2:
1475 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1476 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1478 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1480 COPY_STRING(pName);
1481 COPY_STRING(pEnvironment);
1482 COPY_STRING(pDriverPath);
1483 COPY_STRING(pDataFile);
1484 COPY_STRING(pConfigFile);
1485 break;
1487 case 3:
1489 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1490 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1492 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1494 COPY_STRING(pName);
1495 COPY_STRING(pEnvironment);
1496 COPY_STRING(pDriverPath);
1497 COPY_STRING(pDataFile);
1498 COPY_STRING(pConfigFile);
1499 COPY_STRING(pHelpFile);
1500 COPY_MULTIZ_STRING(pDependentFiles);
1501 COPY_STRING(pMonitorName);
1502 COPY_STRING(pDefaultDataType);
1503 break;
1505 case 4:
1507 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1508 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1510 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1512 COPY_STRING(pName);
1513 COPY_STRING(pEnvironment);
1514 COPY_STRING(pDriverPath);
1515 COPY_STRING(pDataFile);
1516 COPY_STRING(pConfigFile);
1517 COPY_STRING(pHelpFile);
1518 COPY_MULTIZ_STRING(pDependentFiles);
1519 COPY_STRING(pMonitorName);
1520 COPY_STRING(pDefaultDataType);
1521 COPY_MULTIZ_STRING(pszzPreviousNames);
1522 break;
1524 case 5:
1526 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1527 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1529 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1531 COPY_STRING(pName);
1532 COPY_STRING(pEnvironment);
1533 COPY_STRING(pDriverPath);
1534 COPY_STRING(pDataFile);
1535 COPY_STRING(pConfigFile);
1536 break;
1538 case 6:
1540 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1541 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1543 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1545 COPY_STRING(pName);
1546 COPY_STRING(pEnvironment);
1547 COPY_STRING(pDriverPath);
1548 COPY_STRING(pDataFile);
1549 COPY_STRING(pConfigFile);
1550 COPY_STRING(pHelpFile);
1551 COPY_MULTIZ_STRING(pDependentFiles);
1552 COPY_STRING(pMonitorName);
1553 COPY_STRING(pDefaultDataType);
1554 COPY_MULTIZ_STRING(pszzPreviousNames);
1555 COPY_STRING(pszMfgName);
1556 COPY_STRING(pszOEMUrl);
1557 COPY_STRING(pszHardwareID);
1558 COPY_STRING(pszProvider);
1559 break;
1561 case 8:
1563 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1564 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1566 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1568 COPY_STRING(pName);
1569 COPY_STRING(pEnvironment);
1570 COPY_STRING(pDriverPath);
1571 COPY_STRING(pDataFile);
1572 COPY_STRING(pConfigFile);
1573 COPY_STRING(pHelpFile);
1574 COPY_MULTIZ_STRING(pDependentFiles);
1575 COPY_STRING(pMonitorName);
1576 COPY_STRING(pDefaultDataType);
1577 COPY_MULTIZ_STRING(pszzPreviousNames);
1578 COPY_STRING(pszMfgName);
1579 COPY_STRING(pszOEMUrl);
1580 COPY_STRING(pszHardwareID);
1581 COPY_STRING(pszProvider);
1582 COPY_STRING(pszPrintProcessor);
1583 COPY_STRING(pszVendorSetup);
1584 COPY_MULTIZ_STRING(pszzColorProfiles);
1585 COPY_STRING(pszInfPath);
1586 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1587 break;
1591 default:
1592 FIXME("for level %u\n", level);
1595 pDriversW += di_sizeof[level];
1596 out += di_sizeof[level];
1597 id++;
1600 #undef COPY_STRING
1601 #undef COPY_MULTIZ_STRING
1605 /***********************************************************
1606 * PRINTER_INFO_2AtoW
1607 * Creates a unicode copy of PRINTER_INFO_2A on heap
1609 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1611 LPPRINTER_INFO_2W piW;
1612 UNICODE_STRING usBuffer;
1614 if(!piA) return NULL;
1615 piW = HeapAlloc(heap, 0, sizeof(*piW));
1616 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1618 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1619 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1620 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1621 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1622 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1623 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1624 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1625 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1626 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1627 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1628 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1629 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1630 return piW;
1633 /***********************************************************
1634 * FREE_PRINTER_INFO_2W
1635 * Free PRINTER_INFO_2W and all strings
1637 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1639 if(!piW) return;
1641 HeapFree(heap,0,piW->pServerName);
1642 HeapFree(heap,0,piW->pPrinterName);
1643 HeapFree(heap,0,piW->pShareName);
1644 HeapFree(heap,0,piW->pPortName);
1645 HeapFree(heap,0,piW->pDriverName);
1646 HeapFree(heap,0,piW->pComment);
1647 HeapFree(heap,0,piW->pLocation);
1648 HeapFree(heap,0,piW->pDevMode);
1649 HeapFree(heap,0,piW->pSepFile);
1650 HeapFree(heap,0,piW->pPrintProcessor);
1651 HeapFree(heap,0,piW->pDatatype);
1652 HeapFree(heap,0,piW->pParameters);
1653 HeapFree(heap,0,piW);
1654 return;
1657 /******************************************************************
1658 * DeviceCapabilities [WINSPOOL.@]
1659 * DeviceCapabilitiesA [WINSPOOL.@]
1662 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1663 LPSTR pOutput, LPDEVMODEA lpdm)
1665 INT ret;
1667 if (!GDI_CallDeviceCapabilities16)
1669 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1670 (LPCSTR)104 );
1671 if (!GDI_CallDeviceCapabilities16) return -1;
1673 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1675 /* If DC_PAPERSIZE map POINT16s to POINTs */
1676 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1677 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1678 POINT *pt = (POINT *)pOutput;
1679 INT i;
1680 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1681 for(i = 0; i < ret; i++, pt++)
1683 pt->x = tmp[i].x;
1684 pt->y = tmp[i].y;
1686 HeapFree( GetProcessHeap(), 0, tmp );
1688 return ret;
1692 /*****************************************************************************
1693 * DeviceCapabilitiesW [WINSPOOL.@]
1695 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1698 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1699 WORD fwCapability, LPWSTR pOutput,
1700 const DEVMODEW *pDevMode)
1702 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1703 LPSTR pDeviceA = strdupWtoA(pDevice);
1704 LPSTR pPortA = strdupWtoA(pPort);
1705 INT ret;
1707 if(pOutput && (fwCapability == DC_BINNAMES ||
1708 fwCapability == DC_FILEDEPENDENCIES ||
1709 fwCapability == DC_PAPERNAMES)) {
1710 /* These need A -> W translation */
1711 INT size = 0, i;
1712 LPSTR pOutputA;
1713 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1714 dmA);
1715 if(ret == -1)
1716 return ret;
1717 switch(fwCapability) {
1718 case DC_BINNAMES:
1719 size = 24;
1720 break;
1721 case DC_PAPERNAMES:
1722 case DC_FILEDEPENDENCIES:
1723 size = 64;
1724 break;
1726 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1727 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1728 dmA);
1729 for(i = 0; i < ret; i++)
1730 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1731 pOutput + (i * size), size);
1732 HeapFree(GetProcessHeap(), 0, pOutputA);
1733 } else {
1734 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1735 (LPSTR)pOutput, dmA);
1737 HeapFree(GetProcessHeap(),0,pPortA);
1738 HeapFree(GetProcessHeap(),0,pDeviceA);
1739 HeapFree(GetProcessHeap(),0,dmA);
1740 return ret;
1743 /******************************************************************
1744 * DocumentPropertiesA [WINSPOOL.@]
1746 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1748 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1749 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1750 LPDEVMODEA pDevModeInput,DWORD fMode )
1752 LPSTR lpName = pDeviceName;
1753 static CHAR port[] = "LPT1:";
1754 LONG ret;
1756 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1757 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1760 if(!pDeviceName) {
1761 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1762 if(!lpNameW) {
1763 ERR("no name from hPrinter?\n");
1764 SetLastError(ERROR_INVALID_HANDLE);
1765 return -1;
1767 lpName = strdupWtoA(lpNameW);
1770 if (!GDI_CallExtDeviceMode16)
1772 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1773 (LPCSTR)102 );
1774 if (!GDI_CallExtDeviceMode16) {
1775 ERR("No CallExtDeviceMode16?\n");
1776 return -1;
1779 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1780 pDevModeInput, NULL, fMode);
1782 if(!pDeviceName)
1783 HeapFree(GetProcessHeap(),0,lpName);
1784 return ret;
1788 /*****************************************************************************
1789 * DocumentPropertiesW (WINSPOOL.@)
1791 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1793 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1794 LPWSTR pDeviceName,
1795 LPDEVMODEW pDevModeOutput,
1796 LPDEVMODEW pDevModeInput, DWORD fMode)
1799 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1800 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1801 LPDEVMODEA pDevModeOutputA = NULL;
1802 LONG ret;
1804 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1805 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1806 fMode);
1807 if(pDevModeOutput) {
1808 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1809 if(ret < 0) return ret;
1810 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1812 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1813 pDevModeInputA, fMode);
1814 if(pDevModeOutput) {
1815 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1816 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1818 if(fMode == 0 && ret > 0)
1819 ret += (CCHDEVICENAME + CCHFORMNAME);
1820 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1821 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1822 return ret;
1825 /******************************************************************
1826 * OpenPrinterA [WINSPOOL.@]
1828 * See OpenPrinterW.
1831 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1832 LPPRINTER_DEFAULTSA pDefault)
1834 UNICODE_STRING lpPrinterNameW;
1835 UNICODE_STRING usBuffer;
1836 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1837 PWSTR pwstrPrinterNameW;
1838 BOOL ret;
1840 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1842 if(pDefault) {
1843 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1844 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1845 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1846 pDefaultW = &DefaultW;
1848 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1849 if(pDefault) {
1850 RtlFreeUnicodeString(&usBuffer);
1851 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1853 RtlFreeUnicodeString(&lpPrinterNameW);
1854 return ret;
1857 /******************************************************************
1858 * OpenPrinterW [WINSPOOL.@]
1860 * Open a Printer / Printserver or a Printer-Object
1862 * PARAMS
1863 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1864 * phPrinter [O] The resulting Handle is stored here
1865 * pDefault [I] PTR to Default Printer Settings or NULL
1867 * RETURNS
1868 * Success: TRUE
1869 * Failure: FALSE
1871 * NOTES
1872 * lpPrinterName is one of:
1873 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1874 *| Printer: "PrinterName"
1875 *| Printer-Object: "PrinterName,Job xxx"
1876 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1877 *| XcvPort: "Servername,XcvPort PortName"
1879 * BUGS
1880 *| Printer-Object not supported
1881 *| pDefaults is ignored
1884 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1887 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1888 if (pDefault) {
1889 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1890 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1893 if(!phPrinter) {
1894 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1895 SetLastError(ERROR_INVALID_PARAMETER);
1896 return FALSE;
1899 /* Get the unique handle of the printer or Printserver */
1900 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1901 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1902 return (*phPrinter != 0);
1905 /******************************************************************
1906 * AddMonitorA [WINSPOOL.@]
1908 * See AddMonitorW.
1911 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1913 LPWSTR nameW = NULL;
1914 INT len;
1915 BOOL res;
1916 LPMONITOR_INFO_2A mi2a;
1917 MONITOR_INFO_2W mi2w;
1919 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1920 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1921 debugstr_a(mi2a ? mi2a->pName : NULL),
1922 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1923 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1925 if (Level != 2) {
1926 SetLastError(ERROR_INVALID_LEVEL);
1927 return FALSE;
1930 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1931 if (mi2a == NULL) {
1932 return FALSE;
1935 if (pName) {
1936 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1937 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1938 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1941 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1942 if (mi2a->pName) {
1943 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1944 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1945 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1947 if (mi2a->pEnvironment) {
1948 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1949 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1950 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1952 if (mi2a->pDLLName) {
1953 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1954 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1955 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1958 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1960 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1961 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1962 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1964 HeapFree(GetProcessHeap(), 0, nameW);
1965 return (res);
1968 /******************************************************************************
1969 * AddMonitorW [WINSPOOL.@]
1971 * Install a Printmonitor
1973 * PARAMS
1974 * pName [I] Servername or NULL (local Computer)
1975 * Level [I] Structure-Level (Must be 2)
1976 * pMonitors [I] PTR to MONITOR_INFO_2
1978 * RETURNS
1979 * Success: TRUE
1980 * Failure: FALSE
1982 * NOTES
1983 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1986 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1988 LPMONITOR_INFO_2W mi2w;
1990 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1991 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1992 debugstr_w(mi2w ? mi2w->pName : NULL),
1993 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1994 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1996 if ((backend == NULL) && !load_backend()) return FALSE;
1998 if (Level != 2) {
1999 SetLastError(ERROR_INVALID_LEVEL);
2000 return FALSE;
2003 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2004 if (mi2w == NULL) {
2005 return FALSE;
2008 return backend->fpAddMonitor(pName, Level, pMonitors);
2011 /******************************************************************
2012 * DeletePrinterDriverA [WINSPOOL.@]
2015 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2017 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2020 /******************************************************************
2021 * DeletePrinterDriverW [WINSPOOL.@]
2024 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2026 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2029 /******************************************************************
2030 * DeleteMonitorA [WINSPOOL.@]
2032 * See DeleteMonitorW.
2035 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2037 LPWSTR nameW = NULL;
2038 LPWSTR EnvironmentW = NULL;
2039 LPWSTR MonitorNameW = NULL;
2040 BOOL res;
2041 INT len;
2043 if (pName) {
2044 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2045 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2046 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2049 if (pEnvironment) {
2050 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2051 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2052 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2054 if (pMonitorName) {
2055 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2056 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2057 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2060 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2062 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2063 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2064 HeapFree(GetProcessHeap(), 0, nameW);
2065 return (res);
2068 /******************************************************************
2069 * DeleteMonitorW [WINSPOOL.@]
2071 * Delete a specific Printmonitor from a Printing-Environment
2073 * PARAMS
2074 * pName [I] Servername or NULL (local Computer)
2075 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2076 * pMonitorName [I] Name of the Monitor, that should be deleted
2078 * RETURNS
2079 * Success: TRUE
2080 * Failure: FALSE
2082 * NOTES
2083 * pEnvironment is ignored in Windows for the local Computer.
2086 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2089 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2090 debugstr_w(pMonitorName));
2092 if ((backend == NULL) && !load_backend()) return FALSE;
2094 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2098 /******************************************************************
2099 * DeletePortA [WINSPOOL.@]
2101 * See DeletePortW.
2104 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2106 LPWSTR nameW = NULL;
2107 LPWSTR portW = NULL;
2108 INT len;
2109 DWORD res;
2111 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2113 /* convert servername to unicode */
2114 if (pName) {
2115 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2116 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2117 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2120 /* convert portname to unicode */
2121 if (pPortName) {
2122 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2123 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2124 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2127 res = DeletePortW(nameW, hWnd, portW);
2128 HeapFree(GetProcessHeap(), 0, nameW);
2129 HeapFree(GetProcessHeap(), 0, portW);
2130 return res;
2133 /******************************************************************
2134 * DeletePortW [WINSPOOL.@]
2136 * Delete a specific Port
2138 * PARAMS
2139 * pName [I] Servername or NULL (local Computer)
2140 * hWnd [I] Handle to parent Window for the Dialog-Box
2141 * pPortName [I] Name of the Port, that should be deleted
2143 * RETURNS
2144 * Success: TRUE
2145 * Failure: FALSE
2148 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2150 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2152 if ((backend == NULL) && !load_backend()) return FALSE;
2154 if (!pPortName) {
2155 SetLastError(RPC_X_NULL_REF_POINTER);
2156 return FALSE;
2159 return backend->fpDeletePort(pName, hWnd, pPortName);
2162 /******************************************************************************
2163 * SetPrinterW [WINSPOOL.@]
2165 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2167 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2168 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2169 return FALSE;
2172 /******************************************************************************
2173 * WritePrinter [WINSPOOL.@]
2175 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2177 opened_printer_t *printer;
2178 BOOL ret = FALSE;
2180 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2182 EnterCriticalSection(&printer_handles_cs);
2183 printer = get_opened_printer(hPrinter);
2184 if(!printer)
2186 SetLastError(ERROR_INVALID_HANDLE);
2187 goto end;
2190 if(!printer->doc)
2192 SetLastError(ERROR_SPL_NO_STARTDOC);
2193 goto end;
2196 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2197 end:
2198 LeaveCriticalSection(&printer_handles_cs);
2199 return ret;
2202 /*****************************************************************************
2203 * AddFormA [WINSPOOL.@]
2205 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2207 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2208 return 1;
2211 /*****************************************************************************
2212 * AddFormW [WINSPOOL.@]
2214 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2216 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2217 return 1;
2220 /*****************************************************************************
2221 * AddJobA [WINSPOOL.@]
2223 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2225 BOOL ret;
2226 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2227 DWORD needed;
2229 if(Level != 1) {
2230 SetLastError(ERROR_INVALID_LEVEL);
2231 return FALSE;
2234 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2236 if(ret) {
2237 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2238 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2239 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2240 if(*pcbNeeded > cbBuf) {
2241 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2242 ret = FALSE;
2243 } else {
2244 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2245 addjobA->JobId = addjobW->JobId;
2246 addjobA->Path = (char *)(addjobA + 1);
2247 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2250 return ret;
2253 /*****************************************************************************
2254 * AddJobW [WINSPOOL.@]
2256 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2258 opened_printer_t *printer;
2259 job_t *job;
2260 BOOL ret = FALSE;
2261 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2262 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2263 WCHAR path[MAX_PATH], filename[MAX_PATH];
2264 DWORD len;
2265 ADDJOB_INFO_1W *addjob;
2267 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2269 EnterCriticalSection(&printer_handles_cs);
2271 printer = get_opened_printer(hPrinter);
2273 if(!printer) {
2274 SetLastError(ERROR_INVALID_HANDLE);
2275 goto end;
2278 if(Level != 1) {
2279 SetLastError(ERROR_INVALID_LEVEL);
2280 goto end;
2283 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2284 if(!job)
2285 goto end;
2287 job->job_id = InterlockedIncrement(&next_job_id);
2289 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2290 if(path[len - 1] != '\\')
2291 path[len++] = '\\';
2292 memcpy(path + len, spool_path, sizeof(spool_path));
2293 sprintfW(filename, fmtW, path, job->job_id);
2295 len = strlenW(filename);
2296 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2297 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2298 job->document_title = strdupW(default_doc_title);
2299 list_add_tail(&printer->queue->jobs, &job->entry);
2301 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2302 if(*pcbNeeded <= cbBuf) {
2303 addjob = (ADDJOB_INFO_1W*)pData;
2304 addjob->JobId = job->job_id;
2305 addjob->Path = (WCHAR *)(addjob + 1);
2306 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2307 ret = TRUE;
2308 } else
2309 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2311 end:
2312 LeaveCriticalSection(&printer_handles_cs);
2313 return ret;
2316 /*****************************************************************************
2317 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2319 * Return the PATH for the Print-Processors
2321 * See GetPrintProcessorDirectoryW.
2325 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2326 DWORD level, LPBYTE Info,
2327 DWORD cbBuf, LPDWORD pcbNeeded)
2329 LPWSTR serverW = NULL;
2330 LPWSTR envW = NULL;
2331 BOOL ret;
2332 INT len;
2334 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2335 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2338 if (server) {
2339 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2340 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2341 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2344 if (env) {
2345 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2346 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2347 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2350 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2351 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2353 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2354 cbBuf, pcbNeeded);
2356 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2357 cbBuf, NULL, NULL) > 0;
2360 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2361 HeapFree(GetProcessHeap(), 0, envW);
2362 HeapFree(GetProcessHeap(), 0, serverW);
2363 return ret;
2366 /*****************************************************************************
2367 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2369 * Return the PATH for the Print-Processors
2371 * PARAMS
2372 * server [I] Servername (NT only) or NULL (local Computer)
2373 * env [I] Printing-Environment (see below) or NULL (Default)
2374 * level [I] Structure-Level (must be 1)
2375 * Info [O] PTR to Buffer that receives the Result
2376 * cbBuf [I] Size of Buffer at "Info"
2377 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2378 * required for the Buffer at "Info"
2380 * RETURNS
2381 * Success: TRUE and in pcbNeeded the Bytes used in Info
2382 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2383 * if cbBuf is too small
2385 * Native Values returned in Info on Success:
2386 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2387 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2388 *| win9x(Windows 4.0): "%winsysdir%"
2390 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2392 * BUGS
2393 * Only NULL or "" is supported for server
2396 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2397 DWORD level, LPBYTE Info,
2398 DWORD cbBuf, LPDWORD pcbNeeded)
2401 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2402 Info, cbBuf, pcbNeeded);
2404 if ((backend == NULL) && !load_backend()) return FALSE;
2406 if (level != 1) {
2407 /* (Level != 1) is ignored in win9x */
2408 SetLastError(ERROR_INVALID_LEVEL);
2409 return FALSE;
2412 if (pcbNeeded == NULL) {
2413 /* (pcbNeeded == NULL) is ignored in win9x */
2414 SetLastError(RPC_X_NULL_REF_POINTER);
2415 return FALSE;
2418 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2421 /*****************************************************************************
2422 * WINSPOOL_OpenDriverReg [internal]
2424 * opens the registry for the printer drivers depending on the given input
2425 * variable pEnvironment
2427 * RETURNS:
2428 * the opened hkey on success
2429 * NULL on error
2431 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2433 HKEY retval = NULL;
2434 LPWSTR buffer;
2435 const printenv_t * env;
2437 TRACE("(%s)\n", debugstr_w(pEnvironment));
2439 env = validate_envW(pEnvironment);
2440 if (!env) return NULL;
2442 buffer = HeapAlloc( GetProcessHeap(), 0,
2443 (strlenW(DriversW) + strlenW(env->envname) +
2444 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2445 if(buffer) {
2446 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2447 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2448 HeapFree(GetProcessHeap(), 0, buffer);
2450 return retval;
2453 /*****************************************************************************
2454 * AddPrinterW [WINSPOOL.@]
2456 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2458 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2459 LPDEVMODEA dmA;
2460 LPDEVMODEW dmW;
2461 HANDLE retval;
2462 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2463 LONG size;
2464 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2465 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2466 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2467 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2468 statusW[] = {'S','t','a','t','u','s',0},
2469 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2471 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2473 if(pName != NULL) {
2474 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2475 SetLastError(ERROR_INVALID_PARAMETER);
2476 return 0;
2478 if(Level != 2) {
2479 ERR("Level = %d, unsupported!\n", Level);
2480 SetLastError(ERROR_INVALID_LEVEL);
2481 return 0;
2483 if(!pPrinter) {
2484 SetLastError(ERROR_INVALID_PARAMETER);
2485 return 0;
2487 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2488 ERROR_SUCCESS) {
2489 ERR("Can't create Printers key\n");
2490 return 0;
2492 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2493 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2494 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2495 RegCloseKey(hkeyPrinter);
2496 RegCloseKey(hkeyPrinters);
2497 return 0;
2499 RegCloseKey(hkeyPrinter);
2501 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2502 if(!hkeyDrivers) {
2503 ERR("Can't create Drivers key\n");
2504 RegCloseKey(hkeyPrinters);
2505 return 0;
2507 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2508 ERROR_SUCCESS) {
2509 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2510 RegCloseKey(hkeyPrinters);
2511 RegCloseKey(hkeyDrivers);
2512 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2513 return 0;
2515 RegCloseKey(hkeyDriver);
2516 RegCloseKey(hkeyDrivers);
2518 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2519 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2520 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2521 RegCloseKey(hkeyPrinters);
2522 return 0;
2525 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2526 ERROR_SUCCESS) {
2527 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2528 SetLastError(ERROR_INVALID_PRINTER_NAME);
2529 RegCloseKey(hkeyPrinters);
2530 return 0;
2532 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2533 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2534 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2536 /* See if we can load the driver. We may need the devmode structure anyway
2538 * FIXME:
2539 * Note that DocumentPropertiesW will briefly try to open the printer we
2540 * just create to find a DEVMODEA struct (it will use the WINEPS default
2541 * one in case it is not there, so we are ok).
2543 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2545 if(size < 0) {
2546 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2547 size = sizeof(DEVMODEW);
2549 if(pi->pDevMode)
2550 dmW = pi->pDevMode;
2551 else
2553 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2554 dmW->dmSize = size;
2555 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2557 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2558 HeapFree(GetProcessHeap(),0,dmW);
2559 dmW=NULL;
2561 else
2563 /* set devmode to printer name */
2564 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2568 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2569 and we support these drivers. NT writes DEVMODEW so somehow
2570 we'll need to distinguish between these when we support NT
2571 drivers */
2572 if (dmW)
2574 dmA = DEVMODEdupWtoA(dmW);
2575 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2576 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2577 HeapFree(GetProcessHeap(), 0, dmA);
2578 if(!pi->pDevMode)
2579 HeapFree(GetProcessHeap(), 0, dmW);
2581 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2582 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2583 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2584 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2586 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2587 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2588 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2589 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2590 (LPBYTE)&pi->Priority, sizeof(DWORD));
2591 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2592 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2593 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2594 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2595 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2596 (LPBYTE)&pi->Status, sizeof(DWORD));
2597 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2598 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2600 RegCloseKey(hkeyPrinter);
2601 RegCloseKey(hkeyPrinters);
2602 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2603 ERR("OpenPrinter failing\n");
2604 return 0;
2606 return retval;
2609 /*****************************************************************************
2610 * AddPrinterA [WINSPOOL.@]
2612 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2614 UNICODE_STRING pNameW;
2615 PWSTR pwstrNameW;
2616 PRINTER_INFO_2W *piW;
2617 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2618 HANDLE ret;
2620 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2621 if(Level != 2) {
2622 ERR("Level = %d, unsupported!\n", Level);
2623 SetLastError(ERROR_INVALID_LEVEL);
2624 return 0;
2626 pwstrNameW = asciitounicode(&pNameW,pName);
2627 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2629 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2631 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2632 RtlFreeUnicodeString(&pNameW);
2633 return ret;
2637 /*****************************************************************************
2638 * ClosePrinter [WINSPOOL.@]
2640 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2642 UINT_PTR i = (UINT_PTR)hPrinter;
2643 opened_printer_t *printer = NULL;
2644 BOOL ret = FALSE;
2646 TRACE("(%p)\n", hPrinter);
2648 EnterCriticalSection(&printer_handles_cs);
2650 if ((i > 0) && (i <= nb_printer_handles))
2651 printer = printer_handles[i - 1];
2654 if(printer)
2656 struct list *cursor, *cursor2;
2658 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2660 if (printer->backend_printer) {
2661 backend->fpClosePrinter(printer->backend_printer);
2664 if(printer->doc)
2665 EndDocPrinter(hPrinter);
2667 if(InterlockedDecrement(&printer->queue->ref) == 0)
2669 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2671 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2672 ScheduleJob(hPrinter, job->job_id);
2674 HeapFree(GetProcessHeap(), 0, printer->queue);
2677 HeapFree(GetProcessHeap(), 0, printer->printername);
2678 HeapFree(GetProcessHeap(), 0, printer->name);
2679 HeapFree(GetProcessHeap(), 0, printer);
2680 printer_handles[i - 1] = NULL;
2681 ret = TRUE;
2683 LeaveCriticalSection(&printer_handles_cs);
2684 return ret;
2687 /*****************************************************************************
2688 * DeleteFormA [WINSPOOL.@]
2690 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2692 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2693 return 1;
2696 /*****************************************************************************
2697 * DeleteFormW [WINSPOOL.@]
2699 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2701 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2702 return 1;
2705 /*****************************************************************************
2706 * DeletePrinter [WINSPOOL.@]
2708 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2710 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2711 HKEY hkeyPrinters, hkey;
2713 if(!lpNameW) {
2714 SetLastError(ERROR_INVALID_HANDLE);
2715 return FALSE;
2717 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2718 RegDeleteTreeW(hkeyPrinters, lpNameW);
2719 RegCloseKey(hkeyPrinters);
2721 WriteProfileStringW(devicesW, lpNameW, NULL);
2722 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2724 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2725 RegDeleteValueW(hkey, lpNameW);
2726 RegCloseKey(hkey);
2729 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2730 RegDeleteValueW(hkey, lpNameW);
2731 RegCloseKey(hkey);
2733 return TRUE;
2736 /*****************************************************************************
2737 * SetPrinterA [WINSPOOL.@]
2739 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2740 DWORD Command)
2742 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2743 return FALSE;
2746 /*****************************************************************************
2747 * SetJobA [WINSPOOL.@]
2749 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2750 LPBYTE pJob, DWORD Command)
2752 BOOL ret;
2753 LPBYTE JobW;
2754 UNICODE_STRING usBuffer;
2756 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2758 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2759 are all ignored by SetJob, so we don't bother copying them */
2760 switch(Level)
2762 case 0:
2763 JobW = NULL;
2764 break;
2765 case 1:
2767 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2768 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2770 JobW = (LPBYTE)info1W;
2771 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2772 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2773 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2774 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2775 info1W->Status = info1A->Status;
2776 info1W->Priority = info1A->Priority;
2777 info1W->Position = info1A->Position;
2778 info1W->PagesPrinted = info1A->PagesPrinted;
2779 break;
2781 case 2:
2783 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2784 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2786 JobW = (LPBYTE)info2W;
2787 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2788 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2789 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2790 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2791 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2792 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2793 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2794 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2795 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2796 info2W->Status = info2A->Status;
2797 info2W->Priority = info2A->Priority;
2798 info2W->Position = info2A->Position;
2799 info2W->StartTime = info2A->StartTime;
2800 info2W->UntilTime = info2A->UntilTime;
2801 info2W->PagesPrinted = info2A->PagesPrinted;
2802 break;
2804 case 3:
2805 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2806 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2807 break;
2808 default:
2809 SetLastError(ERROR_INVALID_LEVEL);
2810 return FALSE;
2813 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2815 switch(Level)
2817 case 1:
2819 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2820 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2821 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2822 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2823 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2824 break;
2826 case 2:
2828 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2829 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2830 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2831 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2832 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2833 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2834 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2835 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2836 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2837 break;
2840 HeapFree(GetProcessHeap(), 0, JobW);
2842 return ret;
2845 /*****************************************************************************
2846 * SetJobW [WINSPOOL.@]
2848 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2849 LPBYTE pJob, DWORD Command)
2851 BOOL ret = FALSE;
2852 job_t *job;
2854 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2855 FIXME("Ignoring everything other than document title\n");
2857 EnterCriticalSection(&printer_handles_cs);
2858 job = get_job(hPrinter, JobId);
2859 if(!job)
2860 goto end;
2862 switch(Level)
2864 case 0:
2865 break;
2866 case 1:
2868 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2869 HeapFree(GetProcessHeap(), 0, job->document_title);
2870 job->document_title = strdupW(info1->pDocument);
2871 break;
2873 case 2:
2875 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2876 HeapFree(GetProcessHeap(), 0, job->document_title);
2877 job->document_title = strdupW(info2->pDocument);
2878 break;
2880 case 3:
2881 break;
2882 default:
2883 SetLastError(ERROR_INVALID_LEVEL);
2884 goto end;
2886 ret = TRUE;
2887 end:
2888 LeaveCriticalSection(&printer_handles_cs);
2889 return ret;
2892 /*****************************************************************************
2893 * EndDocPrinter [WINSPOOL.@]
2895 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2897 opened_printer_t *printer;
2898 BOOL ret = FALSE;
2899 TRACE("(%p)\n", hPrinter);
2901 EnterCriticalSection(&printer_handles_cs);
2903 printer = get_opened_printer(hPrinter);
2904 if(!printer)
2906 SetLastError(ERROR_INVALID_HANDLE);
2907 goto end;
2910 if(!printer->doc)
2912 SetLastError(ERROR_SPL_NO_STARTDOC);
2913 goto end;
2916 CloseHandle(printer->doc->hf);
2917 ScheduleJob(hPrinter, printer->doc->job_id);
2918 HeapFree(GetProcessHeap(), 0, printer->doc);
2919 printer->doc = NULL;
2920 ret = TRUE;
2921 end:
2922 LeaveCriticalSection(&printer_handles_cs);
2923 return ret;
2926 /*****************************************************************************
2927 * EndPagePrinter [WINSPOOL.@]
2929 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2931 FIXME("(%p): stub\n", hPrinter);
2932 return TRUE;
2935 /*****************************************************************************
2936 * StartDocPrinterA [WINSPOOL.@]
2938 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2940 UNICODE_STRING usBuffer;
2941 DOC_INFO_2W doc2W;
2942 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2943 DWORD ret;
2945 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2946 or one (DOC_INFO_3) extra DWORDs */
2948 switch(Level) {
2949 case 2:
2950 doc2W.JobId = doc2->JobId;
2951 /* fall through */
2952 case 3:
2953 doc2W.dwMode = doc2->dwMode;
2954 /* fall through */
2955 case 1:
2956 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2957 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2958 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2959 break;
2961 default:
2962 SetLastError(ERROR_INVALID_LEVEL);
2963 return FALSE;
2966 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2968 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2969 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2970 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2972 return ret;
2975 /*****************************************************************************
2976 * StartDocPrinterW [WINSPOOL.@]
2978 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2980 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2981 opened_printer_t *printer;
2982 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2983 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2984 JOB_INFO_1W job_info;
2985 DWORD needed, ret = 0;
2986 HANDLE hf;
2987 WCHAR *filename;
2988 job_t *job;
2990 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2991 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2992 debugstr_w(doc->pDatatype));
2994 if(Level < 1 || Level > 3)
2996 SetLastError(ERROR_INVALID_LEVEL);
2997 return 0;
3000 EnterCriticalSection(&printer_handles_cs);
3001 printer = get_opened_printer(hPrinter);
3002 if(!printer)
3004 SetLastError(ERROR_INVALID_HANDLE);
3005 goto end;
3008 if(printer->doc)
3010 SetLastError(ERROR_INVALID_PRINTER_STATE);
3011 goto end;
3014 /* Even if we're printing to a file we still add a print job, we'll
3015 just ignore the spool file name */
3017 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3019 ERR("AddJob failed gle %u\n", GetLastError());
3020 goto end;
3023 /* use pOutputFile only, when it is a real filename */
3024 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3025 filename = doc->pOutputFile;
3026 else
3027 filename = addjob->Path;
3029 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3030 if(hf == INVALID_HANDLE_VALUE)
3031 goto end;
3033 memset(&job_info, 0, sizeof(job_info));
3034 job_info.pDocument = doc->pDocName;
3035 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3037 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3038 printer->doc->hf = hf;
3039 ret = printer->doc->job_id = addjob->JobId;
3040 job = get_job(hPrinter, ret);
3041 job->portname = strdupW(doc->pOutputFile);
3043 end:
3044 LeaveCriticalSection(&printer_handles_cs);
3046 return ret;
3049 /*****************************************************************************
3050 * StartPagePrinter [WINSPOOL.@]
3052 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3054 FIXME("(%p): stub\n", hPrinter);
3055 return TRUE;
3058 /*****************************************************************************
3059 * GetFormA [WINSPOOL.@]
3061 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3062 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3064 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3065 Level,pForm,cbBuf,pcbNeeded);
3066 return FALSE;
3069 /*****************************************************************************
3070 * GetFormW [WINSPOOL.@]
3072 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3073 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3075 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3076 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3077 return FALSE;
3080 /*****************************************************************************
3081 * SetFormA [WINSPOOL.@]
3083 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3084 LPBYTE pForm)
3086 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3087 return FALSE;
3090 /*****************************************************************************
3091 * SetFormW [WINSPOOL.@]
3093 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3094 LPBYTE pForm)
3096 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3097 return FALSE;
3100 /*****************************************************************************
3101 * ReadPrinter [WINSPOOL.@]
3103 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3104 LPDWORD pNoBytesRead)
3106 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3107 return FALSE;
3110 /*****************************************************************************
3111 * ResetPrinterA [WINSPOOL.@]
3113 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3115 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3116 return FALSE;
3119 /*****************************************************************************
3120 * ResetPrinterW [WINSPOOL.@]
3122 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3124 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3125 return FALSE;
3128 /*****************************************************************************
3129 * WINSPOOL_GetDWORDFromReg
3131 * Return DWORD associated with ValueName from hkey.
3133 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3135 DWORD sz = sizeof(DWORD), type, value = 0;
3136 LONG ret;
3138 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3140 if(ret != ERROR_SUCCESS) {
3141 WARN("Got ret = %d on name %s\n", ret, ValueName);
3142 return 0;
3144 if(type != REG_DWORD) {
3145 ERR("Got type %d\n", type);
3146 return 0;
3148 return value;
3152 /*****************************************************************************
3153 * get_filename_from_reg [internal]
3155 * Get ValueName from hkey storing result in out
3156 * when the Value in the registry has only a filename, use driverdir as prefix
3157 * outlen is space left in out
3158 * String is stored either as unicode or ascii
3162 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3163 LPBYTE out, DWORD outlen, LPDWORD needed)
3165 WCHAR filename[MAX_PATH];
3166 DWORD size;
3167 DWORD type;
3168 LONG ret;
3169 LPWSTR buffer = filename;
3170 LPWSTR ptr;
3172 *needed = 0;
3173 size = sizeof(filename);
3174 buffer[0] = '\0';
3175 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3176 if (ret == ERROR_MORE_DATA) {
3177 TRACE("need dynamic buffer: %u\n", size);
3178 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3179 if (!buffer) {
3180 /* No Memory is bad */
3181 return FALSE;
3183 buffer[0] = '\0';
3184 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3187 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3188 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3189 return FALSE;
3192 ptr = buffer;
3193 while (ptr) {
3194 /* do we have a full path ? */
3195 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3196 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3198 if (!ret) {
3199 /* we must build the full Path */
3200 *needed += dirlen;
3201 if ((out) && (outlen > dirlen)) {
3202 lstrcpyW((LPWSTR)out, driverdir);
3203 out += dirlen;
3204 outlen -= dirlen;
3206 else
3207 out = NULL;
3210 /* write the filename */
3211 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3212 if ((out) && (outlen >= size)) {
3213 lstrcpyW((LPWSTR)out, ptr);
3214 out += size;
3215 outlen -= size;
3217 else
3218 out = NULL;
3219 *needed += size;
3220 ptr += lstrlenW(ptr)+1;
3221 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3224 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3226 /* write the multisz-termination */
3227 if (type == REG_MULTI_SZ) {
3228 size = sizeof(WCHAR);
3230 *needed += size;
3231 if (out && (outlen >= size)) {
3232 memset (out, 0, size);
3235 return TRUE;
3238 /*****************************************************************************
3239 * WINSPOOL_GetStringFromReg
3241 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3242 * String is stored as unicode.
3244 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3245 DWORD buflen, DWORD *needed)
3247 DWORD sz = buflen, type;
3248 LONG ret;
3250 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3251 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3252 WARN("Got ret = %d\n", ret);
3253 *needed = 0;
3254 return FALSE;
3256 /* add space for terminating '\0' */
3257 sz += sizeof(WCHAR);
3258 *needed = sz;
3260 if (ptr)
3261 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3263 return TRUE;
3266 /*****************************************************************************
3267 * WINSPOOL_GetDefaultDevMode
3269 * Get a default DevMode values for wineps.
3270 * FIXME - use ppd.
3273 static void WINSPOOL_GetDefaultDevMode(
3274 LPBYTE ptr,
3275 DWORD buflen, DWORD *needed)
3277 DEVMODEW dm;
3278 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3280 /* fill default DEVMODE - should be read from ppd... */
3281 ZeroMemory( &dm, sizeof(dm) );
3282 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3283 dm.dmSpecVersion = DM_SPECVERSION;
3284 dm.dmDriverVersion = 1;
3285 dm.dmSize = sizeof(DEVMODEW);
3286 dm.dmDriverExtra = 0;
3287 dm.dmFields =
3288 DM_ORIENTATION | DM_PAPERSIZE |
3289 DM_PAPERLENGTH | DM_PAPERWIDTH |
3290 DM_SCALE |
3291 DM_COPIES |
3292 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3293 DM_YRESOLUTION | DM_TTOPTION;
3295 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3296 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3297 dm.u1.s1.dmPaperLength = 2970;
3298 dm.u1.s1.dmPaperWidth = 2100;
3300 dm.u1.s1.dmScale = 100;
3301 dm.u1.s1.dmCopies = 1;
3302 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3303 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3304 /* dm.dmColor */
3305 /* dm.dmDuplex */
3306 dm.dmYResolution = 300; /* 300dpi */
3307 dm.dmTTOption = DMTT_BITMAP;
3308 /* dm.dmCollate */
3309 /* dm.dmFormName */
3310 /* dm.dmLogPixels */
3311 /* dm.dmBitsPerPel */
3312 /* dm.dmPelsWidth */
3313 /* dm.dmPelsHeight */
3314 /* dm.u2.dmDisplayFlags */
3315 /* dm.dmDisplayFrequency */
3316 /* dm.dmICMMethod */
3317 /* dm.dmICMIntent */
3318 /* dm.dmMediaType */
3319 /* dm.dmDitherType */
3320 /* dm.dmReserved1 */
3321 /* dm.dmReserved2 */
3322 /* dm.dmPanningWidth */
3323 /* dm.dmPanningHeight */
3325 if(buflen >= sizeof(DEVMODEW))
3326 memcpy(ptr, &dm, sizeof(DEVMODEW));
3327 *needed = sizeof(DEVMODEW);
3330 /*****************************************************************************
3331 * WINSPOOL_GetDevModeFromReg
3333 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3334 * DevMode is stored either as unicode or ascii.
3336 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3337 LPBYTE ptr,
3338 DWORD buflen, DWORD *needed)
3340 DWORD sz = buflen, type;
3341 LONG ret;
3343 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3344 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3345 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3346 if (sz < sizeof(DEVMODEA))
3348 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3349 return FALSE;
3351 /* ensures that dmSize is not erratically bogus if registry is invalid */
3352 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3353 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3354 sz += (CCHDEVICENAME + CCHFORMNAME);
3355 if (ptr && (buflen >= sz)) {
3356 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3357 memcpy(ptr, dmW, sz);
3358 HeapFree(GetProcessHeap(),0,dmW);
3360 *needed = sz;
3361 return TRUE;
3364 /*********************************************************************
3365 * WINSPOOL_GetPrinter_1
3367 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3369 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3370 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3372 DWORD size, left = cbBuf;
3373 BOOL space = (cbBuf > 0);
3374 LPBYTE ptr = buf;
3376 *pcbNeeded = 0;
3378 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3379 if(space && size <= left) {
3380 pi1->pName = (LPWSTR)ptr;
3381 ptr += size;
3382 left -= size;
3383 } else
3384 space = FALSE;
3385 *pcbNeeded += size;
3388 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3389 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3390 if(space && size <= left) {
3391 pi1->pDescription = (LPWSTR)ptr;
3392 ptr += size;
3393 left -= size;
3394 } else
3395 space = FALSE;
3396 *pcbNeeded += size;
3399 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3400 if(space && size <= left) {
3401 pi1->pComment = (LPWSTR)ptr;
3402 ptr += size;
3403 left -= size;
3404 } else
3405 space = FALSE;
3406 *pcbNeeded += size;
3409 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3411 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3412 memset(pi1, 0, sizeof(*pi1));
3414 return space;
3416 /*********************************************************************
3417 * WINSPOOL_GetPrinter_2
3419 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3421 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3422 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3424 DWORD size, left = cbBuf;
3425 BOOL space = (cbBuf > 0);
3426 LPBYTE ptr = buf;
3428 *pcbNeeded = 0;
3430 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3431 if(space && size <= left) {
3432 pi2->pPrinterName = (LPWSTR)ptr;
3433 ptr += size;
3434 left -= size;
3435 } else
3436 space = FALSE;
3437 *pcbNeeded += size;
3439 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3440 if(space && size <= left) {
3441 pi2->pShareName = (LPWSTR)ptr;
3442 ptr += size;
3443 left -= size;
3444 } else
3445 space = FALSE;
3446 *pcbNeeded += size;
3448 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3449 if(space && size <= left) {
3450 pi2->pPortName = (LPWSTR)ptr;
3451 ptr += size;
3452 left -= size;
3453 } else
3454 space = FALSE;
3455 *pcbNeeded += size;
3457 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3458 if(space && size <= left) {
3459 pi2->pDriverName = (LPWSTR)ptr;
3460 ptr += size;
3461 left -= size;
3462 } else
3463 space = FALSE;
3464 *pcbNeeded += size;
3466 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3467 if(space && size <= left) {
3468 pi2->pComment = (LPWSTR)ptr;
3469 ptr += size;
3470 left -= size;
3471 } else
3472 space = FALSE;
3473 *pcbNeeded += size;
3475 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3476 if(space && size <= left) {
3477 pi2->pLocation = (LPWSTR)ptr;
3478 ptr += size;
3479 left -= size;
3480 } else
3481 space = FALSE;
3482 *pcbNeeded += size;
3484 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3485 if(space && size <= left) {
3486 pi2->pDevMode = (LPDEVMODEW)ptr;
3487 ptr += size;
3488 left -= size;
3489 } else
3490 space = FALSE;
3491 *pcbNeeded += size;
3493 else
3495 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3496 if(space && size <= left) {
3497 pi2->pDevMode = (LPDEVMODEW)ptr;
3498 ptr += size;
3499 left -= size;
3500 } else
3501 space = FALSE;
3502 *pcbNeeded += size;
3504 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3505 if(space && size <= left) {
3506 pi2->pSepFile = (LPWSTR)ptr;
3507 ptr += size;
3508 left -= size;
3509 } else
3510 space = FALSE;
3511 *pcbNeeded += size;
3513 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3514 if(space && size <= left) {
3515 pi2->pPrintProcessor = (LPWSTR)ptr;
3516 ptr += size;
3517 left -= size;
3518 } else
3519 space = FALSE;
3520 *pcbNeeded += size;
3522 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3523 if(space && size <= left) {
3524 pi2->pDatatype = (LPWSTR)ptr;
3525 ptr += size;
3526 left -= size;
3527 } else
3528 space = FALSE;
3529 *pcbNeeded += size;
3531 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3532 if(space && size <= left) {
3533 pi2->pParameters = (LPWSTR)ptr;
3534 ptr += size;
3535 left -= size;
3536 } else
3537 space = FALSE;
3538 *pcbNeeded += size;
3540 if(pi2) {
3541 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3542 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3543 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3544 "Default Priority");
3545 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3546 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3549 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3550 memset(pi2, 0, sizeof(*pi2));
3552 return space;
3555 /*********************************************************************
3556 * WINSPOOL_GetPrinter_4
3558 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3560 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3561 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3563 DWORD size, left = cbBuf;
3564 BOOL space = (cbBuf > 0);
3565 LPBYTE ptr = buf;
3567 *pcbNeeded = 0;
3569 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3570 if(space && size <= left) {
3571 pi4->pPrinterName = (LPWSTR)ptr;
3572 ptr += size;
3573 left -= size;
3574 } else
3575 space = FALSE;
3576 *pcbNeeded += size;
3578 if(pi4) {
3579 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3582 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3583 memset(pi4, 0, sizeof(*pi4));
3585 return space;
3588 /*********************************************************************
3589 * WINSPOOL_GetPrinter_5
3591 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3593 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3594 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3596 DWORD size, left = cbBuf;
3597 BOOL space = (cbBuf > 0);
3598 LPBYTE ptr = buf;
3600 *pcbNeeded = 0;
3602 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3603 if(space && size <= left) {
3604 pi5->pPrinterName = (LPWSTR)ptr;
3605 ptr += size;
3606 left -= size;
3607 } else
3608 space = FALSE;
3609 *pcbNeeded += size;
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3612 if(space && size <= left) {
3613 pi5->pPortName = (LPWSTR)ptr;
3614 ptr += size;
3615 left -= size;
3616 } else
3617 space = FALSE;
3618 *pcbNeeded += size;
3620 if(pi5) {
3621 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3622 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3623 "dnsTimeout");
3624 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3625 "txTimeout");
3628 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3629 memset(pi5, 0, sizeof(*pi5));
3631 return space;
3634 /*********************************************************************
3635 * WINSPOOL_GetPrinter_7
3637 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3639 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3640 DWORD cbBuf, LPDWORD pcbNeeded)
3642 DWORD size, left = cbBuf;
3643 BOOL space = (cbBuf > 0);
3644 LPBYTE ptr = buf;
3646 *pcbNeeded = 0;
3648 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3650 ptr = NULL;
3651 size = sizeof(pi7->pszObjectGUID);
3653 if (space && size <= left) {
3654 pi7->pszObjectGUID = (LPWSTR)ptr;
3655 ptr += size;
3656 left -= size;
3657 } else
3658 space = FALSE;
3659 *pcbNeeded += size;
3660 if (pi7) {
3661 /* We do not have a Directory Service */
3662 pi7->dwAction = DSPRINT_UNPUBLISH;
3665 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3666 memset(pi7, 0, sizeof(*pi7));
3668 return space;
3671 /*********************************************************************
3672 * WINSPOOL_GetPrinter_9
3674 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3676 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3677 DWORD cbBuf, LPDWORD pcbNeeded)
3679 DWORD size;
3680 BOOL space = (cbBuf > 0);
3682 *pcbNeeded = 0;
3684 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3685 if(space && size <= cbBuf) {
3686 pi9->pDevMode = (LPDEVMODEW)buf;
3687 } else
3688 space = FALSE;
3689 *pcbNeeded += size;
3691 else
3693 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3694 if(space && size <= cbBuf) {
3695 pi9->pDevMode = (LPDEVMODEW)buf;
3696 } else
3697 space = FALSE;
3698 *pcbNeeded += size;
3701 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3702 memset(pi9, 0, sizeof(*pi9));
3704 return space;
3707 /*****************************************************************************
3708 * GetPrinterW [WINSPOOL.@]
3710 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3711 DWORD cbBuf, LPDWORD pcbNeeded)
3713 LPCWSTR name;
3714 DWORD size, needed = 0;
3715 LPBYTE ptr = NULL;
3716 HKEY hkeyPrinter, hkeyPrinters;
3717 BOOL ret;
3719 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3721 if (!(name = get_opened_printer_name(hPrinter))) {
3722 SetLastError(ERROR_INVALID_HANDLE);
3723 return FALSE;
3726 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3727 ERROR_SUCCESS) {
3728 ERR("Can't create Printers key\n");
3729 return FALSE;
3731 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3733 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3734 RegCloseKey(hkeyPrinters);
3735 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3736 return FALSE;
3739 switch(Level) {
3740 case 2:
3742 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3744 size = sizeof(PRINTER_INFO_2W);
3745 if(size <= cbBuf) {
3746 ptr = pPrinter + size;
3747 cbBuf -= size;
3748 memset(pPrinter, 0, size);
3749 } else {
3750 pi2 = NULL;
3751 cbBuf = 0;
3753 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3754 needed += size;
3755 break;
3758 case 4:
3760 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3762 size = sizeof(PRINTER_INFO_4W);
3763 if(size <= cbBuf) {
3764 ptr = pPrinter + size;
3765 cbBuf -= size;
3766 memset(pPrinter, 0, size);
3767 } else {
3768 pi4 = NULL;
3769 cbBuf = 0;
3771 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3772 needed += size;
3773 break;
3777 case 5:
3779 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3781 size = sizeof(PRINTER_INFO_5W);
3782 if(size <= cbBuf) {
3783 ptr = pPrinter + size;
3784 cbBuf -= size;
3785 memset(pPrinter, 0, size);
3786 } else {
3787 pi5 = NULL;
3788 cbBuf = 0;
3791 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3792 needed += size;
3793 break;
3797 case 6:
3799 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3801 size = sizeof(PRINTER_INFO_6);
3802 if (size <= cbBuf) {
3803 /* FIXME: We do not update the status yet */
3804 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3805 ret = TRUE;
3806 } else {
3807 ret = FALSE;
3810 needed += size;
3811 break;
3814 case 7:
3816 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3818 size = sizeof(PRINTER_INFO_7W);
3819 if (size <= cbBuf) {
3820 ptr = pPrinter + size;
3821 cbBuf -= size;
3822 memset(pPrinter, 0, size);
3823 } else {
3824 pi7 = NULL;
3825 cbBuf = 0;
3828 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3829 needed += size;
3830 break;
3834 case 9:
3836 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3838 size = sizeof(PRINTER_INFO_9W);
3839 if(size <= cbBuf) {
3840 ptr = pPrinter + size;
3841 cbBuf -= size;
3842 memset(pPrinter, 0, size);
3843 } else {
3844 pi9 = NULL;
3845 cbBuf = 0;
3848 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3849 needed += size;
3850 break;
3854 default:
3855 FIXME("Unimplemented level %d\n", Level);
3856 SetLastError(ERROR_INVALID_LEVEL);
3857 RegCloseKey(hkeyPrinters);
3858 RegCloseKey(hkeyPrinter);
3859 return FALSE;
3862 RegCloseKey(hkeyPrinter);
3863 RegCloseKey(hkeyPrinters);
3865 TRACE("returning %d needed = %d\n", ret, needed);
3866 if(pcbNeeded) *pcbNeeded = needed;
3867 if(!ret)
3868 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3869 return ret;
3872 /*****************************************************************************
3873 * GetPrinterA [WINSPOOL.@]
3875 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3876 DWORD cbBuf, LPDWORD pcbNeeded)
3878 BOOL ret;
3879 LPBYTE buf = NULL;
3881 if (cbBuf)
3882 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3884 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3885 if (ret)
3886 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3887 HeapFree(GetProcessHeap(), 0, buf);
3889 return ret;
3892 /*****************************************************************************
3893 * WINSPOOL_EnumPrintersW
3895 * Implementation of EnumPrintersW
3897 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3898 DWORD dwLevel, LPBYTE lpbPrinters,
3899 DWORD cbBuf, LPDWORD lpdwNeeded,
3900 LPDWORD lpdwReturned)
3903 HKEY hkeyPrinters, hkeyPrinter;
3904 WCHAR PrinterName[255];
3905 DWORD needed = 0, number = 0;
3906 DWORD used, i, left;
3907 PBYTE pi, buf;
3909 if(lpbPrinters)
3910 memset(lpbPrinters, 0, cbBuf);
3911 if(lpdwReturned)
3912 *lpdwReturned = 0;
3913 if(lpdwNeeded)
3914 *lpdwNeeded = 0;
3916 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3917 if(dwType == PRINTER_ENUM_DEFAULT)
3918 return TRUE;
3920 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3921 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3922 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3923 if (!dwType) {
3924 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3925 return TRUE;
3930 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3931 FIXME("dwType = %08x\n", dwType);
3932 SetLastError(ERROR_INVALID_FLAGS);
3933 return FALSE;
3936 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3937 ERROR_SUCCESS) {
3938 ERR("Can't create Printers key\n");
3939 return FALSE;
3942 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3943 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3944 RegCloseKey(hkeyPrinters);
3945 ERR("Can't query Printers key\n");
3946 return FALSE;
3948 TRACE("Found %d printers\n", number);
3950 switch(dwLevel) {
3951 case 1:
3952 used = number * sizeof(PRINTER_INFO_1W);
3953 break;
3954 case 2:
3955 used = number * sizeof(PRINTER_INFO_2W);
3956 break;
3957 case 4:
3958 used = number * sizeof(PRINTER_INFO_4W);
3959 break;
3960 case 5:
3961 used = number * sizeof(PRINTER_INFO_5W);
3962 break;
3964 default:
3965 SetLastError(ERROR_INVALID_LEVEL);
3966 RegCloseKey(hkeyPrinters);
3967 return FALSE;
3969 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3971 for(i = 0; i < number; i++) {
3972 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3973 ERROR_SUCCESS) {
3974 ERR("Can't enum key number %d\n", i);
3975 RegCloseKey(hkeyPrinters);
3976 return FALSE;
3978 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3979 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3980 ERROR_SUCCESS) {
3981 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3982 RegCloseKey(hkeyPrinters);
3983 return FALSE;
3986 if(cbBuf > used) {
3987 buf = lpbPrinters + used;
3988 left = cbBuf - used;
3989 } else {
3990 buf = NULL;
3991 left = 0;
3994 switch(dwLevel) {
3995 case 1:
3996 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3997 left, &needed);
3998 used += needed;
3999 if(pi) pi += sizeof(PRINTER_INFO_1W);
4000 break;
4001 case 2:
4002 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4003 left, &needed);
4004 used += needed;
4005 if(pi) pi += sizeof(PRINTER_INFO_2W);
4006 break;
4007 case 4:
4008 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4009 left, &needed);
4010 used += needed;
4011 if(pi) pi += sizeof(PRINTER_INFO_4W);
4012 break;
4013 case 5:
4014 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4015 left, &needed);
4016 used += needed;
4017 if(pi) pi += sizeof(PRINTER_INFO_5W);
4018 break;
4019 default:
4020 ERR("Shouldn't be here!\n");
4021 RegCloseKey(hkeyPrinter);
4022 RegCloseKey(hkeyPrinters);
4023 return FALSE;
4025 RegCloseKey(hkeyPrinter);
4027 RegCloseKey(hkeyPrinters);
4029 if(lpdwNeeded)
4030 *lpdwNeeded = used;
4032 if(used > cbBuf) {
4033 if(lpbPrinters)
4034 memset(lpbPrinters, 0, cbBuf);
4035 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4036 return FALSE;
4038 if(lpdwReturned)
4039 *lpdwReturned = number;
4040 SetLastError(ERROR_SUCCESS);
4041 return TRUE;
4045 /******************************************************************
4046 * EnumPrintersW [WINSPOOL.@]
4048 * Enumerates the available printers, print servers and print
4049 * providers, depending on the specified flags, name and level.
4051 * RETURNS:
4053 * If level is set to 1:
4054 * Returns an array of PRINTER_INFO_1 data structures in the
4055 * lpbPrinters buffer.
4057 * If level is set to 2:
4058 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4059 * Returns an array of PRINTER_INFO_2 data structures in the
4060 * lpbPrinters buffer. Note that according to MSDN also an
4061 * OpenPrinter should be performed on every remote printer.
4063 * If level is set to 4 (officially WinNT only):
4064 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4065 * Fast: Only the registry is queried to retrieve printer names,
4066 * no connection to the driver is made.
4067 * Returns an array of PRINTER_INFO_4 data structures in the
4068 * lpbPrinters buffer.
4070 * If level is set to 5 (officially WinNT4/Win9x only):
4071 * Fast: Only the registry is queried to retrieve printer names,
4072 * no connection to the driver is made.
4073 * Returns an array of PRINTER_INFO_5 data structures in the
4074 * lpbPrinters buffer.
4076 * If level set to 3 or 6+:
4077 * returns zero (failure!)
4079 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4080 * for information.
4082 * BUGS:
4083 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4084 * - Only levels 2, 4 and 5 are implemented at the moment.
4085 * - 16-bit printer drivers are not enumerated.
4086 * - Returned amount of bytes used/needed does not match the real Windoze
4087 * implementation (as in this implementation, all strings are part
4088 * of the buffer, whereas Win32 keeps them somewhere else)
4089 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4091 * NOTE:
4092 * - In a regular Wine installation, no registry settings for printers
4093 * exist, which makes this function return an empty list.
4095 BOOL WINAPI EnumPrintersW(
4096 DWORD dwType, /* [in] Types of print objects to enumerate */
4097 LPWSTR lpszName, /* [in] name of objects to enumerate */
4098 DWORD dwLevel, /* [in] type of printer info structure */
4099 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4100 DWORD cbBuf, /* [in] max size of buffer in bytes */
4101 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4102 LPDWORD lpdwReturned /* [out] number of entries returned */
4105 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4106 lpdwNeeded, lpdwReturned);
4109 /******************************************************************
4110 * EnumPrintersA [WINSPOOL.@]
4112 * See EnumPrintersW
4115 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4116 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4118 BOOL ret;
4119 UNICODE_STRING pNameU;
4120 LPWSTR pNameW;
4121 LPBYTE pPrintersW;
4123 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4124 pPrinters, cbBuf, pcbNeeded, pcReturned);
4126 pNameW = asciitounicode(&pNameU, pName);
4128 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4129 MS Office need this */
4130 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4132 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4134 RtlFreeUnicodeString(&pNameU);
4135 if (ret) {
4136 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4138 HeapFree(GetProcessHeap(), 0, pPrintersW);
4139 return ret;
4142 /*****************************************************************************
4143 * WINSPOOL_GetDriverInfoFromReg [internal]
4145 * Enters the information from the registry into the DRIVER_INFO struct
4147 * RETURNS
4148 * zero if the printer driver does not exist in the registry
4149 * (only if Level > 1) otherwise nonzero
4151 static BOOL WINSPOOL_GetDriverInfoFromReg(
4152 HKEY hkeyDrivers,
4153 LPWSTR DriverName,
4154 const printenv_t * env,
4155 DWORD Level,
4156 LPBYTE ptr, /* DRIVER_INFO */
4157 LPBYTE pDriverStrings, /* strings buffer */
4158 DWORD cbBuf, /* size of string buffer */
4159 LPDWORD pcbNeeded) /* space needed for str. */
4161 DWORD size, tmp;
4162 HKEY hkeyDriver;
4163 WCHAR driverdir[MAX_PATH];
4164 DWORD dirlen;
4165 LPBYTE strPtr = pDriverStrings;
4166 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4168 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4169 debugstr_w(DriverName), env,
4170 Level, di, pDriverStrings, cbBuf);
4172 if (di) ZeroMemory(di, di_sizeof[Level]);
4174 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4175 if (*pcbNeeded <= cbBuf)
4176 strcpyW((LPWSTR)strPtr, DriverName);
4178 /* pName for level 1 has a different offset! */
4179 if (Level == 1) {
4180 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4181 return TRUE;
4184 /* .cVersion and .pName for level > 1 */
4185 if (di) {
4186 di->cVersion = env->driverversion;
4187 di->pName = (LPWSTR) strPtr;
4188 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4191 /* Reserve Space for the largest subdir and a Backslash*/
4192 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4193 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4194 /* Should never Fail */
4195 return FALSE;
4197 lstrcatW(driverdir, env->versionsubdir);
4198 lstrcatW(driverdir, backslashW);
4200 /* dirlen must not include the terminating zero */
4201 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4203 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4204 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4205 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4206 return FALSE;
4209 /* pEnvironment */
4210 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4212 *pcbNeeded += size;
4213 if (*pcbNeeded <= cbBuf) {
4214 lstrcpyW((LPWSTR)strPtr, env->envname);
4215 if (di) di->pEnvironment = (LPWSTR)strPtr;
4216 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4219 /* .pDriverPath is the Graphics rendering engine.
4220 The full Path is required to avoid a crash in some apps */
4221 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4222 *pcbNeeded += size;
4223 if (*pcbNeeded <= cbBuf)
4224 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4226 if (di) di->pDriverPath = (LPWSTR)strPtr;
4227 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4230 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4231 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4232 *pcbNeeded += size;
4233 if (*pcbNeeded <= cbBuf)
4234 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4236 if (di) di->pDataFile = (LPWSTR)strPtr;
4237 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4240 /* .pConfigFile is the Driver user Interface */
4241 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4242 *pcbNeeded += size;
4243 if (*pcbNeeded <= cbBuf)
4244 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4246 if (di) di->pConfigFile = (LPWSTR)strPtr;
4247 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4250 if (Level == 2 ) {
4251 RegCloseKey(hkeyDriver);
4252 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4253 return TRUE;
4256 if (Level == 5 ) {
4257 RegCloseKey(hkeyDriver);
4258 FIXME("level 5: incomplete\n");
4259 return TRUE;
4262 /* .pHelpFile */
4263 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4264 *pcbNeeded += size;
4265 if (*pcbNeeded <= cbBuf)
4266 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4268 if (di) di->pHelpFile = (LPWSTR)strPtr;
4269 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4272 /* .pDependentFiles */
4273 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4274 *pcbNeeded += size;
4275 if (*pcbNeeded <= cbBuf)
4276 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4278 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4279 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4281 else if (GetVersion() & 0x80000000) {
4282 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4283 size = 2 * sizeof(WCHAR);
4284 *pcbNeeded += size;
4285 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4287 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4288 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4291 /* .pMonitorName is the optional Language Monitor */
4292 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4293 *pcbNeeded += size;
4294 if (*pcbNeeded <= cbBuf)
4295 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4297 if (di) di->pMonitorName = (LPWSTR)strPtr;
4298 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4301 /* .pDefaultDataType */
4302 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4303 *pcbNeeded += size;
4304 if(*pcbNeeded <= cbBuf)
4305 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4307 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4308 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4311 if (Level == 3 ) {
4312 RegCloseKey(hkeyDriver);
4313 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4314 return TRUE;
4317 /* .pszzPreviousNames */
4318 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4319 *pcbNeeded += size;
4320 if(*pcbNeeded <= cbBuf)
4321 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4323 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4324 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4327 if (Level == 4 ) {
4328 RegCloseKey(hkeyDriver);
4329 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4330 return TRUE;
4333 /* support is missing, but not important enough for a FIXME */
4334 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4336 /* .pszMfgName */
4337 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4338 *pcbNeeded += size;
4339 if(*pcbNeeded <= cbBuf)
4340 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4342 if (di) di->pszMfgName = (LPWSTR)strPtr;
4343 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4346 /* .pszOEMUrl */
4347 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4348 *pcbNeeded += size;
4349 if(*pcbNeeded <= cbBuf)
4350 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4352 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4353 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4356 /* .pszHardwareID */
4357 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4358 *pcbNeeded += size;
4359 if(*pcbNeeded <= cbBuf)
4360 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4362 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4363 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4366 /* .pszProvider */
4367 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4368 *pcbNeeded += size;
4369 if(*pcbNeeded <= cbBuf)
4370 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4372 if (di) di->pszProvider = (LPWSTR)strPtr;
4373 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4376 if (Level == 6 ) {
4377 RegCloseKey(hkeyDriver);
4378 return TRUE;
4381 /* support is missing, but not important enough for a FIXME */
4382 TRACE("level 8: incomplete\n");
4384 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4385 RegCloseKey(hkeyDriver);
4386 return TRUE;
4389 /*****************************************************************************
4390 * GetPrinterDriverW [WINSPOOL.@]
4392 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4393 DWORD Level, LPBYTE pDriverInfo,
4394 DWORD cbBuf, LPDWORD pcbNeeded)
4396 LPCWSTR name;
4397 WCHAR DriverName[100];
4398 DWORD ret, type, size, needed = 0;
4399 LPBYTE ptr = NULL;
4400 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4401 const printenv_t * env;
4403 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4404 Level,pDriverInfo,cbBuf, pcbNeeded);
4406 if (cbBuf > 0)
4407 ZeroMemory(pDriverInfo, cbBuf);
4409 if (!(name = get_opened_printer_name(hPrinter))) {
4410 SetLastError(ERROR_INVALID_HANDLE);
4411 return FALSE;
4414 if (Level < 1 || Level == 7 || Level > 8) {
4415 SetLastError(ERROR_INVALID_LEVEL);
4416 return FALSE;
4419 env = validate_envW(pEnvironment);
4420 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4422 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4423 ERROR_SUCCESS) {
4424 ERR("Can't create Printers key\n");
4425 return FALSE;
4427 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4428 != ERROR_SUCCESS) {
4429 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4430 RegCloseKey(hkeyPrinters);
4431 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4432 return FALSE;
4434 size = sizeof(DriverName);
4435 DriverName[0] = 0;
4436 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4437 (LPBYTE)DriverName, &size);
4438 RegCloseKey(hkeyPrinter);
4439 RegCloseKey(hkeyPrinters);
4440 if(ret != ERROR_SUCCESS) {
4441 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4442 return FALSE;
4445 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4446 if(!hkeyDrivers) {
4447 ERR("Can't create Drivers key\n");
4448 return FALSE;
4451 size = di_sizeof[Level];
4452 if ((size <= cbBuf) && pDriverInfo)
4453 ptr = pDriverInfo + size;
4455 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4456 env, Level, pDriverInfo, ptr,
4457 (cbBuf < size) ? 0 : cbBuf - size,
4458 &needed)) {
4459 RegCloseKey(hkeyDrivers);
4460 return FALSE;
4463 RegCloseKey(hkeyDrivers);
4465 if(pcbNeeded) *pcbNeeded = size + needed;
4466 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4467 if(cbBuf >= size + needed) return TRUE;
4468 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4469 return FALSE;
4472 /*****************************************************************************
4473 * GetPrinterDriverA [WINSPOOL.@]
4475 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4476 DWORD Level, LPBYTE pDriverInfo,
4477 DWORD cbBuf, LPDWORD pcbNeeded)
4479 BOOL ret;
4480 UNICODE_STRING pEnvW;
4481 PWSTR pwstrEnvW;
4482 LPBYTE buf = NULL;
4484 if (cbBuf)
4486 ZeroMemory(pDriverInfo, cbBuf);
4487 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4490 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4491 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4492 cbBuf, pcbNeeded);
4493 if (ret)
4494 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4496 HeapFree(GetProcessHeap(), 0, buf);
4498 RtlFreeUnicodeString(&pEnvW);
4499 return ret;
4502 /*****************************************************************************
4503 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4505 * Return the PATH for the Printer-Drivers (UNICODE)
4507 * PARAMS
4508 * pName [I] Servername (NT only) or NULL (local Computer)
4509 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4510 * Level [I] Structure-Level (must be 1)
4511 * pDriverDirectory [O] PTR to Buffer that receives the Result
4512 * cbBuf [I] Size of Buffer at pDriverDirectory
4513 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4514 * required for pDriverDirectory
4516 * RETURNS
4517 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4518 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4519 * if cbBuf is too small
4521 * Native Values returned in pDriverDirectory on Success:
4522 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4523 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4524 *| win9x(Windows 4.0): "%winsysdir%"
4526 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4528 * FIXME
4529 *- Only NULL or "" is supported for pName
4532 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4533 DWORD Level, LPBYTE pDriverDirectory,
4534 DWORD cbBuf, LPDWORD pcbNeeded)
4536 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4537 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4539 if ((backend == NULL) && !load_backend()) return FALSE;
4541 if (Level != 1) {
4542 /* (Level != 1) is ignored in win9x */
4543 SetLastError(ERROR_INVALID_LEVEL);
4544 return FALSE;
4546 if (pcbNeeded == NULL) {
4547 /* (pcbNeeded == NULL) is ignored in win9x */
4548 SetLastError(RPC_X_NULL_REF_POINTER);
4549 return FALSE;
4552 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4553 pDriverDirectory, cbBuf, pcbNeeded);
4558 /*****************************************************************************
4559 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4561 * Return the PATH for the Printer-Drivers (ANSI)
4563 * See GetPrinterDriverDirectoryW.
4565 * NOTES
4566 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4569 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4570 DWORD Level, LPBYTE pDriverDirectory,
4571 DWORD cbBuf, LPDWORD pcbNeeded)
4573 UNICODE_STRING nameW, environmentW;
4574 BOOL ret;
4575 DWORD pcbNeededW;
4576 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4577 WCHAR *driverDirectoryW = NULL;
4579 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4580 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4582 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4584 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4585 else nameW.Buffer = NULL;
4586 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4587 else environmentW.Buffer = NULL;
4589 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4590 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4591 if (ret) {
4592 DWORD needed;
4593 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4594 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4595 if(pcbNeeded)
4596 *pcbNeeded = needed;
4597 ret = (needed <= cbBuf) ? TRUE : FALSE;
4598 } else
4599 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4601 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4603 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4604 RtlFreeUnicodeString(&environmentW);
4605 RtlFreeUnicodeString(&nameW);
4607 return ret;
4610 /*****************************************************************************
4611 * AddPrinterDriverA [WINSPOOL.@]
4613 * See AddPrinterDriverW.
4616 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4618 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4619 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4622 /******************************************************************************
4623 * AddPrinterDriverW (WINSPOOL.@)
4625 * Install a Printer Driver
4627 * PARAMS
4628 * pName [I] Servername or NULL (local Computer)
4629 * level [I] Level for the supplied DRIVER_INFO_*W struct
4630 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4632 * RESULTS
4633 * Success: TRUE
4634 * Failure: FALSE
4637 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4639 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4640 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4643 /*****************************************************************************
4644 * AddPrintProcessorA [WINSPOOL.@]
4646 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4647 LPSTR pPrintProcessorName)
4649 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4650 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4651 return FALSE;
4654 /*****************************************************************************
4655 * AddPrintProcessorW [WINSPOOL.@]
4657 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4658 LPWSTR pPrintProcessorName)
4660 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4661 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4662 return FALSE;
4665 /*****************************************************************************
4666 * AddPrintProvidorA [WINSPOOL.@]
4668 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4670 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4671 return FALSE;
4674 /*****************************************************************************
4675 * AddPrintProvidorW [WINSPOOL.@]
4677 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4679 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4680 return FALSE;
4683 /*****************************************************************************
4684 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4686 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4687 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4689 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4690 pDevModeOutput, pDevModeInput);
4691 return 0;
4694 /*****************************************************************************
4695 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4697 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4698 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4700 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4701 pDevModeOutput, pDevModeInput);
4702 return 0;
4705 /*****************************************************************************
4706 * PrinterProperties [WINSPOOL.@]
4708 * Displays a dialog to set the properties of the printer.
4710 * RETURNS
4711 * nonzero on success or zero on failure
4713 * BUGS
4714 * implemented as stub only
4716 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4717 HANDLE hPrinter /* [in] handle to printer object */
4719 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4720 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4721 return FALSE;
4724 /*****************************************************************************
4725 * EnumJobsA [WINSPOOL.@]
4728 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4729 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4730 LPDWORD pcReturned)
4732 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4733 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4735 if(pcbNeeded) *pcbNeeded = 0;
4736 if(pcReturned) *pcReturned = 0;
4737 return FALSE;
4741 /*****************************************************************************
4742 * EnumJobsW [WINSPOOL.@]
4745 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4746 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4747 LPDWORD pcReturned)
4749 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4750 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4752 if(pcbNeeded) *pcbNeeded = 0;
4753 if(pcReturned) *pcReturned = 0;
4754 return FALSE;
4757 /*****************************************************************************
4758 * WINSPOOL_EnumPrinterDrivers [internal]
4760 * Delivers information about all printer drivers installed on the
4761 * localhost or a given server
4763 * RETURNS
4764 * nonzero on success or zero on failure. If the buffer for the returned
4765 * information is too small the function will return an error
4767 * BUGS
4768 * - only implemented for localhost, foreign hosts will return an error
4770 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4771 DWORD Level, LPBYTE pDriverInfo,
4772 DWORD driver_index,
4773 DWORD cbBuf, LPDWORD pcbNeeded,
4774 LPDWORD pcFound, DWORD data_offset)
4776 { HKEY hkeyDrivers;
4777 DWORD i, size = 0;
4778 const printenv_t * env;
4780 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4781 debugstr_w(pName), debugstr_w(pEnvironment),
4782 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4784 env = validate_envW(pEnvironment);
4785 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4787 *pcFound = 0;
4789 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4790 if(!hkeyDrivers) {
4791 ERR("Can't open Drivers key\n");
4792 return FALSE;
4795 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4796 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4797 RegCloseKey(hkeyDrivers);
4798 ERR("Can't query Drivers key\n");
4799 return FALSE;
4801 TRACE("Found %d Drivers\n", *pcFound);
4803 /* get size of single struct
4804 * unicode and ascii structure have the same size
4806 size = di_sizeof[Level];
4808 if (data_offset == 0)
4809 data_offset = size * (*pcFound);
4810 *pcbNeeded = data_offset;
4812 for( i = 0; i < *pcFound; i++) {
4813 WCHAR DriverNameW[255];
4814 PBYTE table_ptr = NULL;
4815 PBYTE data_ptr = NULL;
4816 DWORD needed = 0;
4818 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4819 != ERROR_SUCCESS) {
4820 ERR("Can't enum key number %d\n", i);
4821 RegCloseKey(hkeyDrivers);
4822 return FALSE;
4825 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4826 table_ptr = pDriverInfo + (driver_index + i) * size;
4827 if (pDriverInfo && *pcbNeeded <= cbBuf)
4828 data_ptr = pDriverInfo + *pcbNeeded;
4830 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4831 env, Level, table_ptr, data_ptr,
4832 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4833 &needed)) {
4834 RegCloseKey(hkeyDrivers);
4835 return FALSE;
4838 *pcbNeeded += needed;
4841 RegCloseKey(hkeyDrivers);
4843 if(cbBuf < *pcbNeeded){
4844 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4845 return FALSE;
4848 return TRUE;
4851 /*****************************************************************************
4852 * EnumPrinterDriversW [WINSPOOL.@]
4854 * see function EnumPrinterDrivers for RETURNS, BUGS
4856 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4857 LPBYTE pDriverInfo, DWORD cbBuf,
4858 LPDWORD pcbNeeded, LPDWORD pcReturned)
4860 static const WCHAR allW[] = {'a','l','l',0};
4861 BOOL ret;
4862 DWORD found;
4864 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4866 SetLastError(RPC_X_NULL_REF_POINTER);
4867 return FALSE;
4870 /* check for local drivers */
4871 if((pName) && (pName[0])) {
4872 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4873 SetLastError(ERROR_ACCESS_DENIED);
4874 return FALSE;
4877 /* check input parameter */
4878 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4879 SetLastError(ERROR_INVALID_LEVEL);
4880 return FALSE;
4883 if(pDriverInfo && cbBuf > 0)
4884 memset( pDriverInfo, 0, cbBuf);
4886 /* Exception: pull all printers */
4887 if (pEnvironment && !strcmpW(pEnvironment, allW))
4889 DWORD i, needed, bufsize = cbBuf;
4890 DWORD total_needed = 0;
4891 DWORD total_found = 0;
4892 DWORD data_offset;
4894 /* Precompute the overall total; we need this to know
4895 where pointers end and data begins (i.e. data_offset) */
4896 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4898 needed = found = 0;
4899 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4900 NULL, 0, 0, &needed, &found, 0);
4901 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4902 total_needed += needed;
4903 total_found += found;
4906 data_offset = di_sizeof[Level] * total_found;
4908 *pcReturned = 0;
4909 *pcbNeeded = 0;
4910 total_found = 0;
4911 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4913 needed = found = 0;
4914 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4915 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4916 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4917 else if (ret)
4918 *pcReturned += found;
4919 *pcbNeeded = needed;
4920 data_offset = needed;
4921 total_found += found;
4923 return ret;
4926 /* Normal behavior */
4927 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4928 0, cbBuf, pcbNeeded, &found, 0);
4929 if (ret)
4930 *pcReturned = found;
4932 return ret;
4935 /*****************************************************************************
4936 * EnumPrinterDriversA [WINSPOOL.@]
4938 * see function EnumPrinterDrivers for RETURNS, BUGS
4940 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4941 LPBYTE pDriverInfo, DWORD cbBuf,
4942 LPDWORD pcbNeeded, LPDWORD pcReturned)
4944 BOOL ret;
4945 UNICODE_STRING pNameW, pEnvironmentW;
4946 PWSTR pwstrNameW, pwstrEnvironmentW;
4947 LPBYTE buf = NULL;
4949 if (cbBuf)
4950 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4952 pwstrNameW = asciitounicode(&pNameW, pName);
4953 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4955 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4956 buf, cbBuf, pcbNeeded, pcReturned);
4957 if (ret)
4958 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4960 HeapFree(GetProcessHeap(), 0, buf);
4962 RtlFreeUnicodeString(&pNameW);
4963 RtlFreeUnicodeString(&pEnvironmentW);
4965 return ret;
4968 /******************************************************************************
4969 * EnumPortsA (WINSPOOL.@)
4971 * See EnumPortsW.
4974 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4975 LPDWORD pcbNeeded, LPDWORD pcReturned)
4977 BOOL res;
4978 LPBYTE bufferW = NULL;
4979 LPWSTR nameW = NULL;
4980 DWORD needed = 0;
4981 DWORD numentries = 0;
4982 INT len;
4984 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4985 cbBuf, pcbNeeded, pcReturned);
4987 /* convert servername to unicode */
4988 if (pName) {
4989 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4990 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4991 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4993 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4994 needed = cbBuf * sizeof(WCHAR);
4995 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4996 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4998 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4999 if (pcbNeeded) needed = *pcbNeeded;
5000 /* HeapReAlloc return NULL, when bufferW was NULL */
5001 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5002 HeapAlloc(GetProcessHeap(), 0, needed);
5004 /* Try again with the large Buffer */
5005 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5007 needed = pcbNeeded ? *pcbNeeded : 0;
5008 numentries = pcReturned ? *pcReturned : 0;
5011 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5012 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5014 if (res) {
5015 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5016 DWORD entrysize = 0;
5017 DWORD index;
5018 LPSTR ptr;
5019 LPPORT_INFO_2W pi2w;
5020 LPPORT_INFO_2A pi2a;
5022 needed = 0;
5023 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5025 /* First pass: calculate the size for all Entries */
5026 pi2w = (LPPORT_INFO_2W) bufferW;
5027 pi2a = (LPPORT_INFO_2A) pPorts;
5028 index = 0;
5029 while (index < numentries) {
5030 index++;
5031 needed += entrysize; /* PORT_INFO_?A */
5032 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5034 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5035 NULL, 0, NULL, NULL);
5036 if (Level > 1) {
5037 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5038 NULL, 0, NULL, NULL);
5039 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5040 NULL, 0, NULL, NULL);
5042 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5043 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5044 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5047 /* check for errors and quit on failure */
5048 if (cbBuf < needed) {
5049 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5050 res = FALSE;
5051 goto cleanup;
5053 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5054 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5055 cbBuf -= len ; /* free Bytes in the user-Buffer */
5056 pi2w = (LPPORT_INFO_2W) bufferW;
5057 pi2a = (LPPORT_INFO_2A) pPorts;
5058 index = 0;
5059 /* Second Pass: Fill the User Buffer (if we have one) */
5060 while ((index < numentries) && pPorts) {
5061 index++;
5062 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5063 pi2a->pPortName = ptr;
5064 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5065 ptr, cbBuf , NULL, NULL);
5066 ptr += len;
5067 cbBuf -= len;
5068 if (Level > 1) {
5069 pi2a->pMonitorName = ptr;
5070 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5071 ptr, cbBuf, NULL, NULL);
5072 ptr += len;
5073 cbBuf -= len;
5075 pi2a->pDescription = ptr;
5076 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5077 ptr, cbBuf, NULL, NULL);
5078 ptr += len;
5079 cbBuf -= len;
5081 pi2a->fPortType = pi2w->fPortType;
5082 pi2a->Reserved = 0; /* documented: "must be zero" */
5085 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5086 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5087 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5091 cleanup:
5092 if (pcbNeeded) *pcbNeeded = needed;
5093 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5095 HeapFree(GetProcessHeap(), 0, nameW);
5096 HeapFree(GetProcessHeap(), 0, bufferW);
5098 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5099 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5101 return (res);
5105 /******************************************************************************
5106 * EnumPortsW (WINSPOOL.@)
5108 * Enumerate available Ports
5110 * PARAMS
5111 * pName [I] Servername or NULL (local Computer)
5112 * Level [I] Structure-Level (1 or 2)
5113 * pPorts [O] PTR to Buffer that receives the Result
5114 * cbBuf [I] Size of Buffer at pPorts
5115 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5116 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5118 * RETURNS
5119 * Success: TRUE
5120 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5123 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5126 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5127 cbBuf, pcbNeeded, pcReturned);
5129 if ((backend == NULL) && !load_backend()) return FALSE;
5131 /* Level is not checked in win9x */
5132 if (!Level || (Level > 2)) {
5133 WARN("level (%d) is ignored in win9x\n", Level);
5134 SetLastError(ERROR_INVALID_LEVEL);
5135 return FALSE;
5137 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5138 SetLastError(RPC_X_NULL_REF_POINTER);
5139 return FALSE;
5142 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5145 /******************************************************************************
5146 * GetDefaultPrinterW (WINSPOOL.@)
5148 * FIXME
5149 * This function must read the value from data 'device' of key
5150 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5152 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5154 BOOL retval = TRUE;
5155 DWORD insize, len;
5156 WCHAR *buffer, *ptr;
5158 if (!namesize)
5160 SetLastError(ERROR_INVALID_PARAMETER);
5161 return FALSE;
5164 /* make the buffer big enough for the stuff from the profile/registry,
5165 * the content must fit into the local buffer to compute the correct
5166 * size even if the extern buffer is too small or not given.
5167 * (20 for ,driver,port) */
5168 insize = *namesize;
5169 len = max(100, (insize + 20));
5170 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5172 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5174 SetLastError (ERROR_FILE_NOT_FOUND);
5175 retval = FALSE;
5176 goto end;
5178 TRACE("%s\n", debugstr_w(buffer));
5180 if ((ptr = strchrW(buffer, ',')) == NULL)
5182 SetLastError(ERROR_INVALID_NAME);
5183 retval = FALSE;
5184 goto end;
5187 *ptr = 0;
5188 *namesize = strlenW(buffer) + 1;
5189 if(!name || (*namesize > insize))
5191 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5192 retval = FALSE;
5193 goto end;
5195 strcpyW(name, buffer);
5197 end:
5198 HeapFree( GetProcessHeap(), 0, buffer);
5199 return retval;
5203 /******************************************************************************
5204 * GetDefaultPrinterA (WINSPOOL.@)
5206 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5208 BOOL retval = TRUE;
5209 DWORD insize = 0;
5210 WCHAR *bufferW = NULL;
5212 if (!namesize)
5214 SetLastError(ERROR_INVALID_PARAMETER);
5215 return FALSE;
5218 if(name && *namesize) {
5219 insize = *namesize;
5220 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5223 if(!GetDefaultPrinterW( bufferW, namesize)) {
5224 retval = FALSE;
5225 goto end;
5228 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5229 NULL, NULL);
5230 if (!*namesize)
5232 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5233 retval = FALSE;
5235 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5237 end:
5238 HeapFree( GetProcessHeap(), 0, bufferW);
5239 return retval;
5243 /******************************************************************************
5244 * SetDefaultPrinterW (WINSPOOL.204)
5246 * Set the Name of the Default Printer
5248 * PARAMS
5249 * pszPrinter [I] Name of the Printer or NULL
5251 * RETURNS
5252 * Success: True
5253 * Failure: FALSE
5255 * NOTES
5256 * When the Parameter is NULL or points to an Empty String and
5257 * a Default Printer was already present, then this Function changes nothing.
5258 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5259 * the First enumerated local Printer is used.
5262 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5265 TRACE("(%s)\n", debugstr_w(pszPrinter));
5267 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5268 return FALSE;
5271 /******************************************************************************
5272 * SetDefaultPrinterA (WINSPOOL.202)
5274 * See SetDefaultPrinterW.
5277 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5280 TRACE("(%s)\n", debugstr_a(pszPrinter));
5282 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5283 return FALSE;
5287 /******************************************************************************
5288 * SetPrinterDataExA (WINSPOOL.@)
5290 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5291 LPCSTR pValueName, DWORD Type,
5292 LPBYTE pData, DWORD cbData)
5294 HKEY hkeyPrinter, hkeySubkey;
5295 DWORD ret;
5297 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5298 debugstr_a(pValueName), Type, pData, cbData);
5300 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5301 != ERROR_SUCCESS)
5302 return ret;
5304 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5305 != ERROR_SUCCESS) {
5306 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5307 RegCloseKey(hkeyPrinter);
5308 return ret;
5310 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5311 RegCloseKey(hkeySubkey);
5312 RegCloseKey(hkeyPrinter);
5313 return ret;
5316 /******************************************************************************
5317 * SetPrinterDataExW (WINSPOOL.@)
5319 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5320 LPCWSTR pValueName, DWORD Type,
5321 LPBYTE pData, DWORD cbData)
5323 HKEY hkeyPrinter, hkeySubkey;
5324 DWORD ret;
5326 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5327 debugstr_w(pValueName), Type, pData, cbData);
5329 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5330 != ERROR_SUCCESS)
5331 return ret;
5333 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5334 != ERROR_SUCCESS) {
5335 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5336 RegCloseKey(hkeyPrinter);
5337 return ret;
5339 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5340 RegCloseKey(hkeySubkey);
5341 RegCloseKey(hkeyPrinter);
5342 return ret;
5345 /******************************************************************************
5346 * SetPrinterDataA (WINSPOOL.@)
5348 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5349 LPBYTE pData, DWORD cbData)
5351 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5352 pData, cbData);
5355 /******************************************************************************
5356 * SetPrinterDataW (WINSPOOL.@)
5358 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5359 LPBYTE pData, DWORD cbData)
5361 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5362 pData, cbData);
5365 /******************************************************************************
5366 * GetPrinterDataExA (WINSPOOL.@)
5368 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5369 LPCSTR pValueName, LPDWORD pType,
5370 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5372 opened_printer_t *printer;
5373 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5374 DWORD ret;
5376 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5377 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5379 printer = get_opened_printer(hPrinter);
5380 if(!printer) return ERROR_INVALID_HANDLE;
5382 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5383 if (ret) return ret;
5385 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5387 if (printer->name) {
5389 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5390 if (ret) {
5391 RegCloseKey(hkeyPrinters);
5392 return ret;
5394 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5395 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5396 RegCloseKey(hkeyPrinter);
5397 RegCloseKey(hkeyPrinters);
5398 return ret;
5401 *pcbNeeded = nSize;
5402 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5403 0, pType, pData, pcbNeeded);
5405 if (!ret && !pData) ret = ERROR_MORE_DATA;
5407 RegCloseKey(hkeySubkey);
5408 RegCloseKey(hkeyPrinter);
5409 RegCloseKey(hkeyPrinters);
5411 TRACE("--> %d\n", ret);
5412 return ret;
5415 /******************************************************************************
5416 * GetPrinterDataExW (WINSPOOL.@)
5418 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5419 LPCWSTR pValueName, LPDWORD pType,
5420 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5422 opened_printer_t *printer;
5423 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5424 DWORD ret;
5426 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5427 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5429 printer = get_opened_printer(hPrinter);
5430 if(!printer) return ERROR_INVALID_HANDLE;
5432 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5433 if (ret) return ret;
5435 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5437 if (printer->name) {
5439 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5440 if (ret) {
5441 RegCloseKey(hkeyPrinters);
5442 return ret;
5444 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5445 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5446 RegCloseKey(hkeyPrinter);
5447 RegCloseKey(hkeyPrinters);
5448 return ret;
5451 *pcbNeeded = nSize;
5452 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5453 0, pType, pData, pcbNeeded);
5455 if (!ret && !pData) ret = ERROR_MORE_DATA;
5457 RegCloseKey(hkeySubkey);
5458 RegCloseKey(hkeyPrinter);
5459 RegCloseKey(hkeyPrinters);
5461 TRACE("--> %d\n", ret);
5462 return ret;
5465 /******************************************************************************
5466 * GetPrinterDataA (WINSPOOL.@)
5468 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5469 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5471 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5472 pData, nSize, pcbNeeded);
5475 /******************************************************************************
5476 * GetPrinterDataW (WINSPOOL.@)
5478 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5479 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5481 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5482 pData, nSize, pcbNeeded);
5485 /*******************************************************************************
5486 * EnumPrinterDataExW [WINSPOOL.@]
5488 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5489 LPBYTE pEnumValues, DWORD cbEnumValues,
5490 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5492 HKEY hkPrinter, hkSubKey;
5493 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5494 cbValueNameLen, cbMaxValueLen, cbValueLen,
5495 cbBufSize, dwType;
5496 LPWSTR lpValueName;
5497 HANDLE hHeap;
5498 PBYTE lpValue;
5499 PPRINTER_ENUM_VALUESW ppev;
5501 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5503 if (pKeyName == NULL || *pKeyName == 0)
5504 return ERROR_INVALID_PARAMETER;
5506 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5507 if (ret != ERROR_SUCCESS)
5509 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5510 hPrinter, ret);
5511 return ret;
5514 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5515 if (ret != ERROR_SUCCESS)
5517 r = RegCloseKey (hkPrinter);
5518 if (r != ERROR_SUCCESS)
5519 WARN ("RegCloseKey returned %i\n", r);
5520 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5521 debugstr_w (pKeyName), ret);
5522 return ret;
5525 ret = RegCloseKey (hkPrinter);
5526 if (ret != ERROR_SUCCESS)
5528 ERR ("RegCloseKey returned %i\n", ret);
5529 r = RegCloseKey (hkSubKey);
5530 if (r != ERROR_SUCCESS)
5531 WARN ("RegCloseKey returned %i\n", r);
5532 return ret;
5535 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5536 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5537 if (ret != ERROR_SUCCESS)
5539 r = RegCloseKey (hkSubKey);
5540 if (r != ERROR_SUCCESS)
5541 WARN ("RegCloseKey returned %i\n", r);
5542 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5543 return ret;
5546 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5547 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5549 if (cValues == 0) /* empty key */
5551 r = RegCloseKey (hkSubKey);
5552 if (r != ERROR_SUCCESS)
5553 WARN ("RegCloseKey returned %i\n", r);
5554 *pcbEnumValues = *pnEnumValues = 0;
5555 return ERROR_SUCCESS;
5558 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5560 hHeap = GetProcessHeap ();
5561 if (hHeap == NULL)
5563 ERR ("GetProcessHeap failed\n");
5564 r = RegCloseKey (hkSubKey);
5565 if (r != ERROR_SUCCESS)
5566 WARN ("RegCloseKey returned %i\n", r);
5567 return ERROR_OUTOFMEMORY;
5570 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5571 if (lpValueName == NULL)
5573 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5574 r = RegCloseKey (hkSubKey);
5575 if (r != ERROR_SUCCESS)
5576 WARN ("RegCloseKey returned %i\n", r);
5577 return ERROR_OUTOFMEMORY;
5580 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5581 if (lpValue == NULL)
5583 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5584 if (HeapFree (hHeap, 0, lpValueName) == 0)
5585 WARN ("HeapFree failed with code %i\n", GetLastError ());
5586 r = RegCloseKey (hkSubKey);
5587 if (r != ERROR_SUCCESS)
5588 WARN ("RegCloseKey returned %i\n", r);
5589 return ERROR_OUTOFMEMORY;
5592 TRACE ("pass 1: calculating buffer required for all names and values\n");
5594 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5596 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5598 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5600 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5601 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5602 NULL, NULL, lpValue, &cbValueLen);
5603 if (ret != ERROR_SUCCESS)
5605 if (HeapFree (hHeap, 0, lpValue) == 0)
5606 WARN ("HeapFree failed with code %i\n", GetLastError ());
5607 if (HeapFree (hHeap, 0, lpValueName) == 0)
5608 WARN ("HeapFree failed with code %i\n", GetLastError ());
5609 r = RegCloseKey (hkSubKey);
5610 if (r != ERROR_SUCCESS)
5611 WARN ("RegCloseKey returned %i\n", r);
5612 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5613 return ret;
5616 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5617 debugstr_w (lpValueName), dwIndex,
5618 cbValueNameLen + 1, cbValueLen);
5620 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5621 cbBufSize += cbValueLen;
5624 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5626 *pcbEnumValues = cbBufSize;
5627 *pnEnumValues = cValues;
5629 if (cbEnumValues < cbBufSize) /* buffer too small */
5631 if (HeapFree (hHeap, 0, lpValue) == 0)
5632 WARN ("HeapFree failed with code %i\n", GetLastError ());
5633 if (HeapFree (hHeap, 0, lpValueName) == 0)
5634 WARN ("HeapFree failed with code %i\n", GetLastError ());
5635 r = RegCloseKey (hkSubKey);
5636 if (r != ERROR_SUCCESS)
5637 WARN ("RegCloseKey returned %i\n", r);
5638 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5639 return ERROR_MORE_DATA;
5642 TRACE ("pass 2: copying all names and values to buffer\n");
5644 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5645 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5647 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5649 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5650 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5651 NULL, &dwType, lpValue, &cbValueLen);
5652 if (ret != ERROR_SUCCESS)
5654 if (HeapFree (hHeap, 0, lpValue) == 0)
5655 WARN ("HeapFree failed with code %i\n", GetLastError ());
5656 if (HeapFree (hHeap, 0, lpValueName) == 0)
5657 WARN ("HeapFree failed with code %i\n", GetLastError ());
5658 r = RegCloseKey (hkSubKey);
5659 if (r != ERROR_SUCCESS)
5660 WARN ("RegCloseKey returned %i\n", r);
5661 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5662 return ret;
5665 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5666 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5667 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5668 pEnumValues += cbValueNameLen;
5670 /* return # of *bytes* (including trailing \0), not # of chars */
5671 ppev[dwIndex].cbValueName = cbValueNameLen;
5673 ppev[dwIndex].dwType = dwType;
5675 memcpy (pEnumValues, lpValue, cbValueLen);
5676 ppev[dwIndex].pData = pEnumValues;
5677 pEnumValues += cbValueLen;
5679 ppev[dwIndex].cbData = cbValueLen;
5681 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5682 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5685 if (HeapFree (hHeap, 0, lpValue) == 0)
5687 ret = GetLastError ();
5688 ERR ("HeapFree failed with code %i\n", ret);
5689 if (HeapFree (hHeap, 0, lpValueName) == 0)
5690 WARN ("HeapFree failed with code %i\n", GetLastError ());
5691 r = RegCloseKey (hkSubKey);
5692 if (r != ERROR_SUCCESS)
5693 WARN ("RegCloseKey returned %i\n", r);
5694 return ret;
5697 if (HeapFree (hHeap, 0, lpValueName) == 0)
5699 ret = GetLastError ();
5700 ERR ("HeapFree failed with code %i\n", ret);
5701 r = RegCloseKey (hkSubKey);
5702 if (r != ERROR_SUCCESS)
5703 WARN ("RegCloseKey returned %i\n", r);
5704 return ret;
5707 ret = RegCloseKey (hkSubKey);
5708 if (ret != ERROR_SUCCESS)
5710 ERR ("RegCloseKey returned %i\n", ret);
5711 return ret;
5714 return ERROR_SUCCESS;
5717 /*******************************************************************************
5718 * EnumPrinterDataExA [WINSPOOL.@]
5720 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5721 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5722 * what Windows 2000 SP1 does.
5725 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5726 LPBYTE pEnumValues, DWORD cbEnumValues,
5727 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5729 INT len;
5730 LPWSTR pKeyNameW;
5731 DWORD ret, dwIndex, dwBufSize;
5732 HANDLE hHeap;
5733 LPSTR pBuffer;
5735 TRACE ("%p %s\n", hPrinter, pKeyName);
5737 if (pKeyName == NULL || *pKeyName == 0)
5738 return ERROR_INVALID_PARAMETER;
5740 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5741 if (len == 0)
5743 ret = GetLastError ();
5744 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5745 return ret;
5748 hHeap = GetProcessHeap ();
5749 if (hHeap == NULL)
5751 ERR ("GetProcessHeap failed\n");
5752 return ERROR_OUTOFMEMORY;
5755 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5756 if (pKeyNameW == NULL)
5758 ERR ("Failed to allocate %i bytes from process heap\n",
5759 (LONG)(len * sizeof (WCHAR)));
5760 return ERROR_OUTOFMEMORY;
5763 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5765 ret = GetLastError ();
5766 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5767 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5768 WARN ("HeapFree failed with code %i\n", GetLastError ());
5769 return ret;
5772 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5773 pcbEnumValues, pnEnumValues);
5774 if (ret != ERROR_SUCCESS)
5776 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5777 WARN ("HeapFree failed with code %i\n", GetLastError ());
5778 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5779 return ret;
5782 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5784 ret = GetLastError ();
5785 ERR ("HeapFree failed with code %i\n", ret);
5786 return ret;
5789 if (*pnEnumValues == 0) /* empty key */
5790 return ERROR_SUCCESS;
5792 dwBufSize = 0;
5793 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5795 PPRINTER_ENUM_VALUESW ppev =
5796 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5798 if (dwBufSize < ppev->cbValueName)
5799 dwBufSize = ppev->cbValueName;
5801 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5802 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5803 dwBufSize = ppev->cbData;
5806 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5808 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5809 if (pBuffer == NULL)
5811 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5812 return ERROR_OUTOFMEMORY;
5815 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5817 PPRINTER_ENUM_VALUESW ppev =
5818 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5820 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5821 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5822 NULL);
5823 if (len == 0)
5825 ret = GetLastError ();
5826 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5827 if (HeapFree (hHeap, 0, pBuffer) == 0)
5828 WARN ("HeapFree failed with code %i\n", GetLastError ());
5829 return ret;
5832 memcpy (ppev->pValueName, pBuffer, len);
5834 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5836 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5837 ppev->dwType != REG_MULTI_SZ)
5838 continue;
5840 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5841 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5842 if (len == 0)
5844 ret = GetLastError ();
5845 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5846 if (HeapFree (hHeap, 0, pBuffer) == 0)
5847 WARN ("HeapFree failed with code %i\n", GetLastError ());
5848 return ret;
5851 memcpy (ppev->pData, pBuffer, len);
5853 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5854 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5857 if (HeapFree (hHeap, 0, pBuffer) == 0)
5859 ret = GetLastError ();
5860 ERR ("HeapFree failed with code %i\n", ret);
5861 return ret;
5864 return ERROR_SUCCESS;
5867 /******************************************************************************
5868 * AbortPrinter (WINSPOOL.@)
5870 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5872 FIXME("(%p), stub!\n", hPrinter);
5873 return TRUE;
5876 /******************************************************************************
5877 * AddPortA (WINSPOOL.@)
5879 * See AddPortW.
5882 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5884 LPWSTR nameW = NULL;
5885 LPWSTR monitorW = NULL;
5886 DWORD len;
5887 BOOL res;
5889 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5891 if (pName) {
5892 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5893 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5894 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5897 if (pMonitorName) {
5898 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5899 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5900 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5902 res = AddPortW(nameW, hWnd, monitorW);
5903 HeapFree(GetProcessHeap(), 0, nameW);
5904 HeapFree(GetProcessHeap(), 0, monitorW);
5905 return res;
5908 /******************************************************************************
5909 * AddPortW (WINSPOOL.@)
5911 * Add a Port for a specific Monitor
5913 * PARAMS
5914 * pName [I] Servername or NULL (local Computer)
5915 * hWnd [I] Handle to parent Window for the Dialog-Box
5916 * pMonitorName [I] Name of the Monitor that manage the Port
5918 * RETURNS
5919 * Success: TRUE
5920 * Failure: FALSE
5923 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5925 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5927 if ((backend == NULL) && !load_backend()) return FALSE;
5929 if (!pMonitorName) {
5930 SetLastError(RPC_X_NULL_REF_POINTER);
5931 return FALSE;
5934 return backend->fpAddPort(pName, hWnd, pMonitorName);
5937 /******************************************************************************
5938 * AddPortExA (WINSPOOL.@)
5940 * See AddPortExW.
5943 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5945 PORT_INFO_2W pi2W;
5946 PORT_INFO_2A * pi2A;
5947 LPWSTR nameW = NULL;
5948 LPWSTR monitorW = NULL;
5949 DWORD len;
5950 BOOL res;
5952 pi2A = (PORT_INFO_2A *) pBuffer;
5954 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5955 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5957 if ((level < 1) || (level > 2)) {
5958 SetLastError(ERROR_INVALID_LEVEL);
5959 return FALSE;
5962 if (!pi2A) {
5963 SetLastError(ERROR_INVALID_PARAMETER);
5964 return FALSE;
5967 if (pName) {
5968 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5969 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5970 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5973 if (pMonitorName) {
5974 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5975 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5976 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5979 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5981 if (pi2A->pPortName) {
5982 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5983 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5984 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5987 if (level > 1) {
5988 if (pi2A->pMonitorName) {
5989 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5990 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5991 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5994 if (pi2A->pDescription) {
5995 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5996 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5997 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5999 pi2W.fPortType = pi2A->fPortType;
6000 pi2W.Reserved = pi2A->Reserved;
6003 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6005 HeapFree(GetProcessHeap(), 0, nameW);
6006 HeapFree(GetProcessHeap(), 0, monitorW);
6007 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6008 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6009 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6010 return res;
6014 /******************************************************************************
6015 * AddPortExW (WINSPOOL.@)
6017 * Add a Port for a specific Monitor, without presenting a user interface
6019 * PARAMS
6020 * pName [I] Servername or NULL (local Computer)
6021 * level [I] Structure-Level (1 or 2) for pBuffer
6022 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6023 * pMonitorName [I] Name of the Monitor that manage the Port
6025 * RETURNS
6026 * Success: TRUE
6027 * Failure: FALSE
6030 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6032 PORT_INFO_2W * pi2;
6034 pi2 = (PORT_INFO_2W *) pBuffer;
6036 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6037 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6038 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6039 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6041 if ((backend == NULL) && !load_backend()) return FALSE;
6043 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6044 SetLastError(ERROR_INVALID_PARAMETER);
6045 return FALSE;
6048 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6051 /******************************************************************************
6052 * AddPrinterConnectionA (WINSPOOL.@)
6054 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6056 FIXME("%s\n", debugstr_a(pName));
6057 return FALSE;
6060 /******************************************************************************
6061 * AddPrinterConnectionW (WINSPOOL.@)
6063 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6065 FIXME("%s\n", debugstr_w(pName));
6066 return FALSE;
6069 /******************************************************************************
6070 * AddPrinterDriverExW (WINSPOOL.@)
6072 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6074 * PARAMS
6075 * pName [I] Servername or NULL (local Computer)
6076 * level [I] Level for the supplied DRIVER_INFO_*W struct
6077 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6078 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6080 * RESULTS
6081 * Success: TRUE
6082 * Failure: FALSE
6085 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6087 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6089 if ((backend == NULL) && !load_backend()) return FALSE;
6091 if (level < 2 || level == 5 || level == 7 || level > 8) {
6092 SetLastError(ERROR_INVALID_LEVEL);
6093 return FALSE;
6096 if (!pDriverInfo) {
6097 SetLastError(ERROR_INVALID_PARAMETER);
6098 return FALSE;
6101 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6104 /******************************************************************************
6105 * AddPrinterDriverExA (WINSPOOL.@)
6107 * See AddPrinterDriverExW.
6110 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6112 DRIVER_INFO_8A *diA;
6113 DRIVER_INFO_8W diW;
6114 LPWSTR nameW = NULL;
6115 DWORD lenA;
6116 DWORD len;
6117 DWORD res = FALSE;
6119 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6121 diA = (DRIVER_INFO_8A *) pDriverInfo;
6122 ZeroMemory(&diW, sizeof(diW));
6124 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6125 SetLastError(ERROR_INVALID_LEVEL);
6126 return FALSE;
6129 if (diA == NULL) {
6130 SetLastError(ERROR_INVALID_PARAMETER);
6131 return FALSE;
6134 /* convert servername to unicode */
6135 if (pName) {
6136 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6137 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6138 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6141 /* common fields */
6142 diW.cVersion = diA->cVersion;
6144 if (diA->pName) {
6145 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6146 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6147 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6150 if (diA->pEnvironment) {
6151 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6152 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6153 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6156 if (diA->pDriverPath) {
6157 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6158 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6159 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6162 if (diA->pDataFile) {
6163 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6164 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6165 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6168 if (diA->pConfigFile) {
6169 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6170 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6171 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6174 if ((Level > 2) && diA->pDependentFiles) {
6175 lenA = multi_sz_lenA(diA->pDependentFiles);
6176 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6177 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6178 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6181 if ((Level > 2) && diA->pMonitorName) {
6182 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6183 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6184 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6187 if ((Level > 3) && diA->pDefaultDataType) {
6188 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6189 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6190 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6193 if ((Level > 3) && diA->pszzPreviousNames) {
6194 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6195 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6196 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6197 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6200 if ((Level > 5) && diA->pszMfgName) {
6201 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6202 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6203 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6206 if ((Level > 5) && diA->pszOEMUrl) {
6207 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6208 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6209 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6212 if ((Level > 5) && diA->pszHardwareID) {
6213 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6214 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6215 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6218 if ((Level > 5) && diA->pszProvider) {
6219 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6220 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6221 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6224 if (Level > 7) {
6225 FIXME("level %u is incomplete\n", Level);
6228 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6229 TRACE("got %u with %u\n", res, GetLastError());
6230 HeapFree(GetProcessHeap(), 0, nameW);
6231 HeapFree(GetProcessHeap(), 0, diW.pName);
6232 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6233 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6234 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6235 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6236 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6237 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6238 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6239 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6240 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6241 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6242 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6243 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6245 TRACE("=> %u with %u\n", res, GetLastError());
6246 return res;
6249 /******************************************************************************
6250 * ConfigurePortA (WINSPOOL.@)
6252 * See ConfigurePortW.
6255 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6257 LPWSTR nameW = NULL;
6258 LPWSTR portW = NULL;
6259 INT len;
6260 DWORD res;
6262 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6264 /* convert servername to unicode */
6265 if (pName) {
6266 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6267 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6268 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6271 /* convert portname to unicode */
6272 if (pPortName) {
6273 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6274 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6275 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6278 res = ConfigurePortW(nameW, hWnd, portW);
6279 HeapFree(GetProcessHeap(), 0, nameW);
6280 HeapFree(GetProcessHeap(), 0, portW);
6281 return res;
6284 /******************************************************************************
6285 * ConfigurePortW (WINSPOOL.@)
6287 * Display the Configuration-Dialog for a specific Port
6289 * PARAMS
6290 * pName [I] Servername or NULL (local Computer)
6291 * hWnd [I] Handle to parent Window for the Dialog-Box
6292 * pPortName [I] Name of the Port, that should be configured
6294 * RETURNS
6295 * Success: TRUE
6296 * Failure: FALSE
6299 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6302 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6304 if ((backend == NULL) && !load_backend()) return FALSE;
6306 if (!pPortName) {
6307 SetLastError(RPC_X_NULL_REF_POINTER);
6308 return FALSE;
6311 return backend->fpConfigurePort(pName, hWnd, pPortName);
6314 /******************************************************************************
6315 * ConnectToPrinterDlg (WINSPOOL.@)
6317 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6319 FIXME("%p %x\n", hWnd, Flags);
6320 return NULL;
6323 /******************************************************************************
6324 * DeletePrinterConnectionA (WINSPOOL.@)
6326 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6328 FIXME("%s\n", debugstr_a(pName));
6329 return TRUE;
6332 /******************************************************************************
6333 * DeletePrinterConnectionW (WINSPOOL.@)
6335 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6337 FIXME("%s\n", debugstr_w(pName));
6338 return TRUE;
6341 /******************************************************************************
6342 * DeletePrinterDriverExW (WINSPOOL.@)
6344 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6345 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6347 HKEY hkey_drivers;
6348 BOOL ret = FALSE;
6350 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6351 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6353 if(pName && pName[0])
6355 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6356 SetLastError(ERROR_INVALID_PARAMETER);
6357 return FALSE;
6360 if(dwDeleteFlag)
6362 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6363 SetLastError(ERROR_INVALID_PARAMETER);
6364 return FALSE;
6367 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6369 if(!hkey_drivers)
6371 ERR("Can't open drivers key\n");
6372 return FALSE;
6375 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6376 ret = TRUE;
6378 RegCloseKey(hkey_drivers);
6380 return ret;
6383 /******************************************************************************
6384 * DeletePrinterDriverExA (WINSPOOL.@)
6386 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6387 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6389 UNICODE_STRING NameW, EnvW, DriverW;
6390 BOOL ret;
6392 asciitounicode(&NameW, pName);
6393 asciitounicode(&EnvW, pEnvironment);
6394 asciitounicode(&DriverW, pDriverName);
6396 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6398 RtlFreeUnicodeString(&DriverW);
6399 RtlFreeUnicodeString(&EnvW);
6400 RtlFreeUnicodeString(&NameW);
6402 return ret;
6405 /******************************************************************************
6406 * DeletePrinterDataExW (WINSPOOL.@)
6408 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6409 LPCWSTR pValueName)
6411 FIXME("%p %s %s\n", hPrinter,
6412 debugstr_w(pKeyName), debugstr_w(pValueName));
6413 return ERROR_INVALID_PARAMETER;
6416 /******************************************************************************
6417 * DeletePrinterDataExA (WINSPOOL.@)
6419 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6420 LPCSTR pValueName)
6422 FIXME("%p %s %s\n", hPrinter,
6423 debugstr_a(pKeyName), debugstr_a(pValueName));
6424 return ERROR_INVALID_PARAMETER;
6427 /******************************************************************************
6428 * DeletePrintProcessorA (WINSPOOL.@)
6430 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6432 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6433 debugstr_a(pPrintProcessorName));
6434 return TRUE;
6437 /******************************************************************************
6438 * DeletePrintProcessorW (WINSPOOL.@)
6440 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6442 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6443 debugstr_w(pPrintProcessorName));
6444 return TRUE;
6447 /******************************************************************************
6448 * DeletePrintProvidorA (WINSPOOL.@)
6450 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6452 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6453 debugstr_a(pPrintProviderName));
6454 return TRUE;
6457 /******************************************************************************
6458 * DeletePrintProvidorW (WINSPOOL.@)
6460 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6462 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6463 debugstr_w(pPrintProviderName));
6464 return TRUE;
6467 /******************************************************************************
6468 * EnumFormsA (WINSPOOL.@)
6470 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6471 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6473 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6474 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6475 return FALSE;
6478 /******************************************************************************
6479 * EnumFormsW (WINSPOOL.@)
6481 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6482 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6484 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6485 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6486 return FALSE;
6489 /*****************************************************************************
6490 * EnumMonitorsA [WINSPOOL.@]
6492 * See EnumMonitorsW.
6495 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6496 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6498 BOOL res;
6499 LPBYTE bufferW = NULL;
6500 LPWSTR nameW = NULL;
6501 DWORD needed = 0;
6502 DWORD numentries = 0;
6503 INT len;
6505 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6506 cbBuf, pcbNeeded, pcReturned);
6508 /* convert servername to unicode */
6509 if (pName) {
6510 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6511 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6512 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6514 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6515 needed = cbBuf * sizeof(WCHAR);
6516 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6517 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6519 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6520 if (pcbNeeded) needed = *pcbNeeded;
6521 /* HeapReAlloc return NULL, when bufferW was NULL */
6522 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6523 HeapAlloc(GetProcessHeap(), 0, needed);
6525 /* Try again with the large Buffer */
6526 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6528 numentries = pcReturned ? *pcReturned : 0;
6529 needed = 0;
6531 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6532 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6534 if (res) {
6535 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6536 DWORD entrysize = 0;
6537 DWORD index;
6538 LPSTR ptr;
6539 LPMONITOR_INFO_2W mi2w;
6540 LPMONITOR_INFO_2A mi2a;
6542 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6543 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6545 /* First pass: calculate the size for all Entries */
6546 mi2w = (LPMONITOR_INFO_2W) bufferW;
6547 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6548 index = 0;
6549 while (index < numentries) {
6550 index++;
6551 needed += entrysize; /* MONITOR_INFO_?A */
6552 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6554 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6555 NULL, 0, NULL, NULL);
6556 if (Level > 1) {
6557 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6558 NULL, 0, NULL, NULL);
6559 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6560 NULL, 0, NULL, NULL);
6562 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6563 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6564 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6567 /* check for errors and quit on failure */
6568 if (cbBuf < needed) {
6569 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6570 res = FALSE;
6571 goto emA_cleanup;
6573 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6574 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6575 cbBuf -= len ; /* free Bytes in the user-Buffer */
6576 mi2w = (LPMONITOR_INFO_2W) bufferW;
6577 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6578 index = 0;
6579 /* Second Pass: Fill the User Buffer (if we have one) */
6580 while ((index < numentries) && pMonitors) {
6581 index++;
6582 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6583 mi2a->pName = ptr;
6584 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6585 ptr, cbBuf , NULL, NULL);
6586 ptr += len;
6587 cbBuf -= len;
6588 if (Level > 1) {
6589 mi2a->pEnvironment = ptr;
6590 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6591 ptr, cbBuf, NULL, NULL);
6592 ptr += len;
6593 cbBuf -= len;
6595 mi2a->pDLLName = ptr;
6596 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6597 ptr, cbBuf, NULL, NULL);
6598 ptr += len;
6599 cbBuf -= len;
6601 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6602 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6603 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6606 emA_cleanup:
6607 if (pcbNeeded) *pcbNeeded = needed;
6608 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6610 HeapFree(GetProcessHeap(), 0, nameW);
6611 HeapFree(GetProcessHeap(), 0, bufferW);
6613 TRACE("returning %d with %d (%d byte for %d entries)\n",
6614 (res), GetLastError(), needed, numentries);
6616 return (res);
6620 /*****************************************************************************
6621 * EnumMonitorsW [WINSPOOL.@]
6623 * Enumerate available Port-Monitors
6625 * PARAMS
6626 * pName [I] Servername or NULL (local Computer)
6627 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6628 * pMonitors [O] PTR to Buffer that receives the Result
6629 * cbBuf [I] Size of Buffer at pMonitors
6630 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6631 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6633 * RETURNS
6634 * Success: TRUE
6635 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6638 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6639 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6642 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6643 cbBuf, pcbNeeded, pcReturned);
6645 if ((backend == NULL) && !load_backend()) return FALSE;
6647 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6648 SetLastError(RPC_X_NULL_REF_POINTER);
6649 return FALSE;
6652 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6655 /******************************************************************************
6656 * SpoolerInit (WINSPOOL.@)
6658 * Initialize the Spooler
6660 * RETURNS
6661 * Success: TRUE
6662 * Failure: FALSE
6664 * NOTES
6665 * The function fails on windows, when the spooler service is not running
6668 BOOL WINAPI SpoolerInit(void)
6671 if ((backend == NULL) && !load_backend()) return FALSE;
6672 return TRUE;
6675 /******************************************************************************
6676 * XcvDataW (WINSPOOL.@)
6678 * Execute commands in the Printmonitor DLL
6680 * PARAMS
6681 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6682 * pszDataName [i] Name of the command to execute
6683 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6684 * cbInputData [i] Size in Bytes of Buffer at pInputData
6685 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6686 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6687 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6688 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6690 * RETURNS
6691 * Success: TRUE
6692 * Failure: FALSE
6694 * NOTES
6695 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6696 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6698 * Minimal List of commands, that a Printmonitor DLL should support:
6700 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6701 *| "AddPort" : Add a Port
6702 *| "DeletePort": Delete a Port
6704 * Many Printmonitors support additional commands. Examples for localspl.dll:
6705 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6706 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6709 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6710 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6711 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6713 opened_printer_t *printer;
6715 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6716 pInputData, cbInputData, pOutputData,
6717 cbOutputData, pcbOutputNeeded, pdwStatus);
6719 if ((backend == NULL) && !load_backend()) return FALSE;
6721 printer = get_opened_printer(hXcv);
6722 if (!printer || (!printer->backend_printer)) {
6723 SetLastError(ERROR_INVALID_HANDLE);
6724 return FALSE;
6727 if (!pcbOutputNeeded) {
6728 SetLastError(ERROR_INVALID_PARAMETER);
6729 return FALSE;
6732 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6733 SetLastError(RPC_X_NULL_REF_POINTER);
6734 return FALSE;
6737 *pcbOutputNeeded = 0;
6739 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6740 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6744 /*****************************************************************************
6745 * EnumPrinterDataA [WINSPOOL.@]
6748 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6749 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6750 DWORD cbData, LPDWORD pcbData )
6752 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6753 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6754 return ERROR_NO_MORE_ITEMS;
6757 /*****************************************************************************
6758 * EnumPrinterDataW [WINSPOOL.@]
6761 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6762 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6763 DWORD cbData, LPDWORD pcbData )
6765 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6766 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6767 return ERROR_NO_MORE_ITEMS;
6770 /*****************************************************************************
6771 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6774 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6775 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6776 LPDWORD pcbNeeded, LPDWORD pcReturned)
6778 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6779 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6780 pcbNeeded, pcReturned);
6781 return FALSE;
6784 /*****************************************************************************
6785 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6788 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6789 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6790 LPDWORD pcbNeeded, LPDWORD pcReturned)
6792 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6793 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6794 pcbNeeded, pcReturned);
6795 return FALSE;
6798 /*****************************************************************************
6799 * EnumPrintProcessorsA [WINSPOOL.@]
6801 * See EnumPrintProcessorsW.
6804 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6805 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6807 BOOL res;
6808 LPBYTE bufferW = NULL;
6809 LPWSTR nameW = NULL;
6810 LPWSTR envW = NULL;
6811 DWORD needed = 0;
6812 DWORD numentries = 0;
6813 INT len;
6815 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6816 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6818 /* convert names to unicode */
6819 if (pName) {
6820 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6821 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6822 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6824 if (pEnvironment) {
6825 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6826 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6827 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6830 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6831 needed = cbBuf * sizeof(WCHAR);
6832 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6833 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6835 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6836 if (pcbNeeded) needed = *pcbNeeded;
6837 /* HeapReAlloc return NULL, when bufferW was NULL */
6838 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6839 HeapAlloc(GetProcessHeap(), 0, needed);
6841 /* Try again with the large Buffer */
6842 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6844 numentries = pcReturned ? *pcReturned : 0;
6845 needed = 0;
6847 if (res) {
6848 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6849 DWORD index;
6850 LPSTR ptr;
6851 PPRINTPROCESSOR_INFO_1W ppiw;
6852 PPRINTPROCESSOR_INFO_1A ppia;
6854 /* First pass: calculate the size for all Entries */
6855 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6856 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6857 index = 0;
6858 while (index < numentries) {
6859 index++;
6860 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6861 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6863 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6864 NULL, 0, NULL, NULL);
6866 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6867 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6870 /* check for errors and quit on failure */
6871 if (cbBuf < needed) {
6872 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6873 res = FALSE;
6874 goto epp_cleanup;
6877 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6878 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6879 cbBuf -= len ; /* free Bytes in the user-Buffer */
6880 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6881 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6882 index = 0;
6883 /* Second Pass: Fill the User Buffer (if we have one) */
6884 while ((index < numentries) && pPPInfo) {
6885 index++;
6886 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6887 ppia->pName = ptr;
6888 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6889 ptr, cbBuf , NULL, NULL);
6890 ptr += len;
6891 cbBuf -= len;
6893 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6894 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6898 epp_cleanup:
6899 if (pcbNeeded) *pcbNeeded = needed;
6900 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6902 HeapFree(GetProcessHeap(), 0, nameW);
6903 HeapFree(GetProcessHeap(), 0, envW);
6904 HeapFree(GetProcessHeap(), 0, bufferW);
6906 TRACE("returning %d with %d (%d byte for %d entries)\n",
6907 (res), GetLastError(), needed, numentries);
6909 return (res);
6912 /*****************************************************************************
6913 * EnumPrintProcessorsW [WINSPOOL.@]
6915 * Enumerate available Print Processors
6917 * PARAMS
6918 * pName [I] Servername or NULL (local Computer)
6919 * pEnvironment [I] Printing-Environment or NULL (Default)
6920 * Level [I] Structure-Level (Only 1 is allowed)
6921 * pPPInfo [O] PTR to Buffer that receives the Result
6922 * cbBuf [I] Size of Buffer at pPPInfo
6923 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6924 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6926 * RETURNS
6927 * Success: TRUE
6928 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6931 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6932 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6935 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6936 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6938 if ((backend == NULL) && !load_backend()) return FALSE;
6940 if (!pcbNeeded || !pcReturned) {
6941 SetLastError(RPC_X_NULL_REF_POINTER);
6942 return FALSE;
6945 if (!pPPInfo && (cbBuf > 0)) {
6946 SetLastError(ERROR_INVALID_USER_BUFFER);
6947 return FALSE;
6950 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6951 cbBuf, pcbNeeded, pcReturned);
6954 /*****************************************************************************
6955 * ExtDeviceMode [WINSPOOL.@]
6958 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6959 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6960 DWORD fMode)
6962 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6963 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6964 debugstr_a(pProfile), fMode);
6965 return -1;
6968 /*****************************************************************************
6969 * FindClosePrinterChangeNotification [WINSPOOL.@]
6972 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6974 FIXME("Stub: %p\n", hChange);
6975 return TRUE;
6978 /*****************************************************************************
6979 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6982 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6983 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6985 FIXME("Stub: %p %x %x %p\n",
6986 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6987 return INVALID_HANDLE_VALUE;
6990 /*****************************************************************************
6991 * FindNextPrinterChangeNotification [WINSPOOL.@]
6994 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6995 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6997 FIXME("Stub: %p %p %p %p\n",
6998 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6999 return FALSE;
7002 /*****************************************************************************
7003 * FreePrinterNotifyInfo [WINSPOOL.@]
7006 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7008 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7009 return TRUE;
7012 /*****************************************************************************
7013 * string_to_buf
7015 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7016 * ansi depending on the unicode parameter.
7018 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7020 if(!str)
7022 *size = 0;
7023 return TRUE;
7026 if(unicode)
7028 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7029 if(*size <= cb)
7031 memcpy(ptr, str, *size);
7032 return TRUE;
7034 return FALSE;
7036 else
7038 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7039 if(*size <= cb)
7041 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7042 return TRUE;
7044 return FALSE;
7048 /*****************************************************************************
7049 * get_job_info_1
7051 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7052 LPDWORD pcbNeeded, BOOL unicode)
7054 DWORD size, left = cbBuf;
7055 BOOL space = (cbBuf > 0);
7056 LPBYTE ptr = buf;
7058 *pcbNeeded = 0;
7060 if(space)
7062 ji1->JobId = job->job_id;
7065 string_to_buf(job->document_title, ptr, left, &size, unicode);
7066 if(space && size <= left)
7068 ji1->pDocument = (LPWSTR)ptr;
7069 ptr += size;
7070 left -= size;
7072 else
7073 space = FALSE;
7074 *pcbNeeded += size;
7076 return space;
7079 /*****************************************************************************
7080 * get_job_info_2
7082 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7083 LPDWORD pcbNeeded, BOOL unicode)
7085 DWORD size, left = cbBuf;
7086 BOOL space = (cbBuf > 0);
7087 LPBYTE ptr = buf;
7089 *pcbNeeded = 0;
7091 if(space)
7093 ji2->JobId = job->job_id;
7096 string_to_buf(job->document_title, ptr, left, &size, unicode);
7097 if(space && size <= left)
7099 ji2->pDocument = (LPWSTR)ptr;
7100 ptr += size;
7101 left -= size;
7103 else
7104 space = FALSE;
7105 *pcbNeeded += size;
7107 return space;
7110 /*****************************************************************************
7111 * get_job_info
7113 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7114 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7116 BOOL ret = FALSE;
7117 DWORD needed = 0, size;
7118 job_t *job;
7119 LPBYTE ptr = pJob;
7121 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7123 EnterCriticalSection(&printer_handles_cs);
7124 job = get_job(hPrinter, JobId);
7125 if(!job)
7126 goto end;
7128 switch(Level)
7130 case 1:
7131 size = sizeof(JOB_INFO_1W);
7132 if(cbBuf >= size)
7134 cbBuf -= size;
7135 ptr += size;
7136 memset(pJob, 0, size);
7138 else
7139 cbBuf = 0;
7140 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7141 needed += size;
7142 break;
7144 case 2:
7145 size = sizeof(JOB_INFO_2W);
7146 if(cbBuf >= size)
7148 cbBuf -= size;
7149 ptr += size;
7150 memset(pJob, 0, size);
7152 else
7153 cbBuf = 0;
7154 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7155 needed += size;
7156 break;
7158 case 3:
7159 size = sizeof(JOB_INFO_3);
7160 if(cbBuf >= size)
7162 cbBuf -= size;
7163 memset(pJob, 0, size);
7164 ret = TRUE;
7166 else
7167 cbBuf = 0;
7168 needed = size;
7169 break;
7171 default:
7172 SetLastError(ERROR_INVALID_LEVEL);
7173 goto end;
7175 if(pcbNeeded)
7176 *pcbNeeded = needed;
7177 end:
7178 LeaveCriticalSection(&printer_handles_cs);
7179 return ret;
7182 /*****************************************************************************
7183 * GetJobA [WINSPOOL.@]
7186 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7187 DWORD cbBuf, LPDWORD pcbNeeded)
7189 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7192 /*****************************************************************************
7193 * GetJobW [WINSPOOL.@]
7196 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7197 DWORD cbBuf, LPDWORD pcbNeeded)
7199 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7202 /*****************************************************************************
7203 * schedule_lpr
7205 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7207 char *unixname, *queue, *cmd;
7208 char fmt[] = "lpr -P%s %s";
7209 DWORD len;
7210 int r;
7212 if(!(unixname = wine_get_unix_file_name(filename)))
7213 return FALSE;
7215 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7216 queue = HeapAlloc(GetProcessHeap(), 0, len);
7217 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7219 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7220 sprintf(cmd, fmt, queue, unixname);
7222 TRACE("printing with: %s\n", cmd);
7223 r = system(cmd);
7225 HeapFree(GetProcessHeap(), 0, cmd);
7226 HeapFree(GetProcessHeap(), 0, queue);
7227 HeapFree(GetProcessHeap(), 0, unixname);
7228 return (r == 0);
7231 /*****************************************************************************
7232 * schedule_cups
7234 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7236 #ifdef SONAME_LIBCUPS
7237 if(pcupsPrintFile)
7239 char *unixname, *queue, *unix_doc_title;
7240 DWORD len;
7241 BOOL ret;
7243 if(!(unixname = wine_get_unix_file_name(filename)))
7244 return FALSE;
7246 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7247 queue = HeapAlloc(GetProcessHeap(), 0, len);
7248 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7250 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7251 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7252 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7254 TRACE("printing via cups\n");
7255 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7256 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7257 HeapFree(GetProcessHeap(), 0, queue);
7258 HeapFree(GetProcessHeap(), 0, unixname);
7259 return ret;
7261 else
7262 #endif
7264 return schedule_lpr(printer_name, filename);
7268 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7270 LPWSTR filename;
7272 switch(msg)
7274 case WM_INITDIALOG:
7275 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7276 return TRUE;
7278 case WM_COMMAND:
7279 if(HIWORD(wparam) == BN_CLICKED)
7281 if(LOWORD(wparam) == IDOK)
7283 HANDLE hf;
7284 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7285 LPWSTR *output;
7287 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7288 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7290 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7292 WCHAR caption[200], message[200];
7293 int mb_ret;
7295 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7296 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7297 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7298 if(mb_ret == IDCANCEL)
7300 HeapFree(GetProcessHeap(), 0, filename);
7301 return TRUE;
7304 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7305 if(hf == INVALID_HANDLE_VALUE)
7307 WCHAR caption[200], message[200];
7309 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7310 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7311 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7312 HeapFree(GetProcessHeap(), 0, filename);
7313 return TRUE;
7315 CloseHandle(hf);
7316 DeleteFileW(filename);
7317 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7318 *output = filename;
7319 EndDialog(hwnd, IDOK);
7320 return TRUE;
7322 if(LOWORD(wparam) == IDCANCEL)
7324 EndDialog(hwnd, IDCANCEL);
7325 return TRUE;
7328 return FALSE;
7330 return FALSE;
7333 /*****************************************************************************
7334 * get_filename
7336 static BOOL get_filename(LPWSTR *filename)
7338 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7339 file_dlg_proc, (LPARAM)filename) == IDOK;
7342 /*****************************************************************************
7343 * schedule_file
7345 static BOOL schedule_file(LPCWSTR filename)
7347 LPWSTR output = NULL;
7349 if(get_filename(&output))
7351 BOOL r;
7352 TRACE("copy to %s\n", debugstr_w(output));
7353 r = CopyFileW(filename, output, FALSE);
7354 HeapFree(GetProcessHeap(), 0, output);
7355 return r;
7357 return FALSE;
7360 /*****************************************************************************
7361 * schedule_pipe
7363 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7365 #ifdef HAVE_FORK
7366 char *unixname, *cmdA;
7367 DWORD len;
7368 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7369 BOOL ret = FALSE;
7370 char buf[1024];
7372 if(!(unixname = wine_get_unix_file_name(filename)))
7373 return FALSE;
7375 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7376 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7377 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7379 TRACE("printing with: %s\n", cmdA);
7381 if((file_fd = open(unixname, O_RDONLY)) == -1)
7382 goto end;
7384 if (pipe(fds))
7386 ERR("pipe() failed!\n");
7387 goto end;
7390 if (fork() == 0)
7392 close(0);
7393 dup2(fds[0], 0);
7394 close(fds[1]);
7396 /* reset signals that we previously set to SIG_IGN */
7397 signal(SIGPIPE, SIG_DFL);
7398 signal(SIGCHLD, SIG_DFL);
7400 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7401 _exit(1);
7404 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7405 write(fds[1], buf, no_read);
7407 ret = TRUE;
7409 end:
7410 if(file_fd != -1) close(file_fd);
7411 if(fds[0] != -1) close(fds[0]);
7412 if(fds[1] != -1) close(fds[1]);
7414 HeapFree(GetProcessHeap(), 0, cmdA);
7415 HeapFree(GetProcessHeap(), 0, unixname);
7416 return ret;
7417 #else
7418 return FALSE;
7419 #endif
7422 /*****************************************************************************
7423 * schedule_unixfile
7425 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7427 int in_fd, out_fd, no_read;
7428 char buf[1024];
7429 BOOL ret = FALSE;
7430 char *unixname, *outputA;
7431 DWORD len;
7433 if(!(unixname = wine_get_unix_file_name(filename)))
7434 return FALSE;
7436 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7437 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7438 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7440 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7441 in_fd = open(unixname, O_RDONLY);
7442 if(out_fd == -1 || in_fd == -1)
7443 goto end;
7445 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7446 write(out_fd, buf, no_read);
7448 ret = TRUE;
7449 end:
7450 if(in_fd != -1) close(in_fd);
7451 if(out_fd != -1) close(out_fd);
7452 HeapFree(GetProcessHeap(), 0, outputA);
7453 HeapFree(GetProcessHeap(), 0, unixname);
7454 return ret;
7457 /*****************************************************************************
7458 * ScheduleJob [WINSPOOL.@]
7461 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7463 opened_printer_t *printer;
7464 BOOL ret = FALSE;
7465 struct list *cursor, *cursor2;
7467 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7468 EnterCriticalSection(&printer_handles_cs);
7469 printer = get_opened_printer(hPrinter);
7470 if(!printer)
7471 goto end;
7473 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7475 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7476 HANDLE hf;
7478 if(job->job_id != dwJobID) continue;
7480 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7481 if(hf != INVALID_HANDLE_VALUE)
7483 PRINTER_INFO_5W *pi5 = NULL;
7484 LPWSTR portname = job->portname;
7485 DWORD needed;
7486 HKEY hkey;
7487 WCHAR output[1024];
7488 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7489 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7491 if (!portname)
7493 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7494 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7495 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7496 portname = pi5->pPortName;
7498 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7499 debugstr_w(portname));
7501 output[0] = 0;
7503 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7504 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7506 DWORD type, count = sizeof(output);
7507 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7508 RegCloseKey(hkey);
7510 if(output[0] == '|')
7512 ret = schedule_pipe(output + 1, job->filename);
7514 else if(output[0])
7516 ret = schedule_unixfile(output, job->filename);
7518 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7520 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7522 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7524 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7526 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7528 ret = schedule_file(job->filename);
7530 else
7532 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7534 HeapFree(GetProcessHeap(), 0, pi5);
7535 CloseHandle(hf);
7536 DeleteFileW(job->filename);
7538 list_remove(cursor);
7539 HeapFree(GetProcessHeap(), 0, job->document_title);
7540 HeapFree(GetProcessHeap(), 0, job->portname);
7541 HeapFree(GetProcessHeap(), 0, job->filename);
7542 HeapFree(GetProcessHeap(), 0, job);
7543 break;
7545 end:
7546 LeaveCriticalSection(&printer_handles_cs);
7547 return ret;
7550 /*****************************************************************************
7551 * StartDocDlgA [WINSPOOL.@]
7553 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7555 UNICODE_STRING usBuffer;
7556 DOCINFOW docW;
7557 LPWSTR retW;
7558 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7559 LPSTR ret = NULL;
7561 docW.cbSize = sizeof(docW);
7562 if (doc->lpszDocName)
7564 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7565 if (!(docW.lpszDocName = docnameW)) return NULL;
7567 if (doc->lpszOutput)
7569 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7570 if (!(docW.lpszOutput = outputW)) return NULL;
7572 if (doc->lpszDatatype)
7574 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7575 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7577 docW.fwType = doc->fwType;
7579 retW = StartDocDlgW(hPrinter, &docW);
7581 if(retW)
7583 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7584 ret = HeapAlloc(GetProcessHeap(), 0, len);
7585 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7586 HeapFree(GetProcessHeap(), 0, retW);
7589 HeapFree(GetProcessHeap(), 0, datatypeW);
7590 HeapFree(GetProcessHeap(), 0, outputW);
7591 HeapFree(GetProcessHeap(), 0, docnameW);
7593 return ret;
7596 /*****************************************************************************
7597 * StartDocDlgW [WINSPOOL.@]
7599 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7600 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7601 * port is "FILE:". Also returns the full path if passed a relative path.
7603 * The caller should free the returned string from the process heap.
7605 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7607 LPWSTR ret = NULL;
7608 DWORD len, attr;
7610 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7612 PRINTER_INFO_5W *pi5;
7613 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7614 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7615 return NULL;
7616 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7617 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7618 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7620 HeapFree(GetProcessHeap(), 0, pi5);
7621 return NULL;
7623 HeapFree(GetProcessHeap(), 0, pi5);
7626 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7628 LPWSTR name;
7630 if (get_filename(&name))
7632 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7634 HeapFree(GetProcessHeap(), 0, name);
7635 return NULL;
7637 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7638 GetFullPathNameW(name, len, ret, NULL);
7639 HeapFree(GetProcessHeap(), 0, name);
7641 return ret;
7644 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7645 return NULL;
7647 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7648 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7650 attr = GetFileAttributesW(ret);
7651 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7653 HeapFree(GetProcessHeap(), 0, ret);
7654 ret = NULL;
7656 return ret;