quartz: Only allocate 1 buffer in transform filter.
[wine/wine64.git] / dlls / winspool.drv / info.c
blob81d6b61af61d935575f984b731a5c9feeb450f29
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-2008 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 monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
201 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
202 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
203 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
204 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
206 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
207 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
209 static const WCHAR backslashW[] = {'\\',0};
210 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
211 'i','o','n',' ','F','i','l','e',0};
212 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
213 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
214 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
215 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
216 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
218 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
219 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
220 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
221 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
222 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
223 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
224 static const WCHAR NameW[] = {'N','a','m','e',0};
225 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
226 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
227 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
228 static const WCHAR PortW[] = {'P','o','r','t',0};
229 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
230 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
234 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
235 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW[] = {0};
244 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
257 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
258 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
259 0, sizeof(DRIVER_INFO_8W)};
262 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
263 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
264 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
265 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
266 sizeof(PRINTER_INFO_9W)};
268 /******************************************************************
269 * validate the user-supplied printing-environment [internal]
271 * PARAMS
272 * env [I] PTR to Environment-String or NULL
274 * RETURNS
275 * Failure: NULL
276 * Success: PTR to printenv_t
278 * NOTES
279 * An empty string is handled the same way as NULL.
280 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
284 static const printenv_t * validate_envW(LPCWSTR env)
286 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
287 3, Version3_RegPathW, Version3_SubdirW};
288 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
289 0, Version0_RegPathW, Version0_SubdirW};
291 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
293 const printenv_t *result = NULL;
294 unsigned int i;
296 TRACE("testing %s\n", debugstr_w(env));
297 if (env && env[0])
299 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
301 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
303 result = all_printenv[i];
304 break;
308 if (result == NULL) {
309 FIXME("unsupported Environment: %s\n", debugstr_w(env));
310 SetLastError(ERROR_INVALID_ENVIRONMENT);
312 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
314 else
316 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
318 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
320 return result;
324 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
325 if passed a NULL string. This returns NULLs to the result.
327 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
329 if ( (src) )
331 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
332 return usBufferPtr->Buffer;
334 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
335 return NULL;
338 static LPWSTR strdupW(LPCWSTR p)
340 LPWSTR ret;
341 DWORD len;
343 if(!p) return NULL;
344 len = (strlenW(p) + 1) * sizeof(WCHAR);
345 ret = HeapAlloc(GetProcessHeap(), 0, len);
346 memcpy(ret, p, len);
347 return ret;
350 static LPSTR strdupWtoA( LPCWSTR str )
352 LPSTR ret;
353 INT len;
355 if (!str) return NULL;
356 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
357 ret = HeapAlloc( GetProcessHeap(), 0, len );
358 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
359 return ret;
362 /******************************************************************
363 * Return the number of bytes for an multi_sz string.
364 * The result includes all \0s
365 * (specifically the extra \0, that is needed as multi_sz terminator).
367 #if 0
368 static int multi_sz_lenW(const WCHAR *str)
370 const WCHAR *ptr = str;
371 if(!str) return 0;
374 ptr += lstrlenW(ptr) + 1;
375 } while(*ptr);
377 return (ptr - str + 1) * sizeof(WCHAR);
379 #endif
380 /* ################################ */
382 static int multi_sz_lenA(const char *str)
384 const char *ptr = str;
385 if(!str) return 0;
388 ptr += lstrlenA(ptr) + 1;
389 } while(*ptr);
391 return ptr - str + 1;
394 static void
395 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
396 char qbuf[200];
398 /* If forcing, or no profile string entry for device yet, set the entry
400 * The always change entry if not WINEPS yet is discussable.
402 if (force ||
403 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
404 !strcmp(qbuf,"*") ||
405 !strstr(qbuf,"WINEPS.DRV")
407 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
408 HKEY hkey;
410 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
411 WriteProfileStringA("windows","device",buf);
412 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
413 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
414 RegCloseKey(hkey);
416 HeapFree(GetProcessHeap(),0,buf);
420 static BOOL add_printer_driver(const char *name)
422 DRIVER_INFO_3A di3a;
424 static char driver_9x[] = "wineps16.drv",
425 driver_nt[] = "wineps.drv",
426 env_9x[] = "Windows 4.0",
427 env_nt[] = "Windows NT x86",
428 data_file[] = "generic.ppd",
429 default_data_type[] = "RAW";
431 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
432 di3a.cVersion = 3;
433 di3a.pName = (char *)name;
434 di3a.pEnvironment = env_nt;
435 di3a.pDriverPath = driver_nt;
436 di3a.pDataFile = data_file;
437 di3a.pConfigFile = driver_nt;
438 di3a.pDefaultDataType = default_data_type;
440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
443 di3a.cVersion = 0;
444 di3a.pEnvironment = env_9x;
445 di3a.pDriverPath = driver_9x;
446 di3a.pConfigFile = driver_9x;
447 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
448 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
450 return TRUE;
453 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
454 debugstr_a(di3a.pEnvironment), GetLastError());
455 return FALSE;
458 #ifdef SONAME_LIBCUPS
459 static typeof(cupsGetDests) *pcupsGetDests;
460 static typeof(cupsGetPPD) *pcupsGetPPD;
461 static typeof(cupsPrintFile) *pcupsPrintFile;
462 static void *cupshandle;
464 static BOOL CUPS_LoadPrinters(void)
466 int i, nrofdests;
467 BOOL hadprinter = FALSE, haddefault = FALSE;
468 cups_dest_t *dests;
469 PRINTER_INFO_2A pinfo2a;
470 char *port,*devline;
471 HKEY hkeyPrinter, hkeyPrinters, hkey;
472 char loaderror[256];
474 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
475 if (!cupshandle) {
476 TRACE("%s\n", loaderror);
477 return FALSE;
479 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
481 #define DYNCUPS(x) \
482 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
483 if (!p##x) return FALSE;
485 DYNCUPS(cupsGetPPD);
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
488 #undef DYNCUPS
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491 ERROR_SUCCESS) {
492 ERR("Can't create Printers key\n");
493 return FALSE;
496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498 for (i=0;i<nrofdests;i++) {
499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501 sprintf(port,"LPR:%s", dests[i].name);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504 sprintf(devline, "WINEPS.DRV,%s", port);
505 WriteProfileStringA("devices", dests[i].name, devline);
506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
508 RegCloseKey(hkey);
511 lstrcatA(devline, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 RegCloseKey(hkey);
518 HeapFree(GetProcessHeap(), 0, devline);
520 TRACE("Printer %d: %s\n", i, dests[i].name);
521 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
523 and continue */
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526 RegCloseKey(hkeyPrinter);
527 } else {
528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
530 comment[] = "WINEPS Printer using CUPS",
531 location[] = "<physical location of printer>",
532 params[] = "<parameters?>",
533 share_name[] = "<share name?>",
534 sep_file[] = "<sep file?>";
536 add_printer_driver(dests[i].name);
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = dests[i].name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = location;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
555 HeapFree(GetProcessHeap(),0,port);
557 hadprinter = TRUE;
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
560 haddefault = TRUE;
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 RegCloseKey(hkeyPrinters);
566 return hadprinter;
568 #endif
570 static BOOL
571 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
572 PRINTER_INFO_2A pinfo2a;
573 char *e,*s,*name,*prettyname,*devname;
574 BOOL ret = FALSE, set_default = FALSE;
575 char *port = NULL, *devline,*env_default;
576 HKEY hkeyPrinter, hkeyPrinters, hkey;
578 while (isspace(*pent)) pent++;
579 s = strchr(pent,':');
580 if(s) *s='\0';
581 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
582 strcpy(name,pent);
583 if(s) {
584 *s=':';
585 pent = s;
586 } else
587 pent = "";
589 TRACE("name=%s entry=%s\n",name, pent);
591 if(ispunct(*name)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
593 goto end;
596 if(strstr(pent,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
598 goto end;
601 /* Determine whether this is a postscript printer. */
603 ret = TRUE;
604 env_default = getenv("PRINTER");
605 prettyname = name;
606 /* Get longest name, usually the one at the right for later display. */
607 while((s=strchr(prettyname,'|'))) {
608 *s = '\0';
609 e = s;
610 while(isspace(*--e)) *e = '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname));
612 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
613 for(prettyname = s+1; isspace(*prettyname); prettyname++)
616 e = prettyname + strlen(prettyname);
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname = prettyname;
624 if (strlen(devname)>=CCHDEVICENAME-1)
625 devname = name;
626 if (strlen(devname)>=CCHDEVICENAME-1) {
627 ret = FALSE;
628 goto end;
631 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
632 sprintf(port,"LPR:%s",name);
634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
636 sprintf(devline, "WINEPS.DRV,%s", port);
637 WriteProfileStringA("devices", devname, devline);
638 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
639 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
640 RegCloseKey(hkey);
643 lstrcatA(devline, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
647 RegCloseKey(hkey);
650 HeapFree(GetProcessHeap(),0,devline);
652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
653 ERROR_SUCCESS) {
654 ERR("Can't create Printers key\n");
655 ret = FALSE;
656 goto end;
658 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
660 and continue */
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
663 RegCloseKey(hkeyPrinter);
664 } else {
665 static CHAR data_type[] = "RAW",
666 print_proc[] = "WinPrint",
667 comment[] = "WINEPS Printer using LPR",
668 params[] = "<parameters?>",
669 share_name[] = "<share name?>",
670 sep_file[] = "<sep file?>";
672 add_printer_driver(devname);
674 memset(&pinfo2a,0,sizeof(pinfo2a));
675 pinfo2a.pPrinterName = devname;
676 pinfo2a.pDatatype = data_type;
677 pinfo2a.pPrintProcessor = print_proc;
678 pinfo2a.pDriverName = devname;
679 pinfo2a.pComment = comment;
680 pinfo2a.pLocation = prettyname;
681 pinfo2a.pPortName = port;
682 pinfo2a.pParameters = params;
683 pinfo2a.pShareName = share_name;
684 pinfo2a.pSepFile = sep_file;
686 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
688 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
691 RegCloseKey(hkeyPrinters);
693 if (isfirst || set_default)
694 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
696 end:
697 HeapFree(GetProcessHeap(), 0, port);
698 HeapFree(GetProcessHeap(), 0, name);
699 return ret;
702 static BOOL
703 PRINTCAP_LoadPrinters(void) {
704 BOOL hadprinter = FALSE;
705 char buf[200];
706 FILE *f;
707 char *pent = NULL;
708 BOOL had_bash = FALSE;
710 f = fopen("/etc/printcap","r");
711 if (!f)
712 return FALSE;
714 while(fgets(buf,sizeof(buf),f)) {
715 char *start, *end;
717 end=strchr(buf,'\n');
718 if (end) *end='\0';
720 start = buf;
721 while(isspace(*start)) start++;
722 if(*start == '#' || *start == '\0')
723 continue;
725 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
726 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
727 HeapFree(GetProcessHeap(),0,pent);
728 pent = NULL;
731 if (end && *--end == '\\') {
732 *end = '\0';
733 had_bash = TRUE;
734 } else
735 had_bash = FALSE;
737 if (pent) {
738 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
739 strcat(pent,start);
740 } else {
741 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
742 strcpy(pent,start);
746 if(pent) {
747 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
748 HeapFree(GetProcessHeap(),0,pent);
750 fclose(f);
751 return hadprinter;
754 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
756 if (value)
757 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
758 (lstrlenW(value) + 1) * sizeof(WCHAR));
759 else
760 return ERROR_FILE_NOT_FOUND;
763 /******************************************************************
764 * monitor_unload [internal]
766 * release a printmonitor and unload it from memory, when needed
769 static void monitor_unload(monitor_t * pm)
771 if (pm == NULL) return;
772 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
774 EnterCriticalSection(&monitor_handles_cs);
776 if (pm->refcount) pm->refcount--;
778 if (pm->refcount == 0) {
779 list_remove(&pm->entry);
780 FreeLibrary(pm->hdll);
781 HeapFree(GetProcessHeap(), 0, pm->name);
782 HeapFree(GetProcessHeap(), 0, pm->dllname);
783 HeapFree(GetProcessHeap(), 0, pm);
785 LeaveCriticalSection(&monitor_handles_cs);
788 /******************************************************************
789 * monitor_unloadall [internal]
791 * release all printmonitors and unload them from memory, when needed
794 static void monitor_unloadall(void)
796 monitor_t * pm;
797 monitor_t * next;
799 EnterCriticalSection(&monitor_handles_cs);
800 /* iterate through the list, with safety against removal */
801 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
803 monitor_unload(pm);
805 LeaveCriticalSection(&monitor_handles_cs);
808 /******************************************************************
809 * monitor_load [internal]
811 * load a printmonitor, get the dllname from the registry, when needed
812 * initialize the monitor and dump found function-pointers
814 * On failure, SetLastError() is called and NULL is returned
817 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
819 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
820 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
821 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
822 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
823 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
825 monitor_t * pm = NULL;
826 monitor_t * cursor;
827 LPWSTR regroot = NULL;
828 LPWSTR driver = dllname;
830 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
831 /* Is the Monitor already loaded? */
832 EnterCriticalSection(&monitor_handles_cs);
834 if (name) {
835 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
837 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
838 pm = cursor;
839 break;
844 if (pm == NULL) {
845 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
846 if (pm == NULL) goto cleanup;
847 list_add_tail(&monitor_handles, &pm->entry);
849 pm->refcount++;
851 if (pm->name == NULL) {
852 /* Load the monitor */
853 LPMONITOREX pmonitorEx;
854 DWORD len;
856 if (name) {
857 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
858 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
861 if (regroot) {
862 lstrcpyW(regroot, MonitorsW);
863 lstrcatW(regroot, name);
864 /* Get the Driver from the Registry */
865 if (driver == NULL) {
866 HKEY hroot;
867 DWORD namesize;
868 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
869 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
870 &namesize) == ERROR_SUCCESS) {
871 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
872 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
874 RegCloseKey(hroot);
879 pm->name = strdupW(name);
880 pm->dllname = strdupW(driver);
882 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
883 monitor_unload(pm);
884 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
885 pm = NULL;
886 goto cleanup;
889 pm->hdll = LoadLibraryW(driver);
890 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
892 if (pm->hdll == NULL) {
893 monitor_unload(pm);
894 SetLastError(ERROR_MOD_NOT_FOUND);
895 pm = NULL;
896 goto cleanup;
899 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
900 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
901 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
902 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
903 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
906 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
907 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
908 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
909 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
910 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
912 if (pInitializePrintMonitorUI != NULL) {
913 pm->monitorUI = pInitializePrintMonitorUI();
914 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
915 if (pm->monitorUI) {
916 TRACE( "0x%08x: dwMonitorSize (%d)\n",
917 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
922 if (pInitializePrintMonitor && regroot) {
923 pmonitorEx = pInitializePrintMonitor(regroot);
924 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
925 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
927 if (pmonitorEx) {
928 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
929 pm->monitor = &(pmonitorEx->Monitor);
933 if (pm->monitor) {
934 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
938 if (!pm->monitor && regroot) {
939 if (pInitializePrintMonitor2 != NULL) {
940 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
942 if (pInitializeMonitorEx != NULL) {
943 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
945 if (pInitializeMonitor != NULL) {
946 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
949 if (!pm->monitor && !pm->monitorUI) {
950 monitor_unload(pm);
951 SetLastError(ERROR_PROC_NOT_FOUND);
952 pm = NULL;
955 cleanup:
956 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
957 pm->refcount++;
958 pm_localport = pm;
960 LeaveCriticalSection(&monitor_handles_cs);
961 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
962 HeapFree(GetProcessHeap(), 0, regroot);
963 TRACE("=> %p\n", pm);
964 return pm;
967 /******************************************************************
968 * monitor_loadall [internal]
970 * Load all registered monitors
973 static DWORD monitor_loadall(void)
975 monitor_t * pm;
976 DWORD registered = 0;
977 DWORD loaded = 0;
978 HKEY hmonitors;
979 WCHAR buffer[MAX_PATH];
980 DWORD id = 0;
982 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
983 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
984 NULL, NULL, NULL, NULL, NULL);
986 TRACE("%d monitors registered\n", registered);
988 EnterCriticalSection(&monitor_handles_cs);
989 while (id < registered) {
990 buffer[0] = '\0';
991 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
992 pm = monitor_load(buffer, NULL);
993 if (pm) loaded++;
994 id++;
996 LeaveCriticalSection(&monitor_handles_cs);
997 RegCloseKey(hmonitors);
999 TRACE("%d monitors loaded\n", loaded);
1000 return loaded;
1003 /******************************************************************
1004 * monitor_loadui [internal]
1006 * load the userinterface-dll for a given portmonitor
1008 * On failure, NULL is returned
1011 static monitor_t * monitor_loadui(monitor_t * pm)
1013 monitor_t * pui = NULL;
1014 LPWSTR buffer[MAX_PATH];
1015 HANDLE hXcv;
1016 DWORD len;
1017 DWORD res;
1019 if (pm == NULL) return NULL;
1020 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1022 /* Try the Portmonitor first; works for many monitors */
1023 if (pm->monitorUI) {
1024 EnterCriticalSection(&monitor_handles_cs);
1025 pm->refcount++;
1026 LeaveCriticalSection(&monitor_handles_cs);
1027 return pm;
1030 /* query the userinterface-dllname from the Portmonitor */
1031 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1032 /* building (",XcvMonitor %s",pm->name) not needed yet */
1033 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1034 TRACE("got %u with %p\n", res, hXcv);
1035 if (res) {
1036 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1037 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1038 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1039 pm->monitor->pfnXcvClosePort(hXcv);
1042 return pui;
1046 /******************************************************************
1047 * monitor_load_by_port [internal]
1049 * load a printmonitor for a given port
1051 * On failure, NULL is returned
1054 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1056 HKEY hroot;
1057 HKEY hport;
1058 LPWSTR buffer;
1059 monitor_t * pm = NULL;
1060 DWORD registered = 0;
1061 DWORD id = 0;
1062 DWORD len;
1064 TRACE("(%s)\n", debugstr_w(portname));
1066 /* Try the Local Monitor first */
1067 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1068 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1069 /* found the portname */
1070 RegCloseKey(hroot);
1071 return monitor_load(LocalPortW, NULL);
1073 RegCloseKey(hroot);
1076 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1077 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1078 if (buffer == NULL) return NULL;
1080 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1081 EnterCriticalSection(&monitor_handles_cs);
1082 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1084 while ((pm == NULL) && (id < registered)) {
1085 buffer[0] = '\0';
1086 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1087 TRACE("testing %s\n", debugstr_w(buffer));
1088 len = lstrlenW(buffer);
1089 lstrcatW(buffer, bs_Ports_bsW);
1090 lstrcatW(buffer, portname);
1091 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1092 RegCloseKey(hport);
1093 buffer[len] = '\0'; /* use only the Monitor-Name */
1094 pm = monitor_load(buffer, NULL);
1096 id++;
1098 LeaveCriticalSection(&monitor_handles_cs);
1099 RegCloseKey(hroot);
1101 HeapFree(GetProcessHeap(), 0, buffer);
1102 return pm;
1105 /******************************************************************
1106 * enumerate the local Ports from all loaded monitors (internal)
1108 * returns the needed size (in bytes) for pPorts
1109 * and *lpreturned is set to number of entries returned in pPorts
1112 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1114 monitor_t * pm;
1115 LPWSTR ptr;
1116 LPPORT_INFO_2W cache;
1117 LPPORT_INFO_2W out;
1118 LPBYTE pi_buffer = NULL;
1119 DWORD pi_allocated = 0;
1120 DWORD pi_needed;
1121 DWORD pi_index;
1122 DWORD pi_returned;
1123 DWORD res;
1124 DWORD outindex = 0;
1125 DWORD needed;
1126 DWORD numentries;
1127 DWORD entrysize;
1130 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1131 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1133 numentries = *lpreturned; /* this is 0, when we scan the registry */
1134 needed = entrysize * numentries;
1135 ptr = (LPWSTR) &pPorts[needed];
1137 numentries = 0;
1138 needed = 0;
1140 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1142 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1143 pi_needed = 0;
1144 pi_returned = 0;
1145 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1146 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1147 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1148 HeapFree(GetProcessHeap(), 0, pi_buffer);
1149 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1150 pi_allocated = (pi_buffer) ? pi_needed : 0;
1151 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1153 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1154 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1156 numentries += pi_returned;
1157 needed += pi_needed;
1159 /* fill the output-buffer (pPorts), if we have one */
1160 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1161 pi_index = 0;
1162 while (pi_returned > pi_index) {
1163 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1164 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1165 out->pPortName = ptr;
1166 lstrcpyW(ptr, cache->pPortName);
1167 ptr += (lstrlenW(ptr)+1);
1168 if (level > 1) {
1169 out->pMonitorName = ptr;
1170 lstrcpyW(ptr, cache->pMonitorName);
1171 ptr += (lstrlenW(ptr)+1);
1173 out->pDescription = ptr;
1174 lstrcpyW(ptr, cache->pDescription);
1175 ptr += (lstrlenW(ptr)+1);
1176 out->fPortType = cache->fPortType;
1177 out->Reserved = cache->Reserved;
1179 pi_index++;
1180 outindex++;
1185 /* the temporary portinfo-buffer is no longer needed */
1186 HeapFree(GetProcessHeap(), 0, pi_buffer);
1188 *lpreturned = numentries;
1189 TRACE("need %d byte for %d entries\n", needed, numentries);
1190 return needed;
1193 /******************************************************************
1194 * get_servername_from_name (internal)
1196 * for an external server, a copy of the serverpart from the full name is returned
1199 static LPWSTR get_servername_from_name(LPCWSTR name)
1201 LPWSTR server;
1202 LPWSTR ptr;
1203 WCHAR buffer[MAX_PATH];
1204 DWORD len;
1206 if (name == NULL) return NULL;
1207 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1209 server = strdupW(&name[2]); /* skip over both backslash */
1210 if (server == NULL) return NULL;
1212 /* strip '\' and the printername */
1213 ptr = strchrW(server, '\\');
1214 if (ptr) ptr[0] = '\0';
1216 TRACE("found %s\n", debugstr_w(server));
1218 len = sizeof(buffer)/sizeof(buffer[0]);
1219 if (GetComputerNameW(buffer, &len)) {
1220 if (lstrcmpW(buffer, server) == 0) {
1221 /* The requested Servername is our computername */
1222 HeapFree(GetProcessHeap(), 0, server);
1223 return NULL;
1226 return server;
1229 /******************************************************************
1230 * get_basename_from_name (internal)
1232 * skip over the serverpart from the full name
1235 static LPCWSTR get_basename_from_name(LPCWSTR name)
1237 if (name == NULL) return NULL;
1238 if ((name[0] == '\\') && (name[1] == '\\')) {
1239 /* skip over the servername and search for the following '\' */
1240 name = strchrW(&name[2], '\\');
1241 if ((name) && (name[1])) {
1242 /* found a separator ('\') followed by a name:
1243 skip over the separator and return the rest */
1244 name++;
1246 else
1248 /* no basename present (we found only a servername) */
1249 return NULL;
1252 return name;
1255 /******************************************************************
1256 * get_opened_printer_entry
1257 * Get the first place empty in the opened printer table
1259 * ToDo:
1260 * - pDefault is ignored
1262 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1264 UINT_PTR handle = nb_printer_handles, i;
1265 jobqueue_t *queue = NULL;
1266 opened_printer_t *printer = NULL;
1267 LPWSTR servername;
1268 LPCWSTR printername;
1269 HKEY hkeyPrinters;
1270 HKEY hkeyPrinter;
1271 DWORD len;
1273 servername = get_servername_from_name(name);
1274 if (servername) {
1275 FIXME("server %s not supported\n", debugstr_w(servername));
1276 HeapFree(GetProcessHeap(), 0, servername);
1277 SetLastError(ERROR_INVALID_PRINTER_NAME);
1278 return NULL;
1281 printername = get_basename_from_name(name);
1282 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1284 /* an empty printername is invalid */
1285 if (printername && (!printername[0])) {
1286 SetLastError(ERROR_INVALID_PARAMETER);
1287 return NULL;
1290 EnterCriticalSection(&printer_handles_cs);
1292 for (i = 0; i < nb_printer_handles; i++)
1294 if (!printer_handles[i])
1296 if(handle == nb_printer_handles)
1297 handle = i;
1299 else
1301 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1302 queue = printer_handles[i]->queue;
1306 if (handle >= nb_printer_handles)
1308 opened_printer_t **new_array;
1309 if (printer_handles)
1310 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1311 (nb_printer_handles + 16) * sizeof(*new_array) );
1312 else
1313 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1314 (nb_printer_handles + 16) * sizeof(*new_array) );
1316 if (!new_array)
1318 handle = 0;
1319 goto end;
1321 printer_handles = new_array;
1322 nb_printer_handles += 16;
1325 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1327 handle = 0;
1328 goto end;
1332 /* clone the base name. This is NULL for the printserver */
1333 printer->printername = strdupW(printername);
1335 /* clone the full name */
1336 printer->name = strdupW(name);
1337 if (name && (!printer->name)) {
1338 handle = 0;
1339 goto end;
1342 if (printername) {
1343 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1344 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1345 /* OpenPrinter(",XcvMonitor " detected */
1346 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1347 printer->pm = monitor_load(&printername[len], NULL);
1348 if (printer->pm == NULL) {
1349 SetLastError(ERROR_UNKNOWN_PORT);
1350 handle = 0;
1351 goto end;
1354 else
1356 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1357 if (strncmpW( printername, XcvPortW, len) == 0) {
1358 /* OpenPrinter(",XcvPort " detected */
1359 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1360 printer->pm = monitor_load_by_port(&printername[len]);
1361 if (printer->pm == NULL) {
1362 SetLastError(ERROR_UNKNOWN_PORT);
1363 handle = 0;
1364 goto end;
1369 if (printer->pm) {
1370 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1371 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1372 pDefault ? pDefault->DesiredAccess : 0,
1373 &printer->hXcv);
1375 if (printer->hXcv == NULL) {
1376 SetLastError(ERROR_INVALID_PARAMETER);
1377 handle = 0;
1378 goto end;
1381 else
1383 /* Does the Printer exist? */
1384 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1385 ERR("Can't create Printers key\n");
1386 handle = 0;
1387 goto end;
1389 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1390 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1391 RegCloseKey(hkeyPrinters);
1392 SetLastError(ERROR_INVALID_PRINTER_NAME);
1393 handle = 0;
1394 goto end;
1396 RegCloseKey(hkeyPrinter);
1397 RegCloseKey(hkeyPrinters);
1400 else
1402 TRACE("using the local printserver\n");
1405 if(queue)
1406 printer->queue = queue;
1407 else
1409 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1410 if (!printer->queue) {
1411 handle = 0;
1412 goto end;
1414 list_init(&printer->queue->jobs);
1415 printer->queue->ref = 0;
1417 InterlockedIncrement(&printer->queue->ref);
1419 printer_handles[handle] = printer;
1420 handle++;
1421 end:
1422 LeaveCriticalSection(&printer_handles_cs);
1423 if (!handle && printer) {
1424 /* Something failed: Free all resources */
1425 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1426 monitor_unload(printer->pm);
1427 HeapFree(GetProcessHeap(), 0, printer->printername);
1428 HeapFree(GetProcessHeap(), 0, printer->name);
1429 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1430 HeapFree(GetProcessHeap(), 0, printer);
1433 return (HANDLE)handle;
1436 /******************************************************************
1437 * get_opened_printer
1438 * Get the pointer to the opened printer referred by the handle
1440 static opened_printer_t *get_opened_printer(HANDLE hprn)
1442 UINT_PTR idx = (UINT_PTR)hprn;
1443 opened_printer_t *ret = NULL;
1445 EnterCriticalSection(&printer_handles_cs);
1447 if ((idx > 0) && (idx <= nb_printer_handles)) {
1448 ret = printer_handles[idx - 1];
1450 LeaveCriticalSection(&printer_handles_cs);
1451 return ret;
1454 /******************************************************************
1455 * get_opened_printer_name
1456 * Get the pointer to the opened printer name referred by the handle
1458 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1460 opened_printer_t *printer = get_opened_printer(hprn);
1461 if(!printer) return NULL;
1462 return printer->name;
1465 /******************************************************************
1466 * WINSPOOL_GetOpenedPrinterRegKey
1469 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1471 LPCWSTR name = get_opened_printer_name(hPrinter);
1472 DWORD ret;
1473 HKEY hkeyPrinters;
1475 if(!name) return ERROR_INVALID_HANDLE;
1477 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1478 ERROR_SUCCESS)
1479 return ret;
1481 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1483 ERR("Can't find opened printer %s in registry\n",
1484 debugstr_w(name));
1485 RegCloseKey(hkeyPrinters);
1486 return ERROR_INVALID_PRINTER_NAME; /* ? */
1488 RegCloseKey(hkeyPrinters);
1489 return ERROR_SUCCESS;
1492 void WINSPOOL_LoadSystemPrinters(void)
1494 HKEY hkey, hkeyPrinters;
1495 HANDLE hprn;
1496 DWORD needed, num, i;
1497 WCHAR PrinterName[256];
1498 BOOL done = FALSE;
1500 /* This ensures that all printer entries have a valid Name value. If causes
1501 problems later if they don't. If one is found to be missed we create one
1502 and set it equal to the name of the key */
1503 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1504 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1505 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1506 for(i = 0; i < num; i++) {
1507 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1508 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1509 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1510 set_reg_szW(hkey, NameW, PrinterName);
1512 RegCloseKey(hkey);
1517 RegCloseKey(hkeyPrinters);
1520 /* We want to avoid calling AddPrinter on printers as much as
1521 possible, because on cups printers this will (eventually) lead
1522 to a call to cupsGetPPD which takes forever, even with non-cups
1523 printers AddPrinter takes a while. So we'll tag all printers that
1524 were automatically added last time around, if they still exist
1525 we'll leave them be otherwise we'll delete them. */
1526 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1527 if(needed) {
1528 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1529 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1530 for(i = 0; i < num; i++) {
1531 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1532 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1533 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1534 DWORD dw = 1;
1535 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1536 RegCloseKey(hkey);
1538 ClosePrinter(hprn);
1543 HeapFree(GetProcessHeap(), 0, pi);
1547 #ifdef SONAME_LIBCUPS
1548 done = CUPS_LoadPrinters();
1549 #endif
1551 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1552 PRINTCAP_LoadPrinters();
1554 /* Now enumerate the list again and delete any printers that are still tagged */
1555 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1556 if(needed) {
1557 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1558 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1559 for(i = 0; i < num; i++) {
1560 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1561 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1562 BOOL delete_driver = FALSE;
1563 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1564 DWORD dw, type, size = sizeof(dw);
1565 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1566 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1567 DeletePrinter(hprn);
1568 delete_driver = TRUE;
1570 RegCloseKey(hkey);
1572 ClosePrinter(hprn);
1573 if(delete_driver)
1574 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1579 HeapFree(GetProcessHeap(), 0, pi);
1582 return;
1586 /******************************************************************
1587 * get_job
1589 * Get the pointer to the specified job.
1590 * Should hold the printer_handles_cs before calling.
1592 static job_t *get_job(HANDLE hprn, DWORD JobId)
1594 opened_printer_t *printer = get_opened_printer(hprn);
1595 job_t *job;
1597 if(!printer) return NULL;
1598 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1600 if(job->job_id == JobId)
1601 return job;
1603 return NULL;
1606 /***********************************************************
1607 * DEVMODEcpyAtoW
1609 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1611 BOOL Formname;
1612 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1613 DWORD size;
1615 Formname = (dmA->dmSize > off_formname);
1616 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1617 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1618 dmW->dmDeviceName, CCHDEVICENAME);
1619 if(!Formname) {
1620 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1621 dmA->dmSize - CCHDEVICENAME);
1622 } else {
1623 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1624 off_formname - CCHDEVICENAME);
1625 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1626 dmW->dmFormName, CCHFORMNAME);
1627 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1628 (off_formname + CCHFORMNAME));
1630 dmW->dmSize = size;
1631 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1632 dmA->dmDriverExtra);
1633 return dmW;
1636 /***********************************************************
1637 * DEVMODEdupWtoA
1638 * Creates an ansi copy of supplied devmode
1640 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1642 LPDEVMODEA dmA;
1643 DWORD size;
1645 if (!dmW) return NULL;
1646 size = dmW->dmSize - CCHDEVICENAME -
1647 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1649 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1650 if (!dmA) return NULL;
1652 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1653 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1655 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1656 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1657 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1659 else
1661 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1662 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1663 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1664 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1666 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1669 dmA->dmSize = size;
1670 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1671 return dmA;
1674 /******************************************************************
1675 * convert_printerinfo_W_to_A [internal]
1678 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1679 DWORD level, DWORD outlen, DWORD numentries)
1681 DWORD id = 0;
1682 LPSTR ptr;
1683 INT len;
1685 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1687 len = pi_sizeof[level] * numentries;
1688 ptr = (LPSTR) out + len;
1689 outlen -= len;
1691 /* copy the numbers of all PRINTER_INFO_* first */
1692 memcpy(out, pPrintersW, len);
1694 while (id < numentries) {
1695 switch (level) {
1696 case 1:
1698 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1699 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1701 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1702 if (piW->pDescription) {
1703 piA->pDescription = ptr;
1704 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1705 ptr, outlen, NULL, NULL);
1706 ptr += len;
1707 outlen -= len;
1709 if (piW->pName) {
1710 piA->pName = ptr;
1711 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1712 ptr, outlen, NULL, NULL);
1713 ptr += len;
1714 outlen -= len;
1716 if (piW->pComment) {
1717 piA->pComment = ptr;
1718 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1719 ptr, outlen, NULL, NULL);
1720 ptr += len;
1721 outlen -= len;
1723 break;
1726 case 2:
1728 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1729 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1730 LPDEVMODEA dmA;
1732 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1733 if (piW->pServerName) {
1734 piA->pServerName = ptr;
1735 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1736 ptr, outlen, NULL, NULL);
1737 ptr += len;
1738 outlen -= len;
1740 if (piW->pPrinterName) {
1741 piA->pPrinterName = ptr;
1742 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1743 ptr, outlen, NULL, NULL);
1744 ptr += len;
1745 outlen -= len;
1747 if (piW->pShareName) {
1748 piA->pShareName = ptr;
1749 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1750 ptr, outlen, NULL, NULL);
1751 ptr += len;
1752 outlen -= len;
1754 if (piW->pPortName) {
1755 piA->pPortName = ptr;
1756 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1757 ptr, outlen, NULL, NULL);
1758 ptr += len;
1759 outlen -= len;
1761 if (piW->pDriverName) {
1762 piA->pDriverName = ptr;
1763 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1764 ptr, outlen, NULL, NULL);
1765 ptr += len;
1766 outlen -= len;
1768 if (piW->pComment) {
1769 piA->pComment = ptr;
1770 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1771 ptr, outlen, NULL, NULL);
1772 ptr += len;
1773 outlen -= len;
1775 if (piW->pLocation) {
1776 piA->pLocation = ptr;
1777 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1778 ptr, outlen, NULL, NULL);
1779 ptr += len;
1780 outlen -= len;
1783 dmA = DEVMODEdupWtoA(piW->pDevMode);
1784 if (dmA) {
1785 /* align DEVMODEA to a DWORD boundary */
1786 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1787 ptr += len;
1788 outlen -= len;
1790 piA->pDevMode = (LPDEVMODEA) ptr;
1791 len = dmA->dmSize + dmA->dmDriverExtra;
1792 memcpy(ptr, dmA, len);
1793 HeapFree(GetProcessHeap(), 0, dmA);
1795 ptr += len;
1796 outlen -= len;
1799 if (piW->pSepFile) {
1800 piA->pSepFile = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1802 ptr, outlen, NULL, NULL);
1803 ptr += len;
1804 outlen -= len;
1806 if (piW->pPrintProcessor) {
1807 piA->pPrintProcessor = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1809 ptr, outlen, NULL, NULL);
1810 ptr += len;
1811 outlen -= len;
1813 if (piW->pDatatype) {
1814 piA->pDatatype = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1816 ptr, outlen, NULL, NULL);
1817 ptr += len;
1818 outlen -= len;
1820 if (piW->pParameters) {
1821 piA->pParameters = ptr;
1822 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1823 ptr, outlen, NULL, NULL);
1824 ptr += len;
1825 outlen -= len;
1827 if (piW->pSecurityDescriptor) {
1828 piA->pSecurityDescriptor = NULL;
1829 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1831 break;
1834 case 4:
1836 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1837 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1839 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1841 if (piW->pPrinterName) {
1842 piA->pPrinterName = ptr;
1843 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1844 ptr, outlen, NULL, NULL);
1845 ptr += len;
1846 outlen -= len;
1848 if (piW->pServerName) {
1849 piA->pServerName = ptr;
1850 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1851 ptr, outlen, NULL, NULL);
1852 ptr += len;
1853 outlen -= len;
1855 break;
1858 case 5:
1860 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1861 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1863 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1865 if (piW->pPrinterName) {
1866 piA->pPrinterName = ptr;
1867 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1868 ptr, outlen, NULL, NULL);
1869 ptr += len;
1870 outlen -= len;
1872 if (piW->pPortName) {
1873 piA->pPortName = ptr;
1874 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1875 ptr, outlen, NULL, NULL);
1876 ptr += len;
1877 outlen -= len;
1879 break;
1882 default:
1883 FIXME("for level %u\n", level);
1885 pPrintersW += pi_sizeof[level];
1886 out += pi_sizeof[level];
1887 id++;
1891 /***********************************************************
1892 * PRINTER_INFO_2AtoW
1893 * Creates a unicode copy of PRINTER_INFO_2A on heap
1895 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1897 LPPRINTER_INFO_2W piW;
1898 UNICODE_STRING usBuffer;
1900 if(!piA) return NULL;
1901 piW = HeapAlloc(heap, 0, sizeof(*piW));
1902 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1904 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1905 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1906 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1907 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1908 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1909 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1910 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1911 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1912 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1913 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1914 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1915 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1916 return piW;
1919 /***********************************************************
1920 * FREE_PRINTER_INFO_2W
1921 * Free PRINTER_INFO_2W and all strings
1923 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1925 if(!piW) return;
1927 HeapFree(heap,0,piW->pServerName);
1928 HeapFree(heap,0,piW->pPrinterName);
1929 HeapFree(heap,0,piW->pShareName);
1930 HeapFree(heap,0,piW->pPortName);
1931 HeapFree(heap,0,piW->pDriverName);
1932 HeapFree(heap,0,piW->pComment);
1933 HeapFree(heap,0,piW->pLocation);
1934 HeapFree(heap,0,piW->pDevMode);
1935 HeapFree(heap,0,piW->pSepFile);
1936 HeapFree(heap,0,piW->pPrintProcessor);
1937 HeapFree(heap,0,piW->pDatatype);
1938 HeapFree(heap,0,piW->pParameters);
1939 HeapFree(heap,0,piW);
1940 return;
1943 /******************************************************************
1944 * DeviceCapabilities [WINSPOOL.@]
1945 * DeviceCapabilitiesA [WINSPOOL.@]
1948 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1949 LPSTR pOutput, LPDEVMODEA lpdm)
1951 INT ret;
1953 if (!GDI_CallDeviceCapabilities16)
1955 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1956 (LPCSTR)104 );
1957 if (!GDI_CallDeviceCapabilities16) return -1;
1959 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1961 /* If DC_PAPERSIZE map POINT16s to POINTs */
1962 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1963 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1964 POINT *pt = (POINT *)pOutput;
1965 INT i;
1966 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1967 for(i = 0; i < ret; i++, pt++)
1969 pt->x = tmp[i].x;
1970 pt->y = tmp[i].y;
1972 HeapFree( GetProcessHeap(), 0, tmp );
1974 return ret;
1978 /*****************************************************************************
1979 * DeviceCapabilitiesW [WINSPOOL.@]
1981 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1984 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1985 WORD fwCapability, LPWSTR pOutput,
1986 const DEVMODEW *pDevMode)
1988 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1989 LPSTR pDeviceA = strdupWtoA(pDevice);
1990 LPSTR pPortA = strdupWtoA(pPort);
1991 INT ret;
1993 if(pOutput && (fwCapability == DC_BINNAMES ||
1994 fwCapability == DC_FILEDEPENDENCIES ||
1995 fwCapability == DC_PAPERNAMES)) {
1996 /* These need A -> W translation */
1997 INT size = 0, i;
1998 LPSTR pOutputA;
1999 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2000 dmA);
2001 if(ret == -1)
2002 return ret;
2003 switch(fwCapability) {
2004 case DC_BINNAMES:
2005 size = 24;
2006 break;
2007 case DC_PAPERNAMES:
2008 case DC_FILEDEPENDENCIES:
2009 size = 64;
2010 break;
2012 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2013 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2014 dmA);
2015 for(i = 0; i < ret; i++)
2016 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2017 pOutput + (i * size), size);
2018 HeapFree(GetProcessHeap(), 0, pOutputA);
2019 } else {
2020 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2021 (LPSTR)pOutput, dmA);
2023 HeapFree(GetProcessHeap(),0,pPortA);
2024 HeapFree(GetProcessHeap(),0,pDeviceA);
2025 HeapFree(GetProcessHeap(),0,dmA);
2026 return ret;
2029 /******************************************************************
2030 * DocumentPropertiesA [WINSPOOL.@]
2032 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2034 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2035 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2036 LPDEVMODEA pDevModeInput,DWORD fMode )
2038 LPSTR lpName = pDeviceName;
2039 static CHAR port[] = "LPT1:";
2040 LONG ret;
2042 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2043 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2046 if(!pDeviceName) {
2047 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2048 if(!lpNameW) {
2049 ERR("no name from hPrinter?\n");
2050 SetLastError(ERROR_INVALID_HANDLE);
2051 return -1;
2053 lpName = strdupWtoA(lpNameW);
2056 if (!GDI_CallExtDeviceMode16)
2058 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2059 (LPCSTR)102 );
2060 if (!GDI_CallExtDeviceMode16) {
2061 ERR("No CallExtDeviceMode16?\n");
2062 return -1;
2065 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2066 pDevModeInput, NULL, fMode);
2068 if(!pDeviceName)
2069 HeapFree(GetProcessHeap(),0,lpName);
2070 return ret;
2074 /*****************************************************************************
2075 * DocumentPropertiesW (WINSPOOL.@)
2077 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2079 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2080 LPWSTR pDeviceName,
2081 LPDEVMODEW pDevModeOutput,
2082 LPDEVMODEW pDevModeInput, DWORD fMode)
2085 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2086 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2087 LPDEVMODEA pDevModeOutputA = NULL;
2088 LONG ret;
2090 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2091 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2092 fMode);
2093 if(pDevModeOutput) {
2094 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2095 if(ret < 0) return ret;
2096 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2098 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2099 pDevModeInputA, fMode);
2100 if(pDevModeOutput) {
2101 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2102 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2104 if(fMode == 0 && ret > 0)
2105 ret += (CCHDEVICENAME + CCHFORMNAME);
2106 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2107 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2108 return ret;
2111 /******************************************************************
2112 * OpenPrinterA [WINSPOOL.@]
2114 * See OpenPrinterW.
2117 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2118 LPPRINTER_DEFAULTSA pDefault)
2120 UNICODE_STRING lpPrinterNameW;
2121 UNICODE_STRING usBuffer;
2122 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2123 PWSTR pwstrPrinterNameW;
2124 BOOL ret;
2126 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2128 if(pDefault) {
2129 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2130 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2131 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2132 pDefaultW = &DefaultW;
2134 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2135 if(pDefault) {
2136 RtlFreeUnicodeString(&usBuffer);
2137 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2139 RtlFreeUnicodeString(&lpPrinterNameW);
2140 return ret;
2143 /******************************************************************
2144 * OpenPrinterW [WINSPOOL.@]
2146 * Open a Printer / Printserver or a Printer-Object
2148 * PARAMS
2149 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2150 * phPrinter [O] The resulting Handle is stored here
2151 * pDefault [I] PTR to Default Printer Settings or NULL
2153 * RETURNS
2154 * Success: TRUE
2155 * Failure: FALSE
2157 * NOTES
2158 * lpPrinterName is one of:
2159 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2160 *| Printer: "PrinterName"
2161 *| Printer-Object: "PrinterName,Job xxx"
2162 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2163 *| XcvPort: "Servername,XcvPort PortName"
2165 * BUGS
2166 *| Printer-Object not supported
2167 *| pDefaults is ignored
2170 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2173 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2174 if (pDefault) {
2175 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2176 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2179 if(!phPrinter) {
2180 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2181 SetLastError(ERROR_INVALID_PARAMETER);
2182 return FALSE;
2185 /* Get the unique handle of the printer or Printserver */
2186 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2187 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2188 return (*phPrinter != 0);
2191 /******************************************************************
2192 * AddMonitorA [WINSPOOL.@]
2194 * See AddMonitorW.
2197 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2199 LPWSTR nameW = NULL;
2200 INT len;
2201 BOOL res;
2202 LPMONITOR_INFO_2A mi2a;
2203 MONITOR_INFO_2W mi2w;
2205 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2206 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2207 debugstr_a(mi2a ? mi2a->pName : NULL),
2208 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2209 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2211 if (Level != 2) {
2212 SetLastError(ERROR_INVALID_LEVEL);
2213 return FALSE;
2216 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2217 if (mi2a == NULL) {
2218 return FALSE;
2221 if (pName) {
2222 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2223 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2224 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2227 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2228 if (mi2a->pName) {
2229 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2230 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2231 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2233 if (mi2a->pEnvironment) {
2234 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2235 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2236 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2238 if (mi2a->pDLLName) {
2239 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2240 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2241 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2244 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2246 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2247 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2248 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2250 HeapFree(GetProcessHeap(), 0, nameW);
2251 return (res);
2254 /******************************************************************************
2255 * AddMonitorW [WINSPOOL.@]
2257 * Install a Printmonitor
2259 * PARAMS
2260 * pName [I] Servername or NULL (local Computer)
2261 * Level [I] Structure-Level (Must be 2)
2262 * pMonitors [I] PTR to MONITOR_INFO_2
2264 * RETURNS
2265 * Success: TRUE
2266 * Failure: FALSE
2268 * NOTES
2269 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2272 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2274 monitor_t * pm = NULL;
2275 LPMONITOR_INFO_2W mi2w;
2276 HKEY hroot = NULL;
2277 HKEY hentry = NULL;
2278 DWORD disposition;
2279 BOOL res = FALSE;
2281 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2282 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2283 debugstr_w(mi2w ? mi2w->pName : NULL),
2284 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2285 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2287 if (Level != 2) {
2288 SetLastError(ERROR_INVALID_LEVEL);
2289 return FALSE;
2292 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2293 if (mi2w == NULL) {
2294 return FALSE;
2297 if (pName && (pName[0])) {
2298 FIXME("for server %s not implemented\n", debugstr_w(pName));
2299 SetLastError(ERROR_ACCESS_DENIED);
2300 return FALSE;
2304 if (!mi2w->pName || (! mi2w->pName[0])) {
2305 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2306 SetLastError(ERROR_INVALID_PARAMETER);
2307 return FALSE;
2309 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2310 WARN("Environment %s requested (we support only %s)\n",
2311 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2312 SetLastError(ERROR_INVALID_ENVIRONMENT);
2313 return FALSE;
2316 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2317 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2318 SetLastError(ERROR_INVALID_PARAMETER);
2319 return FALSE;
2322 /* Load and initialize the monitor. SetLastError() is called on failure */
2323 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2324 return FALSE;
2326 monitor_unload(pm);
2328 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2329 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2330 return FALSE;
2333 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2334 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2335 &disposition) == ERROR_SUCCESS) {
2337 /* Some installers set options for the port before calling AddMonitor.
2338 We query the "Driver" entry to verify that the monitor is installed,
2339 before we return an error.
2340 When a user installs two print monitors at the same time with the
2341 same name but with a different driver DLL and a task switch comes
2342 between RegQueryValueExW and RegSetValueExW, a race condition
2343 is possible but silently ignored. */
2345 DWORD namesize = 0;
2347 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2348 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2349 &namesize) == ERROR_SUCCESS)) {
2350 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2351 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2352 9x: ERROR_ALREADY_EXISTS (183) */
2353 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2355 else
2357 INT len;
2358 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2359 res = (RegSetValueExW(hentry, DriverW, 0,
2360 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2362 RegCloseKey(hentry);
2365 RegCloseKey(hroot);
2366 return (res);
2369 /******************************************************************
2370 * DeletePrinterDriverA [WINSPOOL.@]
2373 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2375 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2378 /******************************************************************
2379 * DeletePrinterDriverW [WINSPOOL.@]
2382 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2384 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2387 /******************************************************************
2388 * DeleteMonitorA [WINSPOOL.@]
2390 * See DeleteMonitorW.
2393 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2395 LPWSTR nameW = NULL;
2396 LPWSTR EnvironmentW = NULL;
2397 LPWSTR MonitorNameW = NULL;
2398 BOOL res;
2399 INT len;
2401 if (pName) {
2402 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2403 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2404 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2407 if (pEnvironment) {
2408 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2409 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2410 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2412 if (pMonitorName) {
2413 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2414 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2415 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2418 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2420 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2421 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2422 HeapFree(GetProcessHeap(), 0, nameW);
2423 return (res);
2426 /******************************************************************
2427 * DeleteMonitorW [WINSPOOL.@]
2429 * Delete a specific Printmonitor from a Printing-Environment
2431 * PARAMS
2432 * pName [I] Servername or NULL (local Computer)
2433 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2434 * pMonitorName [I] Name of the Monitor, that should be deleted
2436 * RETURNS
2437 * Success: TRUE
2438 * Failure: FALSE
2440 * NOTES
2441 * pEnvironment is ignored in Windows for the local Computer.
2444 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2447 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2448 debugstr_w(pMonitorName));
2450 if ((backend == NULL) && !load_backend()) return FALSE;
2452 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2456 /******************************************************************
2457 * DeletePortA [WINSPOOL.@]
2459 * See DeletePortW.
2462 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2464 LPWSTR nameW = NULL;
2465 LPWSTR portW = NULL;
2466 INT len;
2467 DWORD res;
2469 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2471 /* convert servername to unicode */
2472 if (pName) {
2473 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2474 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2475 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2478 /* convert portname to unicode */
2479 if (pPortName) {
2480 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2481 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2482 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2485 res = DeletePortW(nameW, hWnd, portW);
2486 HeapFree(GetProcessHeap(), 0, nameW);
2487 HeapFree(GetProcessHeap(), 0, portW);
2488 return res;
2491 /******************************************************************
2492 * DeletePortW [WINSPOOL.@]
2494 * Delete a specific Port
2496 * PARAMS
2497 * pName [I] Servername or NULL (local Computer)
2498 * hWnd [I] Handle to parent Window for the Dialog-Box
2499 * pPortName [I] Name of the Port, that should be deleted
2501 * RETURNS
2502 * Success: TRUE
2503 * Failure: FALSE
2506 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2508 monitor_t * pm;
2509 monitor_t * pui;
2510 DWORD res;
2512 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2514 if (pName && pName[0]) {
2515 SetLastError(ERROR_INVALID_PARAMETER);
2516 return FALSE;
2519 if (!pPortName) {
2520 SetLastError(RPC_X_NULL_REF_POINTER);
2521 return FALSE;
2524 /* an empty Portname is Invalid */
2525 if (!pPortName[0]) {
2526 SetLastError(ERROR_NOT_SUPPORTED);
2527 return FALSE;
2530 pm = monitor_load_by_port(pPortName);
2531 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2532 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2533 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2534 TRACE("got %d with %u\n", res, GetLastError());
2536 else
2538 pui = monitor_loadui(pm);
2539 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2540 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2541 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2542 TRACE("got %d with %u\n", res, GetLastError());
2544 else
2546 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2547 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2549 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2550 SetLastError(ERROR_NOT_SUPPORTED);
2551 res = FALSE;
2553 monitor_unload(pui);
2555 monitor_unload(pm);
2557 TRACE("returning %d with %u\n", res, GetLastError());
2558 return res;
2561 /******************************************************************************
2562 * SetPrinterW [WINSPOOL.@]
2564 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2566 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2567 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2568 return FALSE;
2571 /******************************************************************************
2572 * WritePrinter [WINSPOOL.@]
2574 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2576 opened_printer_t *printer;
2577 BOOL ret = FALSE;
2579 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2581 EnterCriticalSection(&printer_handles_cs);
2582 printer = get_opened_printer(hPrinter);
2583 if(!printer)
2585 SetLastError(ERROR_INVALID_HANDLE);
2586 goto end;
2589 if(!printer->doc)
2591 SetLastError(ERROR_SPL_NO_STARTDOC);
2592 goto end;
2595 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2596 end:
2597 LeaveCriticalSection(&printer_handles_cs);
2598 return ret;
2601 /*****************************************************************************
2602 * AddFormA [WINSPOOL.@]
2604 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2606 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2607 return 1;
2610 /*****************************************************************************
2611 * AddFormW [WINSPOOL.@]
2613 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2615 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2616 return 1;
2619 /*****************************************************************************
2620 * AddJobA [WINSPOOL.@]
2622 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2624 BOOL ret;
2625 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2626 DWORD needed;
2628 if(Level != 1) {
2629 SetLastError(ERROR_INVALID_LEVEL);
2630 return FALSE;
2633 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2635 if(ret) {
2636 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2637 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2638 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2639 if(*pcbNeeded > cbBuf) {
2640 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2641 ret = FALSE;
2642 } else {
2643 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2644 addjobA->JobId = addjobW->JobId;
2645 addjobA->Path = (char *)(addjobA + 1);
2646 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2649 return ret;
2652 /*****************************************************************************
2653 * AddJobW [WINSPOOL.@]
2655 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2657 opened_printer_t *printer;
2658 job_t *job;
2659 BOOL ret = FALSE;
2660 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2661 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2662 WCHAR path[MAX_PATH], filename[MAX_PATH];
2663 DWORD len;
2664 ADDJOB_INFO_1W *addjob;
2666 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2668 EnterCriticalSection(&printer_handles_cs);
2670 printer = get_opened_printer(hPrinter);
2672 if(!printer) {
2673 SetLastError(ERROR_INVALID_HANDLE);
2674 goto end;
2677 if(Level != 1) {
2678 SetLastError(ERROR_INVALID_LEVEL);
2679 goto end;
2682 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2683 if(!job)
2684 goto end;
2686 job->job_id = InterlockedIncrement(&next_job_id);
2688 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2689 if(path[len - 1] != '\\')
2690 path[len++] = '\\';
2691 memcpy(path + len, spool_path, sizeof(spool_path));
2692 sprintfW(filename, fmtW, path, job->job_id);
2694 len = strlenW(filename);
2695 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2696 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2697 job->document_title = strdupW(default_doc_title);
2698 list_add_tail(&printer->queue->jobs, &job->entry);
2700 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2701 if(*pcbNeeded <= cbBuf) {
2702 addjob = (ADDJOB_INFO_1W*)pData;
2703 addjob->JobId = job->job_id;
2704 addjob->Path = (WCHAR *)(addjob + 1);
2705 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2706 ret = TRUE;
2707 } else
2708 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2710 end:
2711 LeaveCriticalSection(&printer_handles_cs);
2712 return ret;
2715 /*****************************************************************************
2716 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2718 * Return the PATH for the Print-Processors
2720 * See GetPrintProcessorDirectoryW.
2724 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2725 DWORD level, LPBYTE Info,
2726 DWORD cbBuf, LPDWORD pcbNeeded)
2728 LPWSTR serverW = NULL;
2729 LPWSTR envW = NULL;
2730 BOOL ret;
2731 INT len;
2733 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2734 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2737 if (server) {
2738 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2739 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2740 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2743 if (env) {
2744 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2745 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2746 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2749 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2750 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2752 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2753 cbBuf, pcbNeeded);
2755 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2756 cbBuf, NULL, NULL) > 0;
2759 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2760 HeapFree(GetProcessHeap(), 0, envW);
2761 HeapFree(GetProcessHeap(), 0, serverW);
2762 return ret;
2765 /*****************************************************************************
2766 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2768 * Return the PATH for the Print-Processors
2770 * PARAMS
2771 * server [I] Servername (NT only) or NULL (local Computer)
2772 * env [I] Printing-Environment (see below) or NULL (Default)
2773 * level [I] Structure-Level (must be 1)
2774 * Info [O] PTR to Buffer that receives the Result
2775 * cbBuf [I] Size of Buffer at "Info"
2776 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2777 * required for the Buffer at "Info"
2779 * RETURNS
2780 * Success: TRUE and in pcbNeeded the Bytes used in Info
2781 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2782 * if cbBuf is too small
2784 * Native Values returned in Info on Success:
2785 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2786 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2787 *| win9x(Windows 4.0): "%winsysdir%"
2789 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2791 * BUGS
2792 * Only NULL or "" is supported for server
2795 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2796 DWORD level, LPBYTE Info,
2797 DWORD cbBuf, LPDWORD pcbNeeded)
2799 DWORD needed;
2800 const printenv_t * env_t;
2802 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2803 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2805 if(server != NULL && server[0]) {
2806 FIXME("server not supported: %s\n", debugstr_w(server));
2807 SetLastError(ERROR_INVALID_PARAMETER);
2808 return FALSE;
2811 env_t = validate_envW(env);
2812 if(!env_t) return FALSE; /* environment invalid or unsupported */
2814 if(level != 1) {
2815 WARN("(Level: %d) is ignored in win9x\n", level);
2816 SetLastError(ERROR_INVALID_LEVEL);
2817 return FALSE;
2820 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2821 needed = GetSystemDirectoryW(NULL, 0);
2822 /* add the Size for the Subdirectories */
2823 needed += lstrlenW(spoolprtprocsW);
2824 needed += lstrlenW(env_t->subdir);
2825 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2827 if(pcbNeeded) *pcbNeeded = needed;
2828 TRACE ("required: 0x%x/%d\n", needed, needed);
2829 if (needed > cbBuf) {
2830 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2831 return FALSE;
2833 if(pcbNeeded == NULL) {
2834 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2835 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2836 SetLastError(RPC_X_NULL_REF_POINTER);
2837 return FALSE;
2839 if(Info == NULL) {
2840 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2841 SetLastError(RPC_X_NULL_REF_POINTER);
2842 return FALSE;
2845 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2846 /* add the Subdirectories */
2847 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2848 lstrcatW((LPWSTR) Info, env_t->subdir);
2849 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2850 return TRUE;
2853 /*****************************************************************************
2854 * WINSPOOL_OpenDriverReg [internal]
2856 * opens the registry for the printer drivers depending on the given input
2857 * variable pEnvironment
2859 * RETURNS:
2860 * the opened hkey on success
2861 * NULL on error
2863 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2865 HKEY retval = NULL;
2866 LPWSTR buffer;
2867 const printenv_t * env;
2869 TRACE("(%s, %d)\n",
2870 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2872 if (!pEnvironment || unicode) {
2873 /* pEnvironment was NULL or an Unicode-String: use it direct */
2874 env = validate_envW(pEnvironment);
2876 else
2878 /* pEnvironment was an ANSI-String: convert to unicode first */
2879 LPWSTR buffer;
2880 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2881 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2882 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2883 env = validate_envW(buffer);
2884 HeapFree(GetProcessHeap(), 0, buffer);
2886 if (!env) return NULL;
2888 buffer = HeapAlloc( GetProcessHeap(), 0,
2889 (strlenW(DriversW) + strlenW(env->envname) +
2890 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2891 if(buffer) {
2892 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2893 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2894 HeapFree(GetProcessHeap(), 0, buffer);
2896 return retval;
2899 /*****************************************************************************
2900 * AddPrinterW [WINSPOOL.@]
2902 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2904 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2905 LPDEVMODEA dmA;
2906 LPDEVMODEW dmW;
2907 HANDLE retval;
2908 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2909 LONG size;
2910 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2911 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2912 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2913 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2914 statusW[] = {'S','t','a','t','u','s',0},
2915 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2917 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2919 if(pName != NULL) {
2920 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2921 SetLastError(ERROR_INVALID_PARAMETER);
2922 return 0;
2924 if(Level != 2) {
2925 ERR("Level = %d, unsupported!\n", Level);
2926 SetLastError(ERROR_INVALID_LEVEL);
2927 return 0;
2929 if(!pPrinter) {
2930 SetLastError(ERROR_INVALID_PARAMETER);
2931 return 0;
2933 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2934 ERROR_SUCCESS) {
2935 ERR("Can't create Printers key\n");
2936 return 0;
2938 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2939 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2940 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2941 RegCloseKey(hkeyPrinter);
2942 RegCloseKey(hkeyPrinters);
2943 return 0;
2945 RegCloseKey(hkeyPrinter);
2947 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2948 if(!hkeyDrivers) {
2949 ERR("Can't create Drivers key\n");
2950 RegCloseKey(hkeyPrinters);
2951 return 0;
2953 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2954 ERROR_SUCCESS) {
2955 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2956 RegCloseKey(hkeyPrinters);
2957 RegCloseKey(hkeyDrivers);
2958 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2959 return 0;
2961 RegCloseKey(hkeyDriver);
2962 RegCloseKey(hkeyDrivers);
2964 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2965 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2966 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2967 RegCloseKey(hkeyPrinters);
2968 return 0;
2971 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2972 ERROR_SUCCESS) {
2973 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2974 SetLastError(ERROR_INVALID_PRINTER_NAME);
2975 RegCloseKey(hkeyPrinters);
2976 return 0;
2978 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2979 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2980 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2982 /* See if we can load the driver. We may need the devmode structure anyway
2984 * FIXME:
2985 * Note that DocumentPropertiesW will briefly try to open the printer we
2986 * just create to find a DEVMODEA struct (it will use the WINEPS default
2987 * one in case it is not there, so we are ok).
2989 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2991 if(size < 0) {
2992 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2993 size = sizeof(DEVMODEW);
2995 if(pi->pDevMode)
2996 dmW = pi->pDevMode;
2997 else
2999 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3000 dmW->dmSize = size;
3001 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
3003 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3004 HeapFree(GetProcessHeap(),0,dmW);
3005 dmW=NULL;
3007 else
3009 /* set devmode to printer name */
3010 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
3014 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3015 and we support these drivers. NT writes DEVMODEW so somehow
3016 we'll need to distinguish between these when we support NT
3017 drivers */
3018 if (dmW)
3020 dmA = DEVMODEdupWtoA(dmW);
3021 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
3022 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3023 HeapFree(GetProcessHeap(), 0, dmA);
3024 if(!pi->pDevMode)
3025 HeapFree(GetProcessHeap(), 0, dmW);
3027 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3028 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3029 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3030 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3032 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3033 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3034 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3035 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3036 (LPBYTE)&pi->Priority, sizeof(DWORD));
3037 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3038 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3039 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3040 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3041 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3042 (LPBYTE)&pi->Status, sizeof(DWORD));
3043 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3044 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
3046 RegCloseKey(hkeyPrinter);
3047 RegCloseKey(hkeyPrinters);
3048 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3049 ERR("OpenPrinter failing\n");
3050 return 0;
3052 return retval;
3055 /*****************************************************************************
3056 * AddPrinterA [WINSPOOL.@]
3058 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3060 UNICODE_STRING pNameW;
3061 PWSTR pwstrNameW;
3062 PRINTER_INFO_2W *piW;
3063 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3064 HANDLE ret;
3066 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
3067 if(Level != 2) {
3068 ERR("Level = %d, unsupported!\n", Level);
3069 SetLastError(ERROR_INVALID_LEVEL);
3070 return 0;
3072 pwstrNameW = asciitounicode(&pNameW,pName);
3073 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3075 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3077 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3078 RtlFreeUnicodeString(&pNameW);
3079 return ret;
3083 /*****************************************************************************
3084 * ClosePrinter [WINSPOOL.@]
3086 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3088 UINT_PTR i = (UINT_PTR)hPrinter;
3089 opened_printer_t *printer = NULL;
3090 BOOL ret = FALSE;
3092 TRACE("(%p)\n", hPrinter);
3094 EnterCriticalSection(&printer_handles_cs);
3096 if ((i > 0) && (i <= nb_printer_handles))
3097 printer = printer_handles[i - 1];
3100 if(printer)
3102 struct list *cursor, *cursor2;
3104 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3105 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3106 printer->hXcv, debugstr_w(printer->name), printer->doc );
3108 if(printer->doc)
3109 EndDocPrinter(hPrinter);
3111 if(InterlockedDecrement(&printer->queue->ref) == 0)
3113 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3115 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3116 ScheduleJob(hPrinter, job->job_id);
3118 HeapFree(GetProcessHeap(), 0, printer->queue);
3120 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3121 monitor_unload(printer->pm);
3122 HeapFree(GetProcessHeap(), 0, printer->printername);
3123 HeapFree(GetProcessHeap(), 0, printer->name);
3124 HeapFree(GetProcessHeap(), 0, printer);
3125 printer_handles[i - 1] = NULL;
3126 ret = TRUE;
3128 LeaveCriticalSection(&printer_handles_cs);
3129 return ret;
3132 /*****************************************************************************
3133 * DeleteFormA [WINSPOOL.@]
3135 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3137 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3138 return 1;
3141 /*****************************************************************************
3142 * DeleteFormW [WINSPOOL.@]
3144 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3146 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3147 return 1;
3150 /*****************************************************************************
3151 * DeletePrinter [WINSPOOL.@]
3153 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3155 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3156 HKEY hkeyPrinters, hkey;
3158 if(!lpNameW) {
3159 SetLastError(ERROR_INVALID_HANDLE);
3160 return FALSE;
3162 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3163 RegDeleteTreeW(hkeyPrinters, lpNameW);
3164 RegCloseKey(hkeyPrinters);
3166 WriteProfileStringW(devicesW, lpNameW, NULL);
3167 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3169 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3170 RegDeleteValueW(hkey, lpNameW);
3171 RegCloseKey(hkey);
3174 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3175 RegDeleteValueW(hkey, lpNameW);
3176 RegCloseKey(hkey);
3178 return TRUE;
3181 /*****************************************************************************
3182 * SetPrinterA [WINSPOOL.@]
3184 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3185 DWORD Command)
3187 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3188 return FALSE;
3191 /*****************************************************************************
3192 * SetJobA [WINSPOOL.@]
3194 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3195 LPBYTE pJob, DWORD Command)
3197 BOOL ret;
3198 LPBYTE JobW;
3199 UNICODE_STRING usBuffer;
3201 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3203 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3204 are all ignored by SetJob, so we don't bother copying them */
3205 switch(Level)
3207 case 0:
3208 JobW = NULL;
3209 break;
3210 case 1:
3212 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3213 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3215 JobW = (LPBYTE)info1W;
3216 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3217 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3218 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3219 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3220 info1W->Status = info1A->Status;
3221 info1W->Priority = info1A->Priority;
3222 info1W->Position = info1A->Position;
3223 info1W->PagesPrinted = info1A->PagesPrinted;
3224 break;
3226 case 2:
3228 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3229 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3231 JobW = (LPBYTE)info2W;
3232 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3233 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3234 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3235 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3236 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3237 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3238 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3239 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3240 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3241 info2W->Status = info2A->Status;
3242 info2W->Priority = info2A->Priority;
3243 info2W->Position = info2A->Position;
3244 info2W->StartTime = info2A->StartTime;
3245 info2W->UntilTime = info2A->UntilTime;
3246 info2W->PagesPrinted = info2A->PagesPrinted;
3247 break;
3249 case 3:
3250 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3251 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3252 break;
3253 default:
3254 SetLastError(ERROR_INVALID_LEVEL);
3255 return FALSE;
3258 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3260 switch(Level)
3262 case 1:
3264 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3265 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3266 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3267 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3268 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3269 break;
3271 case 2:
3273 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3274 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3275 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3276 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3277 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3278 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3279 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3280 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3281 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3282 break;
3285 HeapFree(GetProcessHeap(), 0, JobW);
3287 return ret;
3290 /*****************************************************************************
3291 * SetJobW [WINSPOOL.@]
3293 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3294 LPBYTE pJob, DWORD Command)
3296 BOOL ret = FALSE;
3297 job_t *job;
3299 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3300 FIXME("Ignoring everything other than document title\n");
3302 EnterCriticalSection(&printer_handles_cs);
3303 job = get_job(hPrinter, JobId);
3304 if(!job)
3305 goto end;
3307 switch(Level)
3309 case 0:
3310 break;
3311 case 1:
3313 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3314 HeapFree(GetProcessHeap(), 0, job->document_title);
3315 job->document_title = strdupW(info1->pDocument);
3316 break;
3318 case 2:
3320 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3321 HeapFree(GetProcessHeap(), 0, job->document_title);
3322 job->document_title = strdupW(info2->pDocument);
3323 break;
3325 case 3:
3326 break;
3327 default:
3328 SetLastError(ERROR_INVALID_LEVEL);
3329 goto end;
3331 ret = TRUE;
3332 end:
3333 LeaveCriticalSection(&printer_handles_cs);
3334 return ret;
3337 /*****************************************************************************
3338 * EndDocPrinter [WINSPOOL.@]
3340 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3342 opened_printer_t *printer;
3343 BOOL ret = FALSE;
3344 TRACE("(%p)\n", hPrinter);
3346 EnterCriticalSection(&printer_handles_cs);
3348 printer = get_opened_printer(hPrinter);
3349 if(!printer)
3351 SetLastError(ERROR_INVALID_HANDLE);
3352 goto end;
3355 if(!printer->doc)
3357 SetLastError(ERROR_SPL_NO_STARTDOC);
3358 goto end;
3361 CloseHandle(printer->doc->hf);
3362 ScheduleJob(hPrinter, printer->doc->job_id);
3363 HeapFree(GetProcessHeap(), 0, printer->doc);
3364 printer->doc = NULL;
3365 ret = TRUE;
3366 end:
3367 LeaveCriticalSection(&printer_handles_cs);
3368 return ret;
3371 /*****************************************************************************
3372 * EndPagePrinter [WINSPOOL.@]
3374 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3376 FIXME("(%p): stub\n", hPrinter);
3377 return TRUE;
3380 /*****************************************************************************
3381 * StartDocPrinterA [WINSPOOL.@]
3383 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3385 UNICODE_STRING usBuffer;
3386 DOC_INFO_2W doc2W;
3387 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3388 DWORD ret;
3390 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3391 or one (DOC_INFO_3) extra DWORDs */
3393 switch(Level) {
3394 case 2:
3395 doc2W.JobId = doc2->JobId;
3396 /* fall through */
3397 case 3:
3398 doc2W.dwMode = doc2->dwMode;
3399 /* fall through */
3400 case 1:
3401 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3402 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3403 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3404 break;
3406 default:
3407 SetLastError(ERROR_INVALID_LEVEL);
3408 return FALSE;
3411 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3413 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3414 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3415 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3417 return ret;
3420 /*****************************************************************************
3421 * StartDocPrinterW [WINSPOOL.@]
3423 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3425 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3426 opened_printer_t *printer;
3427 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3428 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3429 JOB_INFO_1W job_info;
3430 DWORD needed, ret = 0;
3431 HANDLE hf;
3432 WCHAR *filename;
3434 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3435 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3436 debugstr_w(doc->pDatatype));
3438 if(Level < 1 || Level > 3)
3440 SetLastError(ERROR_INVALID_LEVEL);
3441 return 0;
3444 EnterCriticalSection(&printer_handles_cs);
3445 printer = get_opened_printer(hPrinter);
3446 if(!printer)
3448 SetLastError(ERROR_INVALID_HANDLE);
3449 goto end;
3452 if(printer->doc)
3454 SetLastError(ERROR_INVALID_PRINTER_STATE);
3455 goto end;
3458 /* Even if we're printing to a file we still add a print job, we'll
3459 just ignore the spool file name */
3461 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3463 ERR("AddJob failed gle %u\n", GetLastError());
3464 goto end;
3467 if(doc->pOutputFile)
3468 filename = doc->pOutputFile;
3469 else
3470 filename = addjob->Path;
3472 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3473 if(hf == INVALID_HANDLE_VALUE)
3474 goto end;
3476 memset(&job_info, 0, sizeof(job_info));
3477 job_info.pDocument = doc->pDocName;
3478 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3480 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3481 printer->doc->hf = hf;
3482 ret = printer->doc->job_id = addjob->JobId;
3483 end:
3484 LeaveCriticalSection(&printer_handles_cs);
3486 return ret;
3489 /*****************************************************************************
3490 * StartPagePrinter [WINSPOOL.@]
3492 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3494 FIXME("(%p): stub\n", hPrinter);
3495 return TRUE;
3498 /*****************************************************************************
3499 * GetFormA [WINSPOOL.@]
3501 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3502 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3504 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3505 Level,pForm,cbBuf,pcbNeeded);
3506 return FALSE;
3509 /*****************************************************************************
3510 * GetFormW [WINSPOOL.@]
3512 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3513 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3515 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3516 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3517 return FALSE;
3520 /*****************************************************************************
3521 * SetFormA [WINSPOOL.@]
3523 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3524 LPBYTE pForm)
3526 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3527 return FALSE;
3530 /*****************************************************************************
3531 * SetFormW [WINSPOOL.@]
3533 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3534 LPBYTE pForm)
3536 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3537 return FALSE;
3540 /*****************************************************************************
3541 * ReadPrinter [WINSPOOL.@]
3543 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3544 LPDWORD pNoBytesRead)
3546 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3547 return FALSE;
3550 /*****************************************************************************
3551 * ResetPrinterA [WINSPOOL.@]
3553 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3555 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3556 return FALSE;
3559 /*****************************************************************************
3560 * ResetPrinterW [WINSPOOL.@]
3562 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3564 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3565 return FALSE;
3568 /*****************************************************************************
3569 * WINSPOOL_GetDWORDFromReg
3571 * Return DWORD associated with ValueName from hkey.
3573 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3575 DWORD sz = sizeof(DWORD), type, value = 0;
3576 LONG ret;
3578 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3580 if(ret != ERROR_SUCCESS) {
3581 WARN("Got ret = %d on name %s\n", ret, ValueName);
3582 return 0;
3584 if(type != REG_DWORD) {
3585 ERR("Got type %d\n", type);
3586 return 0;
3588 return value;
3592 /*****************************************************************************
3593 * get_filename_from_reg [internal]
3595 * Get ValueName from hkey storing result in out
3596 * when the Value in the registry has only a filename, use driverdir as prefix
3597 * outlen is space left in out
3598 * String is stored either as unicode or ascii
3602 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3603 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3605 WCHAR filename[MAX_PATH];
3606 DWORD size;
3607 DWORD type;
3608 LONG ret;
3609 LPWSTR buffer = filename;
3610 LPWSTR ptr;
3612 *needed = 0;
3613 size = sizeof(filename);
3614 buffer[0] = '\0';
3615 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3616 if (ret == ERROR_MORE_DATA) {
3617 TRACE("need dynamic buffer: %u\n", size);
3618 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3619 if (!buffer) {
3620 /* No Memory is bad */
3621 return FALSE;
3623 buffer[0] = '\0';
3624 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3627 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3628 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3629 return FALSE;
3632 ptr = buffer;
3633 while (ptr) {
3634 /* do we have a full path ? */
3635 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3636 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3638 if (!ret) {
3639 /* we must build the full Path */
3640 *needed += dirlen;
3641 if ((out) && (outlen > dirlen)) {
3642 if (unicode) {
3643 lstrcpyW((LPWSTR)out, driverdir);
3645 else
3647 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3649 out += dirlen;
3650 outlen -= dirlen;
3652 else
3653 out = NULL;
3656 /* write the filename */
3657 if (unicode) {
3658 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3659 if ((out) && (outlen >= size)) {
3660 lstrcpyW((LPWSTR)out, ptr);
3661 out += size;
3662 outlen -= size;
3664 else
3665 out = NULL;
3667 else
3669 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3670 if ((out) && (outlen >= size)) {
3671 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3672 out += size;
3673 outlen -= size;
3675 else
3676 out = NULL;
3678 *needed += size;
3679 ptr += lstrlenW(ptr)+1;
3680 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3683 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3685 /* write the multisz-termination */
3686 if (type == REG_MULTI_SZ) {
3687 size = (unicode) ? sizeof(WCHAR) : 1;
3689 *needed += size;
3690 if (out && (outlen >= size)) {
3691 memset (out, 0, size);
3694 return TRUE;
3697 /*****************************************************************************
3698 * WINSPOOL_GetStringFromReg
3700 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3701 * String is stored either as unicode or ascii.
3702 * Bit of a hack here to get the ValueName if we want ascii.
3704 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3705 DWORD buflen, DWORD *needed,
3706 BOOL unicode)
3708 DWORD sz = buflen, type;
3709 LONG ret;
3711 if(unicode)
3712 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3713 else {
3714 LPSTR ValueNameA = strdupWtoA(ValueName);
3715 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3716 HeapFree(GetProcessHeap(),0,ValueNameA);
3718 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3719 WARN("Got ret = %d\n", ret);
3720 *needed = 0;
3721 return FALSE;
3723 /* add space for terminating '\0' */
3724 sz += unicode ? sizeof(WCHAR) : 1;
3725 *needed = sz;
3727 if (ptr)
3728 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3730 return TRUE;
3733 /*****************************************************************************
3734 * WINSPOOL_GetDefaultDevMode
3736 * Get a default DevMode values for wineps.
3737 * FIXME - use ppd.
3740 static void WINSPOOL_GetDefaultDevMode(
3741 LPBYTE ptr,
3742 DWORD buflen, DWORD *needed,
3743 BOOL unicode)
3745 DEVMODEA dm;
3746 static const char szwps[] = "wineps.drv";
3748 /* fill default DEVMODE - should be read from ppd... */
3749 ZeroMemory( &dm, sizeof(dm) );
3750 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3751 dm.dmSpecVersion = DM_SPECVERSION;
3752 dm.dmDriverVersion = 1;
3753 dm.dmSize = sizeof(DEVMODEA);
3754 dm.dmDriverExtra = 0;
3755 dm.dmFields =
3756 DM_ORIENTATION | DM_PAPERSIZE |
3757 DM_PAPERLENGTH | DM_PAPERWIDTH |
3758 DM_SCALE |
3759 DM_COPIES |
3760 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3761 DM_YRESOLUTION | DM_TTOPTION;
3763 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3764 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3765 dm.u1.s1.dmPaperLength = 2970;
3766 dm.u1.s1.dmPaperWidth = 2100;
3768 dm.u1.s1.dmScale = 100;
3769 dm.u1.s1.dmCopies = 1;
3770 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3771 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3772 /* dm.dmColor */
3773 /* dm.dmDuplex */
3774 dm.dmYResolution = 300; /* 300dpi */
3775 dm.dmTTOption = DMTT_BITMAP;
3776 /* dm.dmCollate */
3777 /* dm.dmFormName */
3778 /* dm.dmLogPixels */
3779 /* dm.dmBitsPerPel */
3780 /* dm.dmPelsWidth */
3781 /* dm.dmPelsHeight */
3782 /* dm.u2.dmDisplayFlags */
3783 /* dm.dmDisplayFrequency */
3784 /* dm.dmICMMethod */
3785 /* dm.dmICMIntent */
3786 /* dm.dmMediaType */
3787 /* dm.dmDitherType */
3788 /* dm.dmReserved1 */
3789 /* dm.dmReserved2 */
3790 /* dm.dmPanningWidth */
3791 /* dm.dmPanningHeight */
3793 if(unicode) {
3794 if(buflen >= sizeof(DEVMODEW)) {
3795 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3796 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3797 HeapFree(GetProcessHeap(),0,pdmW);
3799 *needed = sizeof(DEVMODEW);
3801 else
3803 if(buflen >= sizeof(DEVMODEA)) {
3804 memcpy(ptr, &dm, sizeof(DEVMODEA));
3806 *needed = sizeof(DEVMODEA);
3810 /*****************************************************************************
3811 * WINSPOOL_GetDevModeFromReg
3813 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3814 * DevMode is stored either as unicode or ascii.
3816 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3817 LPBYTE ptr,
3818 DWORD buflen, DWORD *needed,
3819 BOOL unicode)
3821 DWORD sz = buflen, type;
3822 LONG ret;
3824 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3825 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3826 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3827 if (sz < sizeof(DEVMODEA))
3829 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3830 return FALSE;
3832 /* ensures that dmSize is not erratically bogus if registry is invalid */
3833 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3834 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3835 if(unicode) {
3836 sz += (CCHDEVICENAME + CCHFORMNAME);
3837 if(buflen >= sz) {
3838 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3839 memcpy(ptr, dmW, sz);
3840 HeapFree(GetProcessHeap(),0,dmW);
3843 *needed = sz;
3844 return TRUE;
3847 /*********************************************************************
3848 * WINSPOOL_GetPrinter_1
3850 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3851 * The strings are either stored as unicode or ascii.
3853 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3854 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3855 BOOL unicode)
3857 DWORD size, left = cbBuf;
3858 BOOL space = (cbBuf > 0);
3859 LPBYTE ptr = buf;
3861 *pcbNeeded = 0;
3863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3864 unicode)) {
3865 if(space && size <= left) {
3866 pi1->pName = (LPWSTR)ptr;
3867 ptr += size;
3868 left -= size;
3869 } else
3870 space = FALSE;
3871 *pcbNeeded += size;
3874 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3875 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3876 unicode)) {
3877 if(space && size <= left) {
3878 pi1->pDescription = (LPWSTR)ptr;
3879 ptr += size;
3880 left -= size;
3881 } else
3882 space = FALSE;
3883 *pcbNeeded += size;
3886 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3887 unicode)) {
3888 if(space && size <= left) {
3889 pi1->pComment = (LPWSTR)ptr;
3890 ptr += size;
3891 left -= size;
3892 } else
3893 space = FALSE;
3894 *pcbNeeded += size;
3897 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3899 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3900 memset(pi1, 0, sizeof(*pi1));
3902 return space;
3904 /*********************************************************************
3905 * WINSPOOL_GetPrinter_2
3907 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3908 * The strings are either stored as unicode or ascii.
3910 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3911 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3912 BOOL unicode)
3914 DWORD size, left = cbBuf;
3915 BOOL space = (cbBuf > 0);
3916 LPBYTE ptr = buf;
3918 *pcbNeeded = 0;
3920 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3921 unicode)) {
3922 if(space && size <= left) {
3923 pi2->pPrinterName = (LPWSTR)ptr;
3924 ptr += size;
3925 left -= size;
3926 } else
3927 space = FALSE;
3928 *pcbNeeded += size;
3930 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3931 unicode)) {
3932 if(space && size <= left) {
3933 pi2->pShareName = (LPWSTR)ptr;
3934 ptr += size;
3935 left -= size;
3936 } else
3937 space = FALSE;
3938 *pcbNeeded += size;
3940 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3941 unicode)) {
3942 if(space && size <= left) {
3943 pi2->pPortName = (LPWSTR)ptr;
3944 ptr += size;
3945 left -= size;
3946 } else
3947 space = FALSE;
3948 *pcbNeeded += size;
3950 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3951 &size, unicode)) {
3952 if(space && size <= left) {
3953 pi2->pDriverName = (LPWSTR)ptr;
3954 ptr += size;
3955 left -= size;
3956 } else
3957 space = FALSE;
3958 *pcbNeeded += size;
3960 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3961 unicode)) {
3962 if(space && size <= left) {
3963 pi2->pComment = (LPWSTR)ptr;
3964 ptr += size;
3965 left -= size;
3966 } else
3967 space = FALSE;
3968 *pcbNeeded += size;
3970 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3971 unicode)) {
3972 if(space && size <= left) {
3973 pi2->pLocation = (LPWSTR)ptr;
3974 ptr += size;
3975 left -= size;
3976 } else
3977 space = FALSE;
3978 *pcbNeeded += size;
3980 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3981 &size, unicode)) {
3982 if(space && size <= left) {
3983 pi2->pDevMode = (LPDEVMODEW)ptr;
3984 ptr += size;
3985 left -= size;
3986 } else
3987 space = FALSE;
3988 *pcbNeeded += size;
3990 else
3992 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3993 if(space && size <= left) {
3994 pi2->pDevMode = (LPDEVMODEW)ptr;
3995 ptr += size;
3996 left -= size;
3997 } else
3998 space = FALSE;
3999 *pcbNeeded += size;
4001 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
4002 &size, unicode)) {
4003 if(space && size <= left) {
4004 pi2->pSepFile = (LPWSTR)ptr;
4005 ptr += size;
4006 left -= size;
4007 } else
4008 space = FALSE;
4009 *pcbNeeded += size;
4011 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
4012 &size, unicode)) {
4013 if(space && size <= left) {
4014 pi2->pPrintProcessor = (LPWSTR)ptr;
4015 ptr += size;
4016 left -= size;
4017 } else
4018 space = FALSE;
4019 *pcbNeeded += size;
4021 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
4022 &size, unicode)) {
4023 if(space && size <= left) {
4024 pi2->pDatatype = (LPWSTR)ptr;
4025 ptr += size;
4026 left -= size;
4027 } else
4028 space = FALSE;
4029 *pcbNeeded += size;
4031 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
4032 &size, unicode)) {
4033 if(space && size <= left) {
4034 pi2->pParameters = (LPWSTR)ptr;
4035 ptr += size;
4036 left -= size;
4037 } else
4038 space = FALSE;
4039 *pcbNeeded += size;
4041 if(pi2) {
4042 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4043 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
4044 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4045 "Default Priority");
4046 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
4047 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
4050 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4051 memset(pi2, 0, sizeof(*pi2));
4053 return space;
4056 /*********************************************************************
4057 * WINSPOOL_GetPrinter_4
4059 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4061 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4062 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4063 BOOL unicode)
4065 DWORD size, left = cbBuf;
4066 BOOL space = (cbBuf > 0);
4067 LPBYTE ptr = buf;
4069 *pcbNeeded = 0;
4071 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4072 unicode)) {
4073 if(space && size <= left) {
4074 pi4->pPrinterName = (LPWSTR)ptr;
4075 ptr += size;
4076 left -= size;
4077 } else
4078 space = FALSE;
4079 *pcbNeeded += size;
4081 if(pi4) {
4082 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4085 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4086 memset(pi4, 0, sizeof(*pi4));
4088 return space;
4091 /*********************************************************************
4092 * WINSPOOL_GetPrinter_5
4094 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4096 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4097 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4098 BOOL unicode)
4100 DWORD size, left = cbBuf;
4101 BOOL space = (cbBuf > 0);
4102 LPBYTE ptr = buf;
4104 *pcbNeeded = 0;
4106 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4107 unicode)) {
4108 if(space && size <= left) {
4109 pi5->pPrinterName = (LPWSTR)ptr;
4110 ptr += size;
4111 left -= size;
4112 } else
4113 space = FALSE;
4114 *pcbNeeded += size;
4116 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4117 unicode)) {
4118 if(space && size <= left) {
4119 pi5->pPortName = (LPWSTR)ptr;
4120 ptr += size;
4121 left -= size;
4122 } else
4123 space = FALSE;
4124 *pcbNeeded += size;
4126 if(pi5) {
4127 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4128 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4129 "dnsTimeout");
4130 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4131 "txTimeout");
4134 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4135 memset(pi5, 0, sizeof(*pi5));
4137 return space;
4140 /*********************************************************************
4141 * WINSPOOL_GetPrinter_7
4143 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4145 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4146 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4148 DWORD size, left = cbBuf;
4149 BOOL space = (cbBuf > 0);
4150 LPBYTE ptr = buf;
4152 *pcbNeeded = 0;
4154 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4156 if (space && size <= left) {
4157 pi7->pszObjectGUID = (LPWSTR)ptr;
4158 ptr += size;
4159 left -= size;
4160 } else
4161 space = FALSE;
4162 *pcbNeeded += size;
4164 if (pi7) {
4165 /* We do not have a Directory Service */
4166 pi7->dwAction = DSPRINT_UNPUBLISH;
4169 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4170 memset(pi7, 0, sizeof(*pi7));
4172 return space;
4175 /*********************************************************************
4176 * WINSPOOL_GetPrinter_9
4178 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4179 * The strings are either stored as unicode or ascii.
4181 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4182 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4184 DWORD size;
4185 BOOL space = (cbBuf > 0);
4187 *pcbNeeded = 0;
4189 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4190 if(space && size <= cbBuf) {
4191 pi9->pDevMode = (LPDEVMODEW)buf;
4192 } else
4193 space = FALSE;
4194 *pcbNeeded += size;
4196 else
4198 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4199 if(space && size <= cbBuf) {
4200 pi9->pDevMode = (LPDEVMODEW)buf;
4201 } else
4202 space = FALSE;
4203 *pcbNeeded += size;
4206 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4207 memset(pi9, 0, sizeof(*pi9));
4209 return space;
4212 /*****************************************************************************
4213 * WINSPOOL_GetPrinter
4215 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4216 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4217 * just a collection of pointers to strings.
4219 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4220 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4222 LPCWSTR name;
4223 DWORD size, needed = 0;
4224 LPBYTE ptr = NULL;
4225 HKEY hkeyPrinter, hkeyPrinters;
4226 BOOL ret;
4228 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4230 if (!(name = get_opened_printer_name(hPrinter))) {
4231 SetLastError(ERROR_INVALID_HANDLE);
4232 return FALSE;
4235 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4236 ERROR_SUCCESS) {
4237 ERR("Can't create Printers key\n");
4238 return FALSE;
4240 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4242 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4243 RegCloseKey(hkeyPrinters);
4244 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4245 return FALSE;
4248 switch(Level) {
4249 case 2:
4251 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4253 size = sizeof(PRINTER_INFO_2W);
4254 if(size <= cbBuf) {
4255 ptr = pPrinter + size;
4256 cbBuf -= size;
4257 memset(pPrinter, 0, size);
4258 } else {
4259 pi2 = NULL;
4260 cbBuf = 0;
4262 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4263 unicode);
4264 needed += size;
4265 break;
4268 case 4:
4270 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4272 size = sizeof(PRINTER_INFO_4W);
4273 if(size <= cbBuf) {
4274 ptr = pPrinter + size;
4275 cbBuf -= size;
4276 memset(pPrinter, 0, size);
4277 } else {
4278 pi4 = NULL;
4279 cbBuf = 0;
4281 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4282 unicode);
4283 needed += size;
4284 break;
4288 case 5:
4290 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4292 size = sizeof(PRINTER_INFO_5W);
4293 if(size <= cbBuf) {
4294 ptr = pPrinter + size;
4295 cbBuf -= size;
4296 memset(pPrinter, 0, size);
4297 } else {
4298 pi5 = NULL;
4299 cbBuf = 0;
4302 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4303 unicode);
4304 needed += size;
4305 break;
4309 case 6:
4311 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4313 size = sizeof(PRINTER_INFO_6);
4314 if (size <= cbBuf) {
4315 /* FIXME: We do not update the status yet */
4316 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4317 ret = TRUE;
4318 } else {
4319 ret = FALSE;
4322 needed += size;
4323 break;
4326 case 7:
4328 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4330 size = sizeof(PRINTER_INFO_7W);
4331 if (size <= cbBuf) {
4332 ptr = pPrinter + size;
4333 cbBuf -= size;
4334 memset(pPrinter, 0, size);
4335 } else {
4336 pi7 = NULL;
4337 cbBuf = 0;
4340 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4341 needed += size;
4342 break;
4346 case 9:
4348 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4350 size = sizeof(PRINTER_INFO_9W);
4351 if(size <= cbBuf) {
4352 ptr = pPrinter + size;
4353 cbBuf -= size;
4354 memset(pPrinter, 0, size);
4355 } else {
4356 pi9 = NULL;
4357 cbBuf = 0;
4360 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4361 needed += size;
4362 break;
4366 default:
4367 FIXME("Unimplemented level %d\n", Level);
4368 SetLastError(ERROR_INVALID_LEVEL);
4369 RegCloseKey(hkeyPrinters);
4370 RegCloseKey(hkeyPrinter);
4371 return FALSE;
4374 RegCloseKey(hkeyPrinter);
4375 RegCloseKey(hkeyPrinters);
4377 TRACE("returning %d needed = %d\n", ret, needed);
4378 if(pcbNeeded) *pcbNeeded = needed;
4379 if(!ret)
4380 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4381 return ret;
4384 /*****************************************************************************
4385 * GetPrinterW [WINSPOOL.@]
4387 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4388 DWORD cbBuf, LPDWORD pcbNeeded)
4390 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4391 TRUE);
4394 /*****************************************************************************
4395 * GetPrinterA [WINSPOOL.@]
4397 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4398 DWORD cbBuf, LPDWORD pcbNeeded)
4400 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4401 FALSE);
4404 /*****************************************************************************
4405 * WINSPOOL_EnumPrinters
4407 * Implementation of EnumPrintersA|W
4409 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4410 DWORD dwLevel, LPBYTE lpbPrinters,
4411 DWORD cbBuf, LPDWORD lpdwNeeded,
4412 LPDWORD lpdwReturned, BOOL unicode)
4415 HKEY hkeyPrinters, hkeyPrinter;
4416 WCHAR PrinterName[255];
4417 DWORD needed = 0, number = 0;
4418 DWORD used, i, left;
4419 PBYTE pi, buf;
4421 if(lpbPrinters)
4422 memset(lpbPrinters, 0, cbBuf);
4423 if(lpdwReturned)
4424 *lpdwReturned = 0;
4425 if(lpdwNeeded)
4426 *lpdwNeeded = 0;
4428 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4429 if(dwType == PRINTER_ENUM_DEFAULT)
4430 return TRUE;
4432 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4433 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4434 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4435 if (!dwType) {
4436 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4437 *lpdwNeeded = 0;
4438 *lpdwReturned = 0;
4439 return TRUE;
4444 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4445 FIXME("dwType = %08x\n", dwType);
4446 SetLastError(ERROR_INVALID_FLAGS);
4447 return FALSE;
4450 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4451 ERROR_SUCCESS) {
4452 ERR("Can't create Printers key\n");
4453 return FALSE;
4456 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4457 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4458 RegCloseKey(hkeyPrinters);
4459 ERR("Can't query Printers key\n");
4460 return FALSE;
4462 TRACE("Found %d printers\n", number);
4464 switch(dwLevel) {
4465 case 1:
4466 used = number * sizeof(PRINTER_INFO_1W);
4467 break;
4468 case 2:
4469 used = number * sizeof(PRINTER_INFO_2W);
4470 break;
4471 case 4:
4472 used = number * sizeof(PRINTER_INFO_4W);
4473 break;
4474 case 5:
4475 used = number * sizeof(PRINTER_INFO_5W);
4476 break;
4478 default:
4479 SetLastError(ERROR_INVALID_LEVEL);
4480 RegCloseKey(hkeyPrinters);
4481 return FALSE;
4483 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4485 for(i = 0; i < number; i++) {
4486 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4487 ERROR_SUCCESS) {
4488 ERR("Can't enum key number %d\n", i);
4489 RegCloseKey(hkeyPrinters);
4490 return FALSE;
4492 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4493 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4494 ERROR_SUCCESS) {
4495 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4496 RegCloseKey(hkeyPrinters);
4497 return FALSE;
4500 if(cbBuf > used) {
4501 buf = lpbPrinters + used;
4502 left = cbBuf - used;
4503 } else {
4504 buf = NULL;
4505 left = 0;
4508 switch(dwLevel) {
4509 case 1:
4510 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4511 left, &needed, unicode);
4512 used += needed;
4513 if(pi) pi += sizeof(PRINTER_INFO_1W);
4514 break;
4515 case 2:
4516 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4517 left, &needed, unicode);
4518 used += needed;
4519 if(pi) pi += sizeof(PRINTER_INFO_2W);
4520 break;
4521 case 4:
4522 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4523 left, &needed, unicode);
4524 used += needed;
4525 if(pi) pi += sizeof(PRINTER_INFO_4W);
4526 break;
4527 case 5:
4528 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4529 left, &needed, unicode);
4530 used += needed;
4531 if(pi) pi += sizeof(PRINTER_INFO_5W);
4532 break;
4533 default:
4534 ERR("Shouldn't be here!\n");
4535 RegCloseKey(hkeyPrinter);
4536 RegCloseKey(hkeyPrinters);
4537 return FALSE;
4539 RegCloseKey(hkeyPrinter);
4541 RegCloseKey(hkeyPrinters);
4543 if(lpdwNeeded)
4544 *lpdwNeeded = used;
4546 if(used > cbBuf) {
4547 if(lpbPrinters)
4548 memset(lpbPrinters, 0, cbBuf);
4549 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4550 return FALSE;
4552 if(lpdwReturned)
4553 *lpdwReturned = number;
4554 SetLastError(ERROR_SUCCESS);
4555 return TRUE;
4559 /******************************************************************
4560 * EnumPrintersW [WINSPOOL.@]
4562 * Enumerates the available printers, print servers and print
4563 * providers, depending on the specified flags, name and level.
4565 * RETURNS:
4567 * If level is set to 1:
4568 * Returns an array of PRINTER_INFO_1 data structures in the
4569 * lpbPrinters buffer.
4571 * If level is set to 2:
4572 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4573 * Returns an array of PRINTER_INFO_2 data structures in the
4574 * lpbPrinters buffer. Note that according to MSDN also an
4575 * OpenPrinter should be performed on every remote printer.
4577 * If level is set to 4 (officially WinNT only):
4578 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4579 * Fast: Only the registry is queried to retrieve printer names,
4580 * no connection to the driver is made.
4581 * Returns an array of PRINTER_INFO_4 data structures in the
4582 * lpbPrinters buffer.
4584 * If level is set to 5 (officially WinNT4/Win9x only):
4585 * Fast: Only the registry is queried to retrieve printer names,
4586 * no connection to the driver is made.
4587 * Returns an array of PRINTER_INFO_5 data structures in the
4588 * lpbPrinters buffer.
4590 * If level set to 3 or 6+:
4591 * returns zero (failure!)
4593 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4594 * for information.
4596 * BUGS:
4597 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4598 * - Only levels 2, 4 and 5 are implemented at the moment.
4599 * - 16-bit printer drivers are not enumerated.
4600 * - Returned amount of bytes used/needed does not match the real Windoze
4601 * implementation (as in this implementation, all strings are part
4602 * of the buffer, whereas Win32 keeps them somewhere else)
4603 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4605 * NOTE:
4606 * - In a regular Wine installation, no registry settings for printers
4607 * exist, which makes this function return an empty list.
4609 BOOL WINAPI EnumPrintersW(
4610 DWORD dwType, /* [in] Types of print objects to enumerate */
4611 LPWSTR lpszName, /* [in] name of objects to enumerate */
4612 DWORD dwLevel, /* [in] type of printer info structure */
4613 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4614 DWORD cbBuf, /* [in] max size of buffer in bytes */
4615 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4616 LPDWORD lpdwReturned /* [out] number of entries returned */
4619 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4620 lpdwNeeded, lpdwReturned, TRUE);
4623 /******************************************************************
4624 * EnumPrintersA [WINSPOOL.@]
4626 * See EnumPrintersW
4629 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4630 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4632 BOOL ret;
4633 UNICODE_STRING pNameU;
4634 LPWSTR pNameW;
4635 LPBYTE pPrintersW;
4637 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4638 pPrinters, cbBuf, pcbNeeded, pcReturned);
4640 pNameW = asciitounicode(&pNameU, pName);
4642 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4643 MS Office need this */
4644 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4646 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4648 RtlFreeUnicodeString(&pNameU);
4649 if (ret) {
4650 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4652 HeapFree(GetProcessHeap(), 0, pPrintersW);
4653 return ret;
4656 /*****************************************************************************
4657 * WINSPOOL_GetDriverInfoFromReg [internal]
4659 * Enters the information from the registry into the DRIVER_INFO struct
4661 * RETURNS
4662 * zero if the printer driver does not exist in the registry
4663 * (only if Level > 1) otherwise nonzero
4665 static BOOL WINSPOOL_GetDriverInfoFromReg(
4666 HKEY hkeyDrivers,
4667 LPWSTR DriverName,
4668 const printenv_t * env,
4669 DWORD Level,
4670 LPBYTE ptr, /* DRIVER_INFO */
4671 LPBYTE pDriverStrings, /* strings buffer */
4672 DWORD cbBuf, /* size of string buffer */
4673 LPDWORD pcbNeeded, /* space needed for str. */
4674 BOOL unicode) /* type of strings */
4676 DWORD size, tmp;
4677 HKEY hkeyDriver;
4678 WCHAR driverdir[MAX_PATH];
4679 DWORD dirlen;
4680 LPBYTE strPtr = pDriverStrings;
4681 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4683 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4684 debugstr_w(DriverName), env,
4685 Level, di, pDriverStrings, cbBuf, unicode);
4687 if (di) ZeroMemory(di, di_sizeof[Level]);
4689 if (unicode) {
4690 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4691 if (*pcbNeeded <= cbBuf)
4692 strcpyW((LPWSTR)strPtr, DriverName);
4694 else
4696 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4697 if (*pcbNeeded <= cbBuf)
4698 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4701 /* pName for level 1 has a different offset! */
4702 if (Level == 1) {
4703 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4704 return TRUE;
4707 /* .cVersion and .pName for level > 1 */
4708 if (di) {
4709 di->cVersion = env->driverversion;
4710 di->pName = (LPWSTR) strPtr;
4711 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4714 /* Reserve Space for the largest subdir and a Backslash*/
4715 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4716 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4717 /* Should never Fail */
4718 return FALSE;
4720 lstrcatW(driverdir, env->versionsubdir);
4721 lstrcatW(driverdir, backslashW);
4723 /* dirlen must not include the terminating zero */
4724 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4725 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4727 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4728 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4729 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4730 return FALSE;
4733 /* pEnvironment */
4734 if (unicode)
4735 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4736 else
4737 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4739 *pcbNeeded += size;
4740 if (*pcbNeeded <= cbBuf) {
4741 if (unicode) {
4742 lstrcpyW((LPWSTR)strPtr, env->envname);
4744 else
4746 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4748 if (di) di->pEnvironment = (LPWSTR)strPtr;
4749 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4752 /* .pDriverPath is the Graphics rendering engine.
4753 The full Path is required to avoid a crash in some apps */
4754 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4755 *pcbNeeded += size;
4756 if (*pcbNeeded <= cbBuf)
4757 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4759 if (di) di->pDriverPath = (LPWSTR)strPtr;
4760 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4763 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4764 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4765 *pcbNeeded += size;
4766 if (*pcbNeeded <= cbBuf)
4767 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4769 if (di) di->pDataFile = (LPWSTR)strPtr;
4770 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4773 /* .pConfigFile is the Driver user Interface */
4774 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4775 *pcbNeeded += size;
4776 if (*pcbNeeded <= cbBuf)
4777 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4779 if (di) di->pConfigFile = (LPWSTR)strPtr;
4780 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4783 if (Level == 2 ) {
4784 RegCloseKey(hkeyDriver);
4785 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4786 return TRUE;
4789 if (Level == 5 ) {
4790 RegCloseKey(hkeyDriver);
4791 FIXME("level 5: incomplete\n");
4792 return TRUE;
4795 /* .pHelpFile */
4796 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4797 *pcbNeeded += size;
4798 if (*pcbNeeded <= cbBuf)
4799 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4801 if (di) di->pHelpFile = (LPWSTR)strPtr;
4802 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4805 /* .pDependentFiles */
4806 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4807 *pcbNeeded += size;
4808 if (*pcbNeeded <= cbBuf)
4809 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4811 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4812 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4814 else if (GetVersion() & 0x80000000) {
4815 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4816 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4817 *pcbNeeded += size;
4818 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4820 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4821 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4824 /* .pMonitorName is the optional Language Monitor */
4825 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4826 *pcbNeeded += size;
4827 if (*pcbNeeded <= cbBuf)
4828 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4830 if (di) di->pMonitorName = (LPWSTR)strPtr;
4831 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4834 /* .pDefaultDataType */
4835 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4836 *pcbNeeded += size;
4837 if(*pcbNeeded <= cbBuf)
4838 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4840 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4841 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4844 if (Level == 3 ) {
4845 RegCloseKey(hkeyDriver);
4846 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4847 return TRUE;
4850 /* .pszzPreviousNames */
4851 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4852 *pcbNeeded += size;
4853 if(*pcbNeeded <= cbBuf)
4854 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4856 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4857 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4860 if (Level == 4 ) {
4861 RegCloseKey(hkeyDriver);
4862 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4863 return TRUE;
4866 /* support is missing, but not important enough for a FIXME */
4867 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4869 /* .pszMfgName */
4870 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4871 *pcbNeeded += size;
4872 if(*pcbNeeded <= cbBuf)
4873 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4875 if (di) di->pszMfgName = (LPWSTR)strPtr;
4876 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4879 /* .pszOEMUrl */
4880 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4881 *pcbNeeded += size;
4882 if(*pcbNeeded <= cbBuf)
4883 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4885 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4886 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4889 /* .pszHardwareID */
4890 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4891 *pcbNeeded += size;
4892 if(*pcbNeeded <= cbBuf)
4893 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4895 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4896 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4899 /* .pszProvider */
4900 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4901 *pcbNeeded += size;
4902 if(*pcbNeeded <= cbBuf)
4903 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4905 if (di) di->pszProvider = (LPWSTR)strPtr;
4906 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4909 if (Level == 6 ) {
4910 RegCloseKey(hkeyDriver);
4911 return TRUE;
4914 /* support is missing, but not important enough for a FIXME */
4915 TRACE("level 8: incomplete\n");
4917 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4918 RegCloseKey(hkeyDriver);
4919 return TRUE;
4922 /*****************************************************************************
4923 * WINSPOOL_GetPrinterDriver
4925 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4926 DWORD Level, LPBYTE pDriverInfo,
4927 DWORD cbBuf, LPDWORD pcbNeeded,
4928 BOOL unicode)
4930 LPCWSTR name;
4931 WCHAR DriverName[100];
4932 DWORD ret, type, size, needed = 0;
4933 LPBYTE ptr = NULL;
4934 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4935 const printenv_t * env;
4937 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4938 Level,pDriverInfo,cbBuf, pcbNeeded);
4941 if (!(name = get_opened_printer_name(hPrinter))) {
4942 SetLastError(ERROR_INVALID_HANDLE);
4943 return FALSE;
4946 if (Level < 1 || Level == 7 || Level > 8) {
4947 SetLastError(ERROR_INVALID_LEVEL);
4948 return FALSE;
4951 env = validate_envW(pEnvironment);
4952 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4954 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4955 ERROR_SUCCESS) {
4956 ERR("Can't create Printers key\n");
4957 return FALSE;
4959 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4960 != ERROR_SUCCESS) {
4961 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4962 RegCloseKey(hkeyPrinters);
4963 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4964 return FALSE;
4966 size = sizeof(DriverName);
4967 DriverName[0] = 0;
4968 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4969 (LPBYTE)DriverName, &size);
4970 RegCloseKey(hkeyPrinter);
4971 RegCloseKey(hkeyPrinters);
4972 if(ret != ERROR_SUCCESS) {
4973 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4974 return FALSE;
4977 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4978 if(!hkeyDrivers) {
4979 ERR("Can't create Drivers key\n");
4980 return FALSE;
4983 size = di_sizeof[Level];
4984 if ((size <= cbBuf) && pDriverInfo)
4985 ptr = pDriverInfo + size;
4987 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4988 env, Level, pDriverInfo, ptr,
4989 (cbBuf < size) ? 0 : cbBuf - size,
4990 &needed, unicode)) {
4991 RegCloseKey(hkeyDrivers);
4992 return FALSE;
4995 RegCloseKey(hkeyDrivers);
4997 if(pcbNeeded) *pcbNeeded = size + needed;
4998 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4999 if(cbBuf >= needed) return TRUE;
5000 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5001 return FALSE;
5004 /*****************************************************************************
5005 * GetPrinterDriverA [WINSPOOL.@]
5007 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5008 DWORD Level, LPBYTE pDriverInfo,
5009 DWORD cbBuf, LPDWORD pcbNeeded)
5011 BOOL ret;
5012 UNICODE_STRING pEnvW;
5013 PWSTR pwstrEnvW;
5015 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5016 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
5017 cbBuf, pcbNeeded, FALSE);
5018 RtlFreeUnicodeString(&pEnvW);
5019 return ret;
5021 /*****************************************************************************
5022 * GetPrinterDriverW [WINSPOOL.@]
5024 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5025 DWORD Level, LPBYTE pDriverInfo,
5026 DWORD cbBuf, LPDWORD pcbNeeded)
5028 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
5029 pDriverInfo, cbBuf, pcbNeeded, TRUE);
5032 /*****************************************************************************
5033 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5035 * Return the PATH for the Printer-Drivers (UNICODE)
5037 * PARAMS
5038 * pName [I] Servername (NT only) or NULL (local Computer)
5039 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5040 * Level [I] Structure-Level (must be 1)
5041 * pDriverDirectory [O] PTR to Buffer that receives the Result
5042 * cbBuf [I] Size of Buffer at pDriverDirectory
5043 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5044 * required for pDriverDirectory
5046 * RETURNS
5047 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5048 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5049 * if cbBuf is too small
5051 * Native Values returned in pDriverDirectory on Success:
5052 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5053 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5054 *| win9x(Windows 4.0): "%winsysdir%"
5056 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5058 * FIXME
5059 *- Only NULL or "" is supported for pName
5062 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5063 DWORD Level, LPBYTE pDriverDirectory,
5064 DWORD cbBuf, LPDWORD pcbNeeded)
5066 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5067 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5069 if ((backend == NULL) && !load_backend()) return FALSE;
5071 if (Level != 1) {
5072 /* (Level != 1) is ignored in win9x */
5073 SetLastError(ERROR_INVALID_LEVEL);
5074 return FALSE;
5076 if (pcbNeeded == NULL) {
5077 /* (pcbNeeded == NULL) is ignored in win9x */
5078 SetLastError(RPC_X_NULL_REF_POINTER);
5079 return FALSE;
5082 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5083 pDriverDirectory, cbBuf, pcbNeeded);
5088 /*****************************************************************************
5089 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5091 * Return the PATH for the Printer-Drivers (ANSI)
5093 * See GetPrinterDriverDirectoryW.
5095 * NOTES
5096 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5099 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5100 DWORD Level, LPBYTE pDriverDirectory,
5101 DWORD cbBuf, LPDWORD pcbNeeded)
5103 UNICODE_STRING nameW, environmentW;
5104 BOOL ret;
5105 DWORD pcbNeededW;
5106 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5107 WCHAR *driverDirectoryW = NULL;
5109 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5110 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5112 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5114 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5115 else nameW.Buffer = NULL;
5116 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5117 else environmentW.Buffer = NULL;
5119 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5120 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5121 if (ret) {
5122 DWORD needed;
5123 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5124 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5125 if(pcbNeeded)
5126 *pcbNeeded = needed;
5127 ret = (needed <= cbBuf) ? TRUE : FALSE;
5128 } else
5129 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5131 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5133 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5134 RtlFreeUnicodeString(&environmentW);
5135 RtlFreeUnicodeString(&nameW);
5137 return ret;
5140 /*****************************************************************************
5141 * AddPrinterDriverA [WINSPOOL.@]
5143 * See AddPrinterDriverW.
5146 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5148 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5149 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5152 /******************************************************************************
5153 * AddPrinterDriverW (WINSPOOL.@)
5155 * Install a Printer Driver
5157 * PARAMS
5158 * pName [I] Servername or NULL (local Computer)
5159 * level [I] Level for the supplied DRIVER_INFO_*W struct
5160 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5162 * RESULTS
5163 * Success: TRUE
5164 * Failure: FALSE
5167 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5169 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5170 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5173 /*****************************************************************************
5174 * AddPrintProcessorA [WINSPOOL.@]
5176 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5177 LPSTR pPrintProcessorName)
5179 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5180 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5181 return FALSE;
5184 /*****************************************************************************
5185 * AddPrintProcessorW [WINSPOOL.@]
5187 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5188 LPWSTR pPrintProcessorName)
5190 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5191 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5192 return FALSE;
5195 /*****************************************************************************
5196 * AddPrintProvidorA [WINSPOOL.@]
5198 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5200 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5201 return FALSE;
5204 /*****************************************************************************
5205 * AddPrintProvidorW [WINSPOOL.@]
5207 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5209 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5210 return FALSE;
5213 /*****************************************************************************
5214 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5216 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5217 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5219 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5220 pDevModeOutput, pDevModeInput);
5221 return 0;
5224 /*****************************************************************************
5225 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5227 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5228 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5230 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5231 pDevModeOutput, pDevModeInput);
5232 return 0;
5235 /*****************************************************************************
5236 * PrinterProperties [WINSPOOL.@]
5238 * Displays a dialog to set the properties of the printer.
5240 * RETURNS
5241 * nonzero on success or zero on failure
5243 * BUGS
5244 * implemented as stub only
5246 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5247 HANDLE hPrinter /* [in] handle to printer object */
5249 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5250 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5251 return FALSE;
5254 /*****************************************************************************
5255 * EnumJobsA [WINSPOOL.@]
5258 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5259 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5260 LPDWORD pcReturned)
5262 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5263 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5265 if(pcbNeeded) *pcbNeeded = 0;
5266 if(pcReturned) *pcReturned = 0;
5267 return FALSE;
5271 /*****************************************************************************
5272 * EnumJobsW [WINSPOOL.@]
5275 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5276 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5277 LPDWORD pcReturned)
5279 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5280 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5282 if(pcbNeeded) *pcbNeeded = 0;
5283 if(pcReturned) *pcReturned = 0;
5284 return FALSE;
5287 /*****************************************************************************
5288 * WINSPOOL_EnumPrinterDrivers [internal]
5290 * Delivers information about all printer drivers installed on the
5291 * localhost or a given server
5293 * RETURNS
5294 * nonzero on success or zero on failure. If the buffer for the returned
5295 * information is too small the function will return an error
5297 * BUGS
5298 * - only implemented for localhost, foreign hosts will return an error
5300 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5301 DWORD Level, LPBYTE pDriverInfo,
5302 DWORD cbBuf, LPDWORD pcbNeeded,
5303 LPDWORD pcReturned, BOOL unicode)
5305 { HKEY hkeyDrivers;
5306 DWORD i, needed, number = 0, size = 0;
5307 WCHAR DriverNameW[255];
5308 PBYTE ptr;
5309 const printenv_t * env;
5311 TRACE("%s,%s,%d,%p,%d,%d\n",
5312 debugstr_w(pName), debugstr_w(pEnvironment),
5313 Level, pDriverInfo, cbBuf, unicode);
5315 /* check for local drivers */
5316 if((pName) && (pName[0])) {
5317 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5318 SetLastError(ERROR_ACCESS_DENIED);
5319 return FALSE;
5322 env = validate_envW(pEnvironment);
5323 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5325 /* check input parameter */
5326 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5327 SetLastError(ERROR_INVALID_LEVEL);
5328 return FALSE;
5331 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5332 SetLastError(RPC_X_NULL_REF_POINTER);
5333 return FALSE;
5336 /* initialize return values */
5337 if(pDriverInfo)
5338 memset( pDriverInfo, 0, cbBuf);
5339 *pcbNeeded = 0;
5340 *pcReturned = 0;
5342 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5343 if(!hkeyDrivers) {
5344 ERR("Can't open Drivers key\n");
5345 return FALSE;
5348 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5349 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5350 RegCloseKey(hkeyDrivers);
5351 ERR("Can't query Drivers key\n");
5352 return FALSE;
5354 TRACE("Found %d Drivers\n", number);
5356 /* get size of single struct
5357 * unicode and ascii structure have the same size
5359 size = di_sizeof[Level];
5361 /* calculate required buffer size */
5362 *pcbNeeded = size * number;
5364 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5365 i < number;
5366 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5367 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5368 != ERROR_SUCCESS) {
5369 ERR("Can't enum key number %d\n", i);
5370 RegCloseKey(hkeyDrivers);
5371 return FALSE;
5373 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5374 env, Level, ptr,
5375 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5376 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5377 &needed, unicode)) {
5378 RegCloseKey(hkeyDrivers);
5379 return FALSE;
5381 (*pcbNeeded) += needed;
5384 RegCloseKey(hkeyDrivers);
5386 if(cbBuf < *pcbNeeded){
5387 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5388 return FALSE;
5391 *pcReturned = number;
5392 return TRUE;
5395 /*****************************************************************************
5396 * EnumPrinterDriversW [WINSPOOL.@]
5398 * see function EnumPrinterDrivers for RETURNS, BUGS
5400 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5401 LPBYTE pDriverInfo, DWORD cbBuf,
5402 LPDWORD pcbNeeded, LPDWORD pcReturned)
5404 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5405 cbBuf, pcbNeeded, pcReturned, TRUE);
5408 /*****************************************************************************
5409 * EnumPrinterDriversA [WINSPOOL.@]
5411 * see function EnumPrinterDrivers for RETURNS, BUGS
5413 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5414 LPBYTE pDriverInfo, DWORD cbBuf,
5415 LPDWORD pcbNeeded, LPDWORD pcReturned)
5416 { BOOL ret;
5417 UNICODE_STRING pNameW, pEnvironmentW;
5418 PWSTR pwstrNameW, pwstrEnvironmentW;
5420 pwstrNameW = asciitounicode(&pNameW, pName);
5421 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5423 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5424 Level, pDriverInfo, cbBuf, pcbNeeded,
5425 pcReturned, FALSE);
5426 RtlFreeUnicodeString(&pNameW);
5427 RtlFreeUnicodeString(&pEnvironmentW);
5429 return ret;
5432 /******************************************************************************
5433 * EnumPortsA (WINSPOOL.@)
5435 * See EnumPortsW.
5438 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5439 LPDWORD pcbNeeded, LPDWORD pcReturned)
5441 BOOL res;
5442 LPBYTE bufferW = NULL;
5443 LPWSTR nameW = NULL;
5444 DWORD needed = 0;
5445 DWORD numentries = 0;
5446 INT len;
5448 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5449 cbBuf, pcbNeeded, pcReturned);
5451 /* convert servername to unicode */
5452 if (pName) {
5453 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5454 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5455 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5457 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5458 needed = cbBuf * sizeof(WCHAR);
5459 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5460 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5462 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5463 if (pcbNeeded) needed = *pcbNeeded;
5464 /* HeapReAlloc return NULL, when bufferW was NULL */
5465 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5466 HeapAlloc(GetProcessHeap(), 0, needed);
5468 /* Try again with the large Buffer */
5469 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5471 needed = pcbNeeded ? *pcbNeeded : 0;
5472 numentries = pcReturned ? *pcReturned : 0;
5475 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5476 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5478 if (res) {
5479 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5480 DWORD entrysize = 0;
5481 DWORD index;
5482 LPSTR ptr;
5483 LPPORT_INFO_2W pi2w;
5484 LPPORT_INFO_2A pi2a;
5486 needed = 0;
5487 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5489 /* First pass: calculate the size for all Entries */
5490 pi2w = (LPPORT_INFO_2W) bufferW;
5491 pi2a = (LPPORT_INFO_2A) pPorts;
5492 index = 0;
5493 while (index < numentries) {
5494 index++;
5495 needed += entrysize; /* PORT_INFO_?A */
5496 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5498 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5499 NULL, 0, NULL, NULL);
5500 if (Level > 1) {
5501 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5502 NULL, 0, NULL, NULL);
5503 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5504 NULL, 0, NULL, NULL);
5506 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5507 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5508 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5511 /* check for errors and quit on failure */
5512 if (cbBuf < needed) {
5513 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5514 res = FALSE;
5515 goto cleanup;
5517 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5518 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5519 cbBuf -= len ; /* free Bytes in the user-Buffer */
5520 pi2w = (LPPORT_INFO_2W) bufferW;
5521 pi2a = (LPPORT_INFO_2A) pPorts;
5522 index = 0;
5523 /* Second Pass: Fill the User Buffer (if we have one) */
5524 while ((index < numentries) && pPorts) {
5525 index++;
5526 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5527 pi2a->pPortName = ptr;
5528 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5529 ptr, cbBuf , NULL, NULL);
5530 ptr += len;
5531 cbBuf -= len;
5532 if (Level > 1) {
5533 pi2a->pMonitorName = ptr;
5534 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5535 ptr, cbBuf, NULL, NULL);
5536 ptr += len;
5537 cbBuf -= len;
5539 pi2a->pDescription = ptr;
5540 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5541 ptr, cbBuf, NULL, NULL);
5542 ptr += len;
5543 cbBuf -= len;
5545 pi2a->fPortType = pi2w->fPortType;
5546 pi2a->Reserved = 0; /* documented: "must be zero" */
5549 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5550 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5551 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5555 cleanup:
5556 if (pcbNeeded) *pcbNeeded = needed;
5557 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5559 HeapFree(GetProcessHeap(), 0, nameW);
5560 HeapFree(GetProcessHeap(), 0, bufferW);
5562 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5563 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5565 return (res);
5569 /******************************************************************************
5570 * EnumPortsW (WINSPOOL.@)
5572 * Enumerate available Ports
5574 * PARAMS
5575 * name [I] Servername or NULL (local Computer)
5576 * level [I] Structure-Level (1 or 2)
5577 * buffer [O] PTR to Buffer that receives the Result
5578 * bufsize [I] Size of Buffer at buffer
5579 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5580 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5582 * RETURNS
5583 * Success: TRUE
5584 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5588 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5590 DWORD needed = 0;
5591 DWORD numentries = 0;
5592 BOOL res = FALSE;
5594 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5595 cbBuf, pcbNeeded, pcReturned);
5597 if (pName && (pName[0])) {
5598 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5599 SetLastError(ERROR_ACCESS_DENIED);
5600 goto emP_cleanup;
5603 /* Level is not checked in win9x */
5604 if (!Level || (Level > 2)) {
5605 WARN("level (%d) is ignored in win9x\n", Level);
5606 SetLastError(ERROR_INVALID_LEVEL);
5607 goto emP_cleanup;
5609 if (!pcbNeeded) {
5610 SetLastError(RPC_X_NULL_REF_POINTER);
5611 goto emP_cleanup;
5614 EnterCriticalSection(&monitor_handles_cs);
5615 monitor_loadall();
5617 /* Scan all local Ports */
5618 numentries = 0;
5619 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5621 /* we calculated the needed buffersize. now do the error-checks */
5622 if (cbBuf < needed) {
5623 monitor_unloadall();
5624 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5625 goto emP_cleanup_cs;
5627 else if (!pPorts || !pcReturned) {
5628 monitor_unloadall();
5629 SetLastError(RPC_X_NULL_REF_POINTER);
5630 goto emP_cleanup_cs;
5633 /* Fill the Buffer */
5634 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5635 res = TRUE;
5636 monitor_unloadall();
5638 emP_cleanup_cs:
5639 LeaveCriticalSection(&monitor_handles_cs);
5641 emP_cleanup:
5642 if (pcbNeeded) *pcbNeeded = needed;
5643 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5645 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5646 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5648 return (res);
5651 /******************************************************************************
5652 * GetDefaultPrinterW (WINSPOOL.@)
5654 * FIXME
5655 * This function must read the value from data 'device' of key
5656 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5658 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5660 BOOL retval = TRUE;
5661 DWORD insize, len;
5662 WCHAR *buffer, *ptr;
5664 if (!namesize)
5666 SetLastError(ERROR_INVALID_PARAMETER);
5667 return FALSE;
5670 /* make the buffer big enough for the stuff from the profile/registry,
5671 * the content must fit into the local buffer to compute the correct
5672 * size even if the extern buffer is too small or not given.
5673 * (20 for ,driver,port) */
5674 insize = *namesize;
5675 len = max(100, (insize + 20));
5676 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5678 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5680 SetLastError (ERROR_FILE_NOT_FOUND);
5681 retval = FALSE;
5682 goto end;
5684 TRACE("%s\n", debugstr_w(buffer));
5686 if ((ptr = strchrW(buffer, ',')) == NULL)
5688 SetLastError(ERROR_INVALID_NAME);
5689 retval = FALSE;
5690 goto end;
5693 *ptr = 0;
5694 *namesize = strlenW(buffer) + 1;
5695 if(!name || (*namesize > insize))
5697 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5698 retval = FALSE;
5699 goto end;
5701 strcpyW(name, buffer);
5703 end:
5704 HeapFree( GetProcessHeap(), 0, buffer);
5705 return retval;
5709 /******************************************************************************
5710 * GetDefaultPrinterA (WINSPOOL.@)
5712 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5714 BOOL retval = TRUE;
5715 DWORD insize = 0;
5716 WCHAR *bufferW = NULL;
5718 if (!namesize)
5720 SetLastError(ERROR_INVALID_PARAMETER);
5721 return FALSE;
5724 if(name && *namesize) {
5725 insize = *namesize;
5726 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5729 if(!GetDefaultPrinterW( bufferW, namesize)) {
5730 retval = FALSE;
5731 goto end;
5734 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5735 NULL, NULL);
5736 if (!*namesize)
5738 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5739 retval = FALSE;
5741 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5743 end:
5744 HeapFree( GetProcessHeap(), 0, bufferW);
5745 return retval;
5749 /******************************************************************************
5750 * SetDefaultPrinterW (WINSPOOL.204)
5752 * Set the Name of the Default Printer
5754 * PARAMS
5755 * pszPrinter [I] Name of the Printer or NULL
5757 * RETURNS
5758 * Success: True
5759 * Failure: FALSE
5761 * NOTES
5762 * When the Parameter is NULL or points to an Empty String and
5763 * a Default Printer was already present, then this Function changes nothing.
5764 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5765 * the First enumerated local Printer is used.
5768 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5771 TRACE("(%s)\n", debugstr_w(pszPrinter));
5773 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5774 return FALSE;
5777 /******************************************************************************
5778 * SetDefaultPrinterA (WINSPOOL.202)
5780 * See SetDefaultPrinterW.
5783 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5786 TRACE("(%s)\n", debugstr_a(pszPrinter));
5788 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5789 return FALSE;
5793 /******************************************************************************
5794 * SetPrinterDataExA (WINSPOOL.@)
5796 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5797 LPCSTR pValueName, DWORD Type,
5798 LPBYTE pData, DWORD cbData)
5800 HKEY hkeyPrinter, hkeySubkey;
5801 DWORD ret;
5803 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5804 debugstr_a(pValueName), Type, pData, cbData);
5806 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5807 != ERROR_SUCCESS)
5808 return ret;
5810 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5811 != ERROR_SUCCESS) {
5812 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5813 RegCloseKey(hkeyPrinter);
5814 return ret;
5816 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5817 RegCloseKey(hkeySubkey);
5818 RegCloseKey(hkeyPrinter);
5819 return ret;
5822 /******************************************************************************
5823 * SetPrinterDataExW (WINSPOOL.@)
5825 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5826 LPCWSTR pValueName, DWORD Type,
5827 LPBYTE pData, DWORD cbData)
5829 HKEY hkeyPrinter, hkeySubkey;
5830 DWORD ret;
5832 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5833 debugstr_w(pValueName), Type, pData, cbData);
5835 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5836 != ERROR_SUCCESS)
5837 return ret;
5839 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5840 != ERROR_SUCCESS) {
5841 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5842 RegCloseKey(hkeyPrinter);
5843 return ret;
5845 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5846 RegCloseKey(hkeySubkey);
5847 RegCloseKey(hkeyPrinter);
5848 return ret;
5851 /******************************************************************************
5852 * SetPrinterDataA (WINSPOOL.@)
5854 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5855 LPBYTE pData, DWORD cbData)
5857 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5858 pData, cbData);
5861 /******************************************************************************
5862 * SetPrinterDataW (WINSPOOL.@)
5864 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5865 LPBYTE pData, DWORD cbData)
5867 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5868 pData, cbData);
5871 /******************************************************************************
5872 * GetPrinterDataExA (WINSPOOL.@)
5874 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5875 LPCSTR pValueName, LPDWORD pType,
5876 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5878 HKEY hkeyPrinter, hkeySubkey;
5879 DWORD ret;
5881 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5882 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5883 pcbNeeded);
5885 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5886 != ERROR_SUCCESS)
5887 return ret;
5889 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5890 != ERROR_SUCCESS) {
5891 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5892 RegCloseKey(hkeyPrinter);
5893 return ret;
5895 *pcbNeeded = nSize;
5896 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5897 RegCloseKey(hkeySubkey);
5898 RegCloseKey(hkeyPrinter);
5899 return ret;
5902 /******************************************************************************
5903 * GetPrinterDataExW (WINSPOOL.@)
5905 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5906 LPCWSTR pValueName, LPDWORD pType,
5907 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5909 HKEY hkeyPrinter, hkeySubkey;
5910 DWORD ret;
5912 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5913 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5914 pcbNeeded);
5916 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5917 != ERROR_SUCCESS)
5918 return ret;
5920 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5921 != ERROR_SUCCESS) {
5922 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5923 RegCloseKey(hkeyPrinter);
5924 return ret;
5926 *pcbNeeded = nSize;
5927 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5928 RegCloseKey(hkeySubkey);
5929 RegCloseKey(hkeyPrinter);
5930 return ret;
5933 /******************************************************************************
5934 * GetPrinterDataA (WINSPOOL.@)
5936 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5937 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5939 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5940 pData, nSize, pcbNeeded);
5943 /******************************************************************************
5944 * GetPrinterDataW (WINSPOOL.@)
5946 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5947 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5949 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5950 pData, nSize, pcbNeeded);
5953 /*******************************************************************************
5954 * EnumPrinterDataExW [WINSPOOL.@]
5956 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5957 LPBYTE pEnumValues, DWORD cbEnumValues,
5958 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5960 HKEY hkPrinter, hkSubKey;
5961 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5962 cbValueNameLen, cbMaxValueLen, cbValueLen,
5963 cbBufSize, dwType;
5964 LPWSTR lpValueName;
5965 HANDLE hHeap;
5966 PBYTE lpValue;
5967 PPRINTER_ENUM_VALUESW ppev;
5969 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5971 if (pKeyName == NULL || *pKeyName == 0)
5972 return ERROR_INVALID_PARAMETER;
5974 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5975 if (ret != ERROR_SUCCESS)
5977 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5978 hPrinter, ret);
5979 return ret;
5982 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5983 if (ret != ERROR_SUCCESS)
5985 r = RegCloseKey (hkPrinter);
5986 if (r != ERROR_SUCCESS)
5987 WARN ("RegCloseKey returned %i\n", r);
5988 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5989 debugstr_w (pKeyName), ret);
5990 return ret;
5993 ret = RegCloseKey (hkPrinter);
5994 if (ret != ERROR_SUCCESS)
5996 ERR ("RegCloseKey returned %i\n", ret);
5997 r = RegCloseKey (hkSubKey);
5998 if (r != ERROR_SUCCESS)
5999 WARN ("RegCloseKey returned %i\n", r);
6000 return ret;
6003 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6004 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6005 if (ret != ERROR_SUCCESS)
6007 r = RegCloseKey (hkSubKey);
6008 if (r != ERROR_SUCCESS)
6009 WARN ("RegCloseKey returned %i\n", r);
6010 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6011 return ret;
6014 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6015 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6017 if (cValues == 0) /* empty key */
6019 r = RegCloseKey (hkSubKey);
6020 if (r != ERROR_SUCCESS)
6021 WARN ("RegCloseKey returned %i\n", r);
6022 *pcbEnumValues = *pnEnumValues = 0;
6023 return ERROR_SUCCESS;
6026 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6028 hHeap = GetProcessHeap ();
6029 if (hHeap == NULL)
6031 ERR ("GetProcessHeap failed\n");
6032 r = RegCloseKey (hkSubKey);
6033 if (r != ERROR_SUCCESS)
6034 WARN ("RegCloseKey returned %i\n", r);
6035 return ERROR_OUTOFMEMORY;
6038 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6039 if (lpValueName == NULL)
6041 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6042 r = RegCloseKey (hkSubKey);
6043 if (r != ERROR_SUCCESS)
6044 WARN ("RegCloseKey returned %i\n", r);
6045 return ERROR_OUTOFMEMORY;
6048 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6049 if (lpValue == NULL)
6051 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6052 if (HeapFree (hHeap, 0, lpValueName) == 0)
6053 WARN ("HeapFree failed with code %i\n", GetLastError ());
6054 r = RegCloseKey (hkSubKey);
6055 if (r != ERROR_SUCCESS)
6056 WARN ("RegCloseKey returned %i\n", r);
6057 return ERROR_OUTOFMEMORY;
6060 TRACE ("pass 1: calculating buffer required for all names and values\n");
6062 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6064 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6066 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6068 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6069 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6070 NULL, NULL, lpValue, &cbValueLen);
6071 if (ret != ERROR_SUCCESS)
6073 if (HeapFree (hHeap, 0, lpValue) == 0)
6074 WARN ("HeapFree failed with code %i\n", GetLastError ());
6075 if (HeapFree (hHeap, 0, lpValueName) == 0)
6076 WARN ("HeapFree failed with code %i\n", GetLastError ());
6077 r = RegCloseKey (hkSubKey);
6078 if (r != ERROR_SUCCESS)
6079 WARN ("RegCloseKey returned %i\n", r);
6080 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6081 return ret;
6084 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6085 debugstr_w (lpValueName), dwIndex,
6086 cbValueNameLen + 1, cbValueLen);
6088 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6089 cbBufSize += cbValueLen;
6092 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6094 *pcbEnumValues = cbBufSize;
6095 *pnEnumValues = cValues;
6097 if (cbEnumValues < cbBufSize) /* buffer too small */
6099 if (HeapFree (hHeap, 0, lpValue) == 0)
6100 WARN ("HeapFree failed with code %i\n", GetLastError ());
6101 if (HeapFree (hHeap, 0, lpValueName) == 0)
6102 WARN ("HeapFree failed with code %i\n", GetLastError ());
6103 r = RegCloseKey (hkSubKey);
6104 if (r != ERROR_SUCCESS)
6105 WARN ("RegCloseKey returned %i\n", r);
6106 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6107 return ERROR_MORE_DATA;
6110 TRACE ("pass 2: copying all names and values to buffer\n");
6112 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6113 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6115 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6117 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6118 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6119 NULL, &dwType, lpValue, &cbValueLen);
6120 if (ret != ERROR_SUCCESS)
6122 if (HeapFree (hHeap, 0, lpValue) == 0)
6123 WARN ("HeapFree failed with code %i\n", GetLastError ());
6124 if (HeapFree (hHeap, 0, lpValueName) == 0)
6125 WARN ("HeapFree failed with code %i\n", GetLastError ());
6126 r = RegCloseKey (hkSubKey);
6127 if (r != ERROR_SUCCESS)
6128 WARN ("RegCloseKey returned %i\n", r);
6129 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6130 return ret;
6133 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6134 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6135 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6136 pEnumValues += cbValueNameLen;
6138 /* return # of *bytes* (including trailing \0), not # of chars */
6139 ppev[dwIndex].cbValueName = cbValueNameLen;
6141 ppev[dwIndex].dwType = dwType;
6143 memcpy (pEnumValues, lpValue, cbValueLen);
6144 ppev[dwIndex].pData = pEnumValues;
6145 pEnumValues += cbValueLen;
6147 ppev[dwIndex].cbData = cbValueLen;
6149 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6150 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6153 if (HeapFree (hHeap, 0, lpValue) == 0)
6155 ret = GetLastError ();
6156 ERR ("HeapFree failed with code %i\n", ret);
6157 if (HeapFree (hHeap, 0, lpValueName) == 0)
6158 WARN ("HeapFree failed with code %i\n", GetLastError ());
6159 r = RegCloseKey (hkSubKey);
6160 if (r != ERROR_SUCCESS)
6161 WARN ("RegCloseKey returned %i\n", r);
6162 return ret;
6165 if (HeapFree (hHeap, 0, lpValueName) == 0)
6167 ret = GetLastError ();
6168 ERR ("HeapFree failed with code %i\n", ret);
6169 r = RegCloseKey (hkSubKey);
6170 if (r != ERROR_SUCCESS)
6171 WARN ("RegCloseKey returned %i\n", r);
6172 return ret;
6175 ret = RegCloseKey (hkSubKey);
6176 if (ret != ERROR_SUCCESS)
6178 ERR ("RegCloseKey returned %i\n", ret);
6179 return ret;
6182 return ERROR_SUCCESS;
6185 /*******************************************************************************
6186 * EnumPrinterDataExA [WINSPOOL.@]
6188 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6189 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6190 * what Windows 2000 SP1 does.
6193 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6194 LPBYTE pEnumValues, DWORD cbEnumValues,
6195 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6197 INT len;
6198 LPWSTR pKeyNameW;
6199 DWORD ret, dwIndex, dwBufSize;
6200 HANDLE hHeap;
6201 LPSTR pBuffer;
6203 TRACE ("%p %s\n", hPrinter, pKeyName);
6205 if (pKeyName == NULL || *pKeyName == 0)
6206 return ERROR_INVALID_PARAMETER;
6208 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6209 if (len == 0)
6211 ret = GetLastError ();
6212 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6213 return ret;
6216 hHeap = GetProcessHeap ();
6217 if (hHeap == NULL)
6219 ERR ("GetProcessHeap failed\n");
6220 return ERROR_OUTOFMEMORY;
6223 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6224 if (pKeyNameW == NULL)
6226 ERR ("Failed to allocate %i bytes from process heap\n",
6227 (LONG)(len * sizeof (WCHAR)));
6228 return ERROR_OUTOFMEMORY;
6231 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6233 ret = GetLastError ();
6234 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6235 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6236 WARN ("HeapFree failed with code %i\n", GetLastError ());
6237 return ret;
6240 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6241 pcbEnumValues, pnEnumValues);
6242 if (ret != ERROR_SUCCESS)
6244 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6245 WARN ("HeapFree failed with code %i\n", GetLastError ());
6246 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6247 return ret;
6250 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6252 ret = GetLastError ();
6253 ERR ("HeapFree failed with code %i\n", ret);
6254 return ret;
6257 if (*pnEnumValues == 0) /* empty key */
6258 return ERROR_SUCCESS;
6260 dwBufSize = 0;
6261 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6263 PPRINTER_ENUM_VALUESW ppev =
6264 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6266 if (dwBufSize < ppev->cbValueName)
6267 dwBufSize = ppev->cbValueName;
6269 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6270 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6271 dwBufSize = ppev->cbData;
6274 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6276 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6277 if (pBuffer == NULL)
6279 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6280 return ERROR_OUTOFMEMORY;
6283 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6285 PPRINTER_ENUM_VALUESW ppev =
6286 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6288 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6289 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6290 NULL);
6291 if (len == 0)
6293 ret = GetLastError ();
6294 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6295 if (HeapFree (hHeap, 0, pBuffer) == 0)
6296 WARN ("HeapFree failed with code %i\n", GetLastError ());
6297 return ret;
6300 memcpy (ppev->pValueName, pBuffer, len);
6302 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6304 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6305 ppev->dwType != REG_MULTI_SZ)
6306 continue;
6308 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6309 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6310 if (len == 0)
6312 ret = GetLastError ();
6313 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6314 if (HeapFree (hHeap, 0, pBuffer) == 0)
6315 WARN ("HeapFree failed with code %i\n", GetLastError ());
6316 return ret;
6319 memcpy (ppev->pData, pBuffer, len);
6321 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6322 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6325 if (HeapFree (hHeap, 0, pBuffer) == 0)
6327 ret = GetLastError ();
6328 ERR ("HeapFree failed with code %i\n", ret);
6329 return ret;
6332 return ERROR_SUCCESS;
6335 /******************************************************************************
6336 * AbortPrinter (WINSPOOL.@)
6338 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6340 FIXME("(%p), stub!\n", hPrinter);
6341 return TRUE;
6344 /******************************************************************************
6345 * AddPortA (WINSPOOL.@)
6347 * See AddPortW.
6350 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6352 LPWSTR nameW = NULL;
6353 LPWSTR monitorW = NULL;
6354 DWORD len;
6355 BOOL res;
6357 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6359 if (pName) {
6360 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6361 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6362 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6365 if (pMonitorName) {
6366 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6367 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6368 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6370 res = AddPortW(nameW, hWnd, monitorW);
6371 HeapFree(GetProcessHeap(), 0, nameW);
6372 HeapFree(GetProcessHeap(), 0, monitorW);
6373 return res;
6376 /******************************************************************************
6377 * AddPortW (WINSPOOL.@)
6379 * Add a Port for a specific Monitor
6381 * PARAMS
6382 * pName [I] Servername or NULL (local Computer)
6383 * hWnd [I] Handle to parent Window for the Dialog-Box
6384 * pMonitorName [I] Name of the Monitor that manage the Port
6386 * RETURNS
6387 * Success: TRUE
6388 * Failure: FALSE
6391 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6393 monitor_t * pm;
6394 monitor_t * pui;
6395 DWORD res;
6397 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6399 if (pName && pName[0]) {
6400 SetLastError(ERROR_INVALID_PARAMETER);
6401 return FALSE;
6404 if (!pMonitorName) {
6405 SetLastError(RPC_X_NULL_REF_POINTER);
6406 return FALSE;
6409 /* an empty Monitorname is Invalid */
6410 if (!pMonitorName[0]) {
6411 SetLastError(ERROR_NOT_SUPPORTED);
6412 return FALSE;
6415 pm = monitor_load(pMonitorName, NULL);
6416 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6417 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6418 TRACE("got %d with %u\n", res, GetLastError());
6419 res = TRUE;
6421 else
6423 pui = monitor_loadui(pm);
6424 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6425 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6426 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6427 TRACE("got %d with %u\n", res, GetLastError());
6428 res = TRUE;
6430 else
6432 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6433 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6435 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6436 SetLastError(ERROR_NOT_SUPPORTED);
6437 res = FALSE;
6439 monitor_unload(pui);
6441 monitor_unload(pm);
6442 TRACE("returning %d with %u\n", res, GetLastError());
6443 return res;
6446 /******************************************************************************
6447 * AddPortExA (WINSPOOL.@)
6449 * See AddPortExW.
6452 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6454 PORT_INFO_2W pi2W;
6455 PORT_INFO_2A * pi2A;
6456 LPWSTR nameW = NULL;
6457 LPWSTR monitorW = NULL;
6458 DWORD len;
6459 BOOL res;
6461 pi2A = (PORT_INFO_2A *) pBuffer;
6463 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6464 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6466 if ((level < 1) || (level > 2)) {
6467 SetLastError(ERROR_INVALID_LEVEL);
6468 return FALSE;
6471 if (!pi2A) {
6472 SetLastError(ERROR_INVALID_PARAMETER);
6473 return FALSE;
6476 if (pName) {
6477 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6478 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6479 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6482 if (pMonitorName) {
6483 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6484 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6485 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6488 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6490 if (pi2A->pPortName) {
6491 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6492 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6493 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6496 if (level > 1) {
6497 if (pi2A->pMonitorName) {
6498 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6499 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6500 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6503 if (pi2A->pDescription) {
6504 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6505 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6506 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6508 pi2W.fPortType = pi2A->fPortType;
6509 pi2W.Reserved = pi2A->Reserved;
6512 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6514 HeapFree(GetProcessHeap(), 0, nameW);
6515 HeapFree(GetProcessHeap(), 0, monitorW);
6516 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6517 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6518 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6519 return res;
6523 /******************************************************************************
6524 * AddPortExW (WINSPOOL.@)
6526 * Add a Port for a specific Monitor, without presenting a user interface
6528 * PARAMS
6529 * pName [I] Servername or NULL (local Computer)
6530 * level [I] Structure-Level (1 or 2) for pBuffer
6531 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6532 * pMonitorName [I] Name of the Monitor that manage the Port
6534 * RETURNS
6535 * Success: TRUE
6536 * Failure: FALSE
6539 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6541 PORT_INFO_2W * pi2;
6542 monitor_t * pm;
6543 DWORD res = FALSE;
6545 pi2 = (PORT_INFO_2W *) pBuffer;
6547 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6548 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6549 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6550 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6553 if ((level < 1) || (level > 2)) {
6554 SetLastError(ERROR_INVALID_LEVEL);
6555 return FALSE;
6558 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6559 SetLastError(ERROR_INVALID_PARAMETER);
6560 return FALSE;
6563 /* load the Monitor */
6564 pm = monitor_load(pMonitorName, NULL);
6565 if (!pm) {
6566 SetLastError(ERROR_INVALID_PARAMETER);
6567 return FALSE;
6570 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6571 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6572 TRACE("got %u with %u\n", res, GetLastError());
6574 else
6576 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6578 monitor_unload(pm);
6579 return res;
6582 /******************************************************************************
6583 * AddPrinterConnectionA (WINSPOOL.@)
6585 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6587 FIXME("%s\n", debugstr_a(pName));
6588 return FALSE;
6591 /******************************************************************************
6592 * AddPrinterConnectionW (WINSPOOL.@)
6594 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6596 FIXME("%s\n", debugstr_w(pName));
6597 return FALSE;
6600 /******************************************************************************
6601 * AddPrinterDriverExW (WINSPOOL.@)
6603 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6605 * PARAMS
6606 * pName [I] Servername or NULL (local Computer)
6607 * level [I] Level for the supplied DRIVER_INFO_*W struct
6608 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6609 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6611 * RESULTS
6612 * Success: TRUE
6613 * Failure: FALSE
6616 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6618 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6620 if ((backend == NULL) && !load_backend()) return FALSE;
6622 if (level < 2 || level == 5 || level == 7 || level > 8) {
6623 SetLastError(ERROR_INVALID_LEVEL);
6624 return FALSE;
6627 if (!pDriverInfo) {
6628 SetLastError(ERROR_INVALID_PARAMETER);
6629 return FALSE;
6632 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6635 /******************************************************************************
6636 * AddPrinterDriverExA (WINSPOOL.@)
6638 * See AddPrinterDriverExW.
6641 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6643 DRIVER_INFO_8A *diA;
6644 DRIVER_INFO_8W diW;
6645 LPWSTR nameW = NULL;
6646 DWORD lenA;
6647 DWORD len;
6648 DWORD res = FALSE;
6650 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6652 diA = (DRIVER_INFO_8A *) pDriverInfo;
6653 ZeroMemory(&diW, sizeof(diW));
6655 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6656 SetLastError(ERROR_INVALID_LEVEL);
6657 return FALSE;
6660 if (diA == NULL) {
6661 SetLastError(ERROR_INVALID_PARAMETER);
6662 return FALSE;
6665 /* convert servername to unicode */
6666 if (pName) {
6667 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6668 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6669 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6672 /* common fields */
6673 diW.cVersion = diA->cVersion;
6675 if (diA->pName) {
6676 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6677 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6678 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6681 if (diA->pEnvironment) {
6682 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6683 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6684 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6687 if (diA->pDriverPath) {
6688 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6689 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6690 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6693 if (diA->pDataFile) {
6694 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6695 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6696 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6699 if (diA->pConfigFile) {
6700 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6701 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6702 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6705 if ((Level > 2) && diA->pDependentFiles) {
6706 lenA = multi_sz_lenA(diA->pDependentFiles);
6707 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6708 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6709 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6712 if ((Level > 2) && diA->pMonitorName) {
6713 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6714 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6715 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6718 if ((Level > 3) && diA->pDefaultDataType) {
6719 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6720 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6721 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6724 if ((Level > 3) && diA->pszzPreviousNames) {
6725 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6726 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6727 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6728 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6731 if ((Level > 5) && diA->pszMfgName) {
6732 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6733 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6734 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6737 if ((Level > 5) && diA->pszOEMUrl) {
6738 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6739 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6740 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6743 if ((Level > 5) && diA->pszHardwareID) {
6744 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6745 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6746 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6749 if ((Level > 5) && diA->pszProvider) {
6750 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6751 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6755 if (Level > 7) {
6756 FIXME("level %u is incomplete\n", Level);
6759 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6760 TRACE("got %u with %u\n", res, GetLastError());
6761 HeapFree(GetProcessHeap(), 0, nameW);
6762 HeapFree(GetProcessHeap(), 0, diW.pName);
6763 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6764 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6765 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6766 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6767 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6768 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6769 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6770 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6771 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6772 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6773 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6774 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6776 TRACE("=> %u with %u\n", res, GetLastError());
6777 return res;
6780 /******************************************************************************
6781 * ConfigurePortA (WINSPOOL.@)
6783 * See ConfigurePortW.
6786 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6788 LPWSTR nameW = NULL;
6789 LPWSTR portW = NULL;
6790 INT len;
6791 DWORD res;
6793 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6795 /* convert servername to unicode */
6796 if (pName) {
6797 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6798 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6799 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6802 /* convert portname to unicode */
6803 if (pPortName) {
6804 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6805 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6806 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6809 res = ConfigurePortW(nameW, hWnd, portW);
6810 HeapFree(GetProcessHeap(), 0, nameW);
6811 HeapFree(GetProcessHeap(), 0, portW);
6812 return res;
6815 /******************************************************************************
6816 * ConfigurePortW (WINSPOOL.@)
6818 * Display the Configuration-Dialog for a specific Port
6820 * PARAMS
6821 * pName [I] Servername or NULL (local Computer)
6822 * hWnd [I] Handle to parent Window for the Dialog-Box
6823 * pPortName [I] Name of the Port, that should be configured
6825 * RETURNS
6826 * Success: TRUE
6827 * Failure: FALSE
6830 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6832 monitor_t * pm;
6833 monitor_t * pui;
6834 DWORD res;
6836 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6838 if (pName && pName[0]) {
6839 SetLastError(ERROR_INVALID_PARAMETER);
6840 return FALSE;
6843 if (!pPortName) {
6844 SetLastError(RPC_X_NULL_REF_POINTER);
6845 return FALSE;
6848 /* an empty Portname is Invalid, but can popup a Dialog */
6849 if (!pPortName[0]) {
6850 SetLastError(ERROR_NOT_SUPPORTED);
6851 return FALSE;
6854 pm = monitor_load_by_port(pPortName);
6855 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6856 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6857 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6858 TRACE("got %d with %u\n", res, GetLastError());
6860 else
6862 pui = monitor_loadui(pm);
6863 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6864 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6865 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6866 TRACE("got %d with %u\n", res, GetLastError());
6868 else
6870 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6871 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6873 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6874 SetLastError(ERROR_NOT_SUPPORTED);
6875 res = FALSE;
6877 monitor_unload(pui);
6879 monitor_unload(pm);
6881 TRACE("returning %d with %u\n", res, GetLastError());
6882 return res;
6885 /******************************************************************************
6886 * ConnectToPrinterDlg (WINSPOOL.@)
6888 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6890 FIXME("%p %x\n", hWnd, Flags);
6891 return NULL;
6894 /******************************************************************************
6895 * DeletePrinterConnectionA (WINSPOOL.@)
6897 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6899 FIXME("%s\n", debugstr_a(pName));
6900 return TRUE;
6903 /******************************************************************************
6904 * DeletePrinterConnectionW (WINSPOOL.@)
6906 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6908 FIXME("%s\n", debugstr_w(pName));
6909 return TRUE;
6912 /******************************************************************************
6913 * DeletePrinterDriverExW (WINSPOOL.@)
6915 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6916 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6918 HKEY hkey_drivers;
6919 BOOL ret = FALSE;
6921 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6922 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6924 if(pName && pName[0])
6926 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6927 SetLastError(ERROR_INVALID_PARAMETER);
6928 return FALSE;
6931 if(dwDeleteFlag)
6933 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6934 SetLastError(ERROR_INVALID_PARAMETER);
6935 return FALSE;
6938 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6940 if(!hkey_drivers)
6942 ERR("Can't open drivers key\n");
6943 return FALSE;
6946 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6947 ret = TRUE;
6949 RegCloseKey(hkey_drivers);
6951 return ret;
6954 /******************************************************************************
6955 * DeletePrinterDriverExA (WINSPOOL.@)
6957 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6958 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6960 UNICODE_STRING NameW, EnvW, DriverW;
6961 BOOL ret;
6963 asciitounicode(&NameW, pName);
6964 asciitounicode(&EnvW, pEnvironment);
6965 asciitounicode(&DriverW, pDriverName);
6967 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6969 RtlFreeUnicodeString(&DriverW);
6970 RtlFreeUnicodeString(&EnvW);
6971 RtlFreeUnicodeString(&NameW);
6973 return ret;
6976 /******************************************************************************
6977 * DeletePrinterDataExW (WINSPOOL.@)
6979 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6980 LPCWSTR pValueName)
6982 FIXME("%p %s %s\n", hPrinter,
6983 debugstr_w(pKeyName), debugstr_w(pValueName));
6984 return ERROR_INVALID_PARAMETER;
6987 /******************************************************************************
6988 * DeletePrinterDataExA (WINSPOOL.@)
6990 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6991 LPCSTR pValueName)
6993 FIXME("%p %s %s\n", hPrinter,
6994 debugstr_a(pKeyName), debugstr_a(pValueName));
6995 return ERROR_INVALID_PARAMETER;
6998 /******************************************************************************
6999 * DeletePrintProcessorA (WINSPOOL.@)
7001 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7003 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7004 debugstr_a(pPrintProcessorName));
7005 return TRUE;
7008 /******************************************************************************
7009 * DeletePrintProcessorW (WINSPOOL.@)
7011 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7013 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7014 debugstr_w(pPrintProcessorName));
7015 return TRUE;
7018 /******************************************************************************
7019 * DeletePrintProvidorA (WINSPOOL.@)
7021 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7023 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7024 debugstr_a(pPrintProviderName));
7025 return TRUE;
7028 /******************************************************************************
7029 * DeletePrintProvidorW (WINSPOOL.@)
7031 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7033 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7034 debugstr_w(pPrintProviderName));
7035 return TRUE;
7038 /******************************************************************************
7039 * EnumFormsA (WINSPOOL.@)
7041 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7042 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7044 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7045 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7046 return FALSE;
7049 /******************************************************************************
7050 * EnumFormsW (WINSPOOL.@)
7052 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7053 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7055 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7056 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7057 return FALSE;
7060 /*****************************************************************************
7061 * EnumMonitorsA [WINSPOOL.@]
7063 * See EnumMonitorsW.
7066 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7067 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7069 BOOL res;
7070 LPBYTE bufferW = NULL;
7071 LPWSTR nameW = NULL;
7072 DWORD needed = 0;
7073 DWORD numentries = 0;
7074 INT len;
7076 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7077 cbBuf, pcbNeeded, pcReturned);
7079 /* convert servername to unicode */
7080 if (pName) {
7081 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7082 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7083 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7085 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7086 needed = cbBuf * sizeof(WCHAR);
7087 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7088 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7090 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7091 if (pcbNeeded) needed = *pcbNeeded;
7092 /* HeapReAlloc return NULL, when bufferW was NULL */
7093 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7094 HeapAlloc(GetProcessHeap(), 0, needed);
7096 /* Try again with the large Buffer */
7097 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7099 numentries = pcReturned ? *pcReturned : 0;
7100 needed = 0;
7102 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7103 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7105 if (res) {
7106 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7107 DWORD entrysize = 0;
7108 DWORD index;
7109 LPSTR ptr;
7110 LPMONITOR_INFO_2W mi2w;
7111 LPMONITOR_INFO_2A mi2a;
7113 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7114 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7116 /* First pass: calculate the size for all Entries */
7117 mi2w = (LPMONITOR_INFO_2W) bufferW;
7118 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7119 index = 0;
7120 while (index < numentries) {
7121 index++;
7122 needed += entrysize; /* MONITOR_INFO_?A */
7123 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7125 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7126 NULL, 0, NULL, NULL);
7127 if (Level > 1) {
7128 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7129 NULL, 0, NULL, NULL);
7130 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7131 NULL, 0, NULL, NULL);
7133 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7134 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7135 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7138 /* check for errors and quit on failure */
7139 if (cbBuf < needed) {
7140 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7141 res = FALSE;
7142 goto emA_cleanup;
7144 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7145 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7146 cbBuf -= len ; /* free Bytes in the user-Buffer */
7147 mi2w = (LPMONITOR_INFO_2W) bufferW;
7148 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7149 index = 0;
7150 /* Second Pass: Fill the User Buffer (if we have one) */
7151 while ((index < numentries) && pMonitors) {
7152 index++;
7153 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7154 mi2a->pName = ptr;
7155 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7156 ptr, cbBuf , NULL, NULL);
7157 ptr += len;
7158 cbBuf -= len;
7159 if (Level > 1) {
7160 mi2a->pEnvironment = ptr;
7161 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7162 ptr, cbBuf, NULL, NULL);
7163 ptr += len;
7164 cbBuf -= len;
7166 mi2a->pDLLName = ptr;
7167 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7168 ptr, cbBuf, NULL, NULL);
7169 ptr += len;
7170 cbBuf -= len;
7172 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7173 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7174 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7177 emA_cleanup:
7178 if (pcbNeeded) *pcbNeeded = needed;
7179 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7181 HeapFree(GetProcessHeap(), 0, nameW);
7182 HeapFree(GetProcessHeap(), 0, bufferW);
7184 TRACE("returning %d with %d (%d byte for %d entries)\n",
7185 (res), GetLastError(), needed, numentries);
7187 return (res);
7191 /*****************************************************************************
7192 * EnumMonitorsW [WINSPOOL.@]
7194 * Enumerate available Port-Monitors
7196 * PARAMS
7197 * pName [I] Servername or NULL (local Computer)
7198 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7199 * pMonitors [O] PTR to Buffer that receives the Result
7200 * cbBuf [I] Size of Buffer at pMonitors
7201 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7202 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7204 * RETURNS
7205 * Success: TRUE
7206 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7209 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7210 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7213 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7214 cbBuf, pcbNeeded, pcReturned);
7216 if ((backend == NULL) && !load_backend()) return FALSE;
7218 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7219 SetLastError(RPC_X_NULL_REF_POINTER);
7220 return FALSE;
7223 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7226 /******************************************************************************
7227 * SpoolerInit (WINSPOOL.@)
7229 * Initialize the Spooler
7231 * RETURNS
7232 * Success: TRUE
7233 * Failure: FALSE
7235 * NOTES
7236 * The function fails on windows, when the spooler service is not running
7239 BOOL WINAPI SpoolerInit(void)
7242 if ((backend == NULL) && !load_backend()) return FALSE;
7243 return TRUE;
7246 /******************************************************************************
7247 * XcvDataW (WINSPOOL.@)
7249 * Execute commands in the Printmonitor DLL
7251 * PARAMS
7252 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7253 * pszDataName [i] Name of the command to execute
7254 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7255 * cbInputData [i] Size in Bytes of Buffer at pInputData
7256 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7257 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7258 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7259 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7261 * RETURNS
7262 * Success: TRUE
7263 * Failure: FALSE
7265 * NOTES
7266 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7267 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7269 * Minimal List of commands, that a Printmonitor DLL should support:
7271 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7272 *| "AddPort" : Add a Port
7273 *| "DeletePort": Delete a Port
7275 * Many Printmonitors support additional commands. Examples for localspl.dll:
7276 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7277 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7280 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7281 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7282 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7284 opened_printer_t *printer;
7286 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7287 pInputData, cbInputData, pOutputData,
7288 cbOutputData, pcbOutputNeeded, pdwStatus);
7290 printer = get_opened_printer(hXcv);
7291 if (!printer || (!printer->hXcv)) {
7292 SetLastError(ERROR_INVALID_HANDLE);
7293 return FALSE;
7296 if (!pcbOutputNeeded) {
7297 SetLastError(ERROR_INVALID_PARAMETER);
7298 return FALSE;
7301 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7302 SetLastError(RPC_X_NULL_REF_POINTER);
7303 return FALSE;
7306 *pcbOutputNeeded = 0;
7308 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7309 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7311 return TRUE;
7314 /*****************************************************************************
7315 * EnumPrinterDataA [WINSPOOL.@]
7318 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7319 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7320 DWORD cbData, LPDWORD pcbData )
7322 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7323 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7324 return ERROR_NO_MORE_ITEMS;
7327 /*****************************************************************************
7328 * EnumPrinterDataW [WINSPOOL.@]
7331 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7332 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7333 DWORD cbData, LPDWORD pcbData )
7335 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7336 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7337 return ERROR_NO_MORE_ITEMS;
7340 /*****************************************************************************
7341 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7344 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7345 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7346 LPDWORD pcbNeeded, LPDWORD pcReturned)
7348 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7349 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7350 pcbNeeded, pcReturned);
7351 return FALSE;
7354 /*****************************************************************************
7355 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7358 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7359 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7360 LPDWORD pcbNeeded, LPDWORD pcReturned)
7362 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7363 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7364 pcbNeeded, pcReturned);
7365 return FALSE;
7368 /*****************************************************************************
7369 * EnumPrintProcessorsA [WINSPOOL.@]
7372 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7373 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7375 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7376 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7377 return FALSE;
7380 /*****************************************************************************
7381 * EnumPrintProcessorsW [WINSPOOL.@]
7384 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7385 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7387 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7388 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7389 cbBuf, pcbNeeded, pcbReturned);
7390 return FALSE;
7393 /*****************************************************************************
7394 * ExtDeviceMode [WINSPOOL.@]
7397 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7398 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7399 DWORD fMode)
7401 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7402 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7403 debugstr_a(pProfile), fMode);
7404 return -1;
7407 /*****************************************************************************
7408 * FindClosePrinterChangeNotification [WINSPOOL.@]
7411 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7413 FIXME("Stub: %p\n", hChange);
7414 return TRUE;
7417 /*****************************************************************************
7418 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7421 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7422 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7424 FIXME("Stub: %p %x %x %p\n",
7425 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7426 return INVALID_HANDLE_VALUE;
7429 /*****************************************************************************
7430 * FindNextPrinterChangeNotification [WINSPOOL.@]
7433 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7434 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7436 FIXME("Stub: %p %p %p %p\n",
7437 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7438 return FALSE;
7441 /*****************************************************************************
7442 * FreePrinterNotifyInfo [WINSPOOL.@]
7445 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7447 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7448 return TRUE;
7451 /*****************************************************************************
7452 * string_to_buf
7454 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7455 * ansi depending on the unicode parameter.
7457 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7459 if(!str)
7461 *size = 0;
7462 return TRUE;
7465 if(unicode)
7467 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7468 if(*size <= cb)
7470 memcpy(ptr, str, *size);
7471 return TRUE;
7473 return FALSE;
7475 else
7477 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7478 if(*size <= cb)
7480 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7481 return TRUE;
7483 return FALSE;
7487 /*****************************************************************************
7488 * get_job_info_1
7490 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7491 LPDWORD pcbNeeded, BOOL unicode)
7493 DWORD size, left = cbBuf;
7494 BOOL space = (cbBuf > 0);
7495 LPBYTE ptr = buf;
7497 *pcbNeeded = 0;
7499 if(space)
7501 ji1->JobId = job->job_id;
7504 string_to_buf(job->document_title, ptr, left, &size, unicode);
7505 if(space && size <= left)
7507 ji1->pDocument = (LPWSTR)ptr;
7508 ptr += size;
7509 left -= size;
7511 else
7512 space = FALSE;
7513 *pcbNeeded += size;
7515 return space;
7518 /*****************************************************************************
7519 * get_job_info_2
7521 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7522 LPDWORD pcbNeeded, BOOL unicode)
7524 DWORD size, left = cbBuf;
7525 BOOL space = (cbBuf > 0);
7526 LPBYTE ptr = buf;
7528 *pcbNeeded = 0;
7530 if(space)
7532 ji2->JobId = job->job_id;
7535 string_to_buf(job->document_title, ptr, left, &size, unicode);
7536 if(space && size <= left)
7538 ji2->pDocument = (LPWSTR)ptr;
7539 ptr += size;
7540 left -= size;
7542 else
7543 space = FALSE;
7544 *pcbNeeded += size;
7546 return space;
7549 /*****************************************************************************
7550 * get_job_info
7552 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7553 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7555 BOOL ret = FALSE;
7556 DWORD needed = 0, size;
7557 job_t *job;
7558 LPBYTE ptr = pJob;
7560 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7562 EnterCriticalSection(&printer_handles_cs);
7563 job = get_job(hPrinter, JobId);
7564 if(!job)
7565 goto end;
7567 switch(Level)
7569 case 1:
7570 size = sizeof(JOB_INFO_1W);
7571 if(cbBuf >= size)
7573 cbBuf -= size;
7574 ptr += size;
7575 memset(pJob, 0, size);
7577 else
7578 cbBuf = 0;
7579 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7580 needed += size;
7581 break;
7583 case 2:
7584 size = sizeof(JOB_INFO_2W);
7585 if(cbBuf >= size)
7587 cbBuf -= size;
7588 ptr += size;
7589 memset(pJob, 0, size);
7591 else
7592 cbBuf = 0;
7593 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7594 needed += size;
7595 break;
7597 case 3:
7598 size = sizeof(JOB_INFO_3);
7599 if(cbBuf >= size)
7601 cbBuf -= size;
7602 memset(pJob, 0, size);
7603 ret = TRUE;
7605 else
7606 cbBuf = 0;
7607 needed = size;
7608 break;
7610 default:
7611 SetLastError(ERROR_INVALID_LEVEL);
7612 goto end;
7614 if(pcbNeeded)
7615 *pcbNeeded = needed;
7616 end:
7617 LeaveCriticalSection(&printer_handles_cs);
7618 return ret;
7621 /*****************************************************************************
7622 * GetJobA [WINSPOOL.@]
7625 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7626 DWORD cbBuf, LPDWORD pcbNeeded)
7628 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7631 /*****************************************************************************
7632 * GetJobW [WINSPOOL.@]
7635 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7636 DWORD cbBuf, LPDWORD pcbNeeded)
7638 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7641 /*****************************************************************************
7642 * schedule_lpr
7644 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7646 char *unixname, *queue, *cmd;
7647 char fmt[] = "lpr -P%s %s";
7648 DWORD len;
7650 if(!(unixname = wine_get_unix_file_name(filename)))
7651 return FALSE;
7653 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7654 queue = HeapAlloc(GetProcessHeap(), 0, len);
7655 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7657 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7658 sprintf(cmd, fmt, queue, unixname);
7660 TRACE("printing with: %s\n", cmd);
7661 system(cmd);
7663 HeapFree(GetProcessHeap(), 0, cmd);
7664 HeapFree(GetProcessHeap(), 0, queue);
7665 HeapFree(GetProcessHeap(), 0, unixname);
7666 return TRUE;
7669 /*****************************************************************************
7670 * schedule_cups
7672 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7674 #ifdef SONAME_LIBCUPS
7675 if(pcupsPrintFile)
7677 char *unixname, *queue, *doc_titleA;
7678 DWORD len;
7679 BOOL ret;
7681 if(!(unixname = wine_get_unix_file_name(filename)))
7682 return FALSE;
7684 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7685 queue = HeapAlloc(GetProcessHeap(), 0, len);
7686 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7688 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7689 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7690 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7692 TRACE("printing via cups\n");
7693 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7694 HeapFree(GetProcessHeap(), 0, doc_titleA);
7695 HeapFree(GetProcessHeap(), 0, queue);
7696 HeapFree(GetProcessHeap(), 0, unixname);
7697 return ret;
7699 else
7700 #endif
7702 return schedule_lpr(printer_name, filename);
7706 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7708 LPWSTR filename;
7710 switch(msg)
7712 case WM_INITDIALOG:
7713 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7714 return TRUE;
7716 case WM_COMMAND:
7717 if(HIWORD(wparam) == BN_CLICKED)
7719 if(LOWORD(wparam) == IDOK)
7721 HANDLE hf;
7722 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7723 LPWSTR *output;
7725 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7726 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7728 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7730 WCHAR caption[200], message[200];
7731 int mb_ret;
7733 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7734 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7735 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7736 if(mb_ret == IDCANCEL)
7738 HeapFree(GetProcessHeap(), 0, filename);
7739 return TRUE;
7742 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7743 if(hf == INVALID_HANDLE_VALUE)
7745 WCHAR caption[200], message[200];
7747 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7748 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7749 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7750 HeapFree(GetProcessHeap(), 0, filename);
7751 return TRUE;
7753 CloseHandle(hf);
7754 DeleteFileW(filename);
7755 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7756 *output = filename;
7757 EndDialog(hwnd, IDOK);
7758 return TRUE;
7760 if(LOWORD(wparam) == IDCANCEL)
7762 EndDialog(hwnd, IDCANCEL);
7763 return TRUE;
7766 return FALSE;
7768 return FALSE;
7771 /*****************************************************************************
7772 * get_filename
7774 static BOOL get_filename(LPWSTR *filename)
7776 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7777 file_dlg_proc, (LPARAM)filename) == IDOK;
7780 /*****************************************************************************
7781 * schedule_file
7783 static BOOL schedule_file(LPCWSTR filename)
7785 LPWSTR output = NULL;
7787 if(get_filename(&output))
7789 TRACE("copy to %s\n", debugstr_w(output));
7790 CopyFileW(filename, output, FALSE);
7791 HeapFree(GetProcessHeap(), 0, output);
7792 return TRUE;
7794 return FALSE;
7797 /*****************************************************************************
7798 * schedule_pipe
7800 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7802 #ifdef HAVE_FORK
7803 char *unixname, *cmdA;
7804 DWORD len;
7805 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7806 BOOL ret = FALSE;
7807 char buf[1024];
7809 if(!(unixname = wine_get_unix_file_name(filename)))
7810 return FALSE;
7812 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7813 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7814 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7816 TRACE("printing with: %s\n", cmdA);
7818 if((file_fd = open(unixname, O_RDONLY)) == -1)
7819 goto end;
7821 if (pipe(fds))
7823 ERR("pipe() failed!\n");
7824 goto end;
7827 if (fork() == 0)
7829 close(0);
7830 dup2(fds[0], 0);
7831 close(fds[1]);
7833 /* reset signals that we previously set to SIG_IGN */
7834 signal(SIGPIPE, SIG_DFL);
7835 signal(SIGCHLD, SIG_DFL);
7837 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7838 _exit(1);
7841 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7842 write(fds[1], buf, no_read);
7844 ret = TRUE;
7846 end:
7847 if(file_fd != -1) close(file_fd);
7848 if(fds[0] != -1) close(fds[0]);
7849 if(fds[1] != -1) close(fds[1]);
7851 HeapFree(GetProcessHeap(), 0, cmdA);
7852 HeapFree(GetProcessHeap(), 0, unixname);
7853 return ret;
7854 #else
7855 return FALSE;
7856 #endif
7859 /*****************************************************************************
7860 * schedule_unixfile
7862 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7864 int in_fd, out_fd, no_read;
7865 char buf[1024];
7866 BOOL ret = FALSE;
7867 char *unixname, *outputA;
7868 DWORD len;
7870 if(!(unixname = wine_get_unix_file_name(filename)))
7871 return FALSE;
7873 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7874 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7875 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7877 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7878 in_fd = open(unixname, O_RDONLY);
7879 if(out_fd == -1 || in_fd == -1)
7880 goto end;
7882 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7883 write(out_fd, buf, no_read);
7885 ret = TRUE;
7886 end:
7887 if(in_fd != -1) close(in_fd);
7888 if(out_fd != -1) close(out_fd);
7889 HeapFree(GetProcessHeap(), 0, outputA);
7890 HeapFree(GetProcessHeap(), 0, unixname);
7891 return ret;
7894 /*****************************************************************************
7895 * ScheduleJob [WINSPOOL.@]
7898 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7900 opened_printer_t *printer;
7901 BOOL ret = FALSE;
7902 struct list *cursor, *cursor2;
7904 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7905 EnterCriticalSection(&printer_handles_cs);
7906 printer = get_opened_printer(hPrinter);
7907 if(!printer)
7908 goto end;
7910 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7912 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7913 HANDLE hf;
7915 if(job->job_id != dwJobID) continue;
7917 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7918 if(hf != INVALID_HANDLE_VALUE)
7920 PRINTER_INFO_5W *pi5;
7921 DWORD needed;
7922 HKEY hkey;
7923 WCHAR output[1024];
7924 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7925 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7927 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7928 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7929 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7930 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7931 debugstr_w(pi5->pPortName));
7933 output[0] = 0;
7935 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7936 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7938 DWORD type, count = sizeof(output);
7939 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7940 RegCloseKey(hkey);
7942 if(output[0] == '|')
7944 schedule_pipe(output + 1, job->filename);
7946 else if(output[0])
7948 schedule_unixfile(output, job->filename);
7950 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7952 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7954 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7956 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7958 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7960 schedule_file(job->filename);
7962 else
7964 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7966 HeapFree(GetProcessHeap(), 0, pi5);
7967 CloseHandle(hf);
7968 DeleteFileW(job->filename);
7970 list_remove(cursor);
7971 HeapFree(GetProcessHeap(), 0, job->document_title);
7972 HeapFree(GetProcessHeap(), 0, job->filename);
7973 HeapFree(GetProcessHeap(), 0, job);
7974 ret = TRUE;
7975 break;
7977 end:
7978 LeaveCriticalSection(&printer_handles_cs);
7979 return ret;
7982 /*****************************************************************************
7983 * StartDocDlgA [WINSPOOL.@]
7985 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7987 UNICODE_STRING usBuffer;
7988 DOCINFOW docW;
7989 LPWSTR retW;
7990 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7991 LPSTR ret = NULL;
7993 docW.cbSize = sizeof(docW);
7994 if (doc->lpszDocName)
7996 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7997 if (!(docW.lpszDocName = docnameW)) return NULL;
7999 if (doc->lpszOutput)
8001 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8002 if (!(docW.lpszOutput = outputW)) return NULL;
8004 if (doc->lpszDatatype)
8006 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8007 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8009 docW.fwType = doc->fwType;
8011 retW = StartDocDlgW(hPrinter, &docW);
8013 if(retW)
8015 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8016 ret = HeapAlloc(GetProcessHeap(), 0, len);
8017 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8018 HeapFree(GetProcessHeap(), 0, retW);
8021 HeapFree(GetProcessHeap(), 0, datatypeW);
8022 HeapFree(GetProcessHeap(), 0, outputW);
8023 HeapFree(GetProcessHeap(), 0, docnameW);
8025 return ret;
8028 /*****************************************************************************
8029 * StartDocDlgW [WINSPOOL.@]
8031 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8032 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8033 * port is "FILE:". Also returns the full path if passed a relative path.
8035 * The caller should free the returned string from the process heap.
8037 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8039 LPWSTR ret = NULL;
8040 DWORD len, attr;
8042 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8044 PRINTER_INFO_5W *pi5;
8045 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8046 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8047 return NULL;
8048 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8049 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8050 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8052 HeapFree(GetProcessHeap(), 0, pi5);
8053 return NULL;
8055 HeapFree(GetProcessHeap(), 0, pi5);
8058 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8060 LPWSTR name;
8062 if (get_filename(&name))
8064 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8066 HeapFree(GetProcessHeap(), 0, name);
8067 return NULL;
8069 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8070 GetFullPathNameW(name, len, ret, NULL);
8071 HeapFree(GetProcessHeap(), 0, name);
8073 return ret;
8076 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8077 return NULL;
8079 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8080 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8082 attr = GetFileAttributesW(ret);
8083 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8085 HeapFree(GetProcessHeap(), 0, ret);
8086 ret = NULL;
8088 return ret;