gdi32: PATH_ExtTextOut remove incorrect shift to DC origin.
[wine/hacks.git] / dlls / winspool.drv / info.c
blob81609574b38d3c676c69a0d66f7e48f56bcb8745
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-2009 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_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
199 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
200 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
201 static const WCHAR subdir_x64W[] = {'x','6','4',0};
202 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
203 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
204 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
205 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
206 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
208 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
209 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
211 static const WCHAR backslashW[] = {'\\',0};
212 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
213 'i','o','n',' ','F','i','l','e',0};
214 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
215 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
216 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
217 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
218 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
219 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
220 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
221 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
222 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
223 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
224 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
225 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
226 static const WCHAR NameW[] = {'N','a','m','e',0};
227 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
228 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
229 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
230 static const WCHAR PortW[] = {'P','o','r','t',0};
231 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
232 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
233 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
234 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
235 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
236 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
237 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
238 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
239 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
240 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
241 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
242 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
243 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
244 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
245 static const WCHAR emptyStringW[] = {0};
246 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
247 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
249 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
251 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
252 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
253 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
255 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
256 'D','o','c','u','m','e','n','t',0};
258 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
259 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
260 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
261 0, sizeof(DRIVER_INFO_8W)};
264 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
265 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
266 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
267 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
268 sizeof(PRINTER_INFO_9W)};
270 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
271 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
272 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
274 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
276 /******************************************************************
277 * validate the user-supplied printing-environment [internal]
279 * PARAMS
280 * env [I] PTR to Environment-String or NULL
282 * RETURNS
283 * Failure: NULL
284 * Success: PTR to printenv_t
286 * NOTES
287 * An empty string is handled the same way as NULL.
288 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
292 static const printenv_t * validate_envW(LPCWSTR env)
294 const printenv_t *result = NULL;
295 unsigned int i;
297 TRACE("testing %s\n", debugstr_w(env));
298 if (env && env[0])
300 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
302 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
304 result = all_printenv[i];
305 break;
309 if (result == NULL) {
310 FIXME("unsupported Environment: %s\n", debugstr_w(env));
311 SetLastError(ERROR_INVALID_ENVIRONMENT);
313 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
315 else
317 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
319 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
321 return result;
325 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
326 if passed a NULL string. This returns NULLs to the result.
328 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
330 if ( (src) )
332 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
333 return usBufferPtr->Buffer;
335 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
336 return NULL;
339 static LPWSTR strdupW(LPCWSTR p)
341 LPWSTR ret;
342 DWORD len;
344 if(!p) return NULL;
345 len = (strlenW(p) + 1) * sizeof(WCHAR);
346 ret = HeapAlloc(GetProcessHeap(), 0, len);
347 memcpy(ret, p, len);
348 return ret;
351 static LPSTR strdupWtoA( LPCWSTR str )
353 LPSTR ret;
354 INT len;
356 if (!str) return NULL;
357 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
358 ret = HeapAlloc( GetProcessHeap(), 0, len );
359 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
360 return ret;
363 /******************************************************************
364 * Return the number of bytes for an multi_sz string.
365 * The result includes all \0s
366 * (specifically the extra \0, that is needed as multi_sz terminator).
368 #if 0
369 static int multi_sz_lenW(const WCHAR *str)
371 const WCHAR *ptr = str;
372 if(!str) return 0;
375 ptr += lstrlenW(ptr) + 1;
376 } while(*ptr);
378 return (ptr - str + 1) * sizeof(WCHAR);
380 #endif
381 /* ################################ */
383 static int multi_sz_lenA(const char *str)
385 const char *ptr = str;
386 if(!str) return 0;
389 ptr += lstrlenA(ptr) + 1;
390 } while(*ptr);
392 return ptr - str + 1;
395 static void
396 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
397 char qbuf[200];
399 /* If forcing, or no profile string entry for device yet, set the entry
401 * The always change entry if not WINEPS yet is discussable.
403 if (force ||
404 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
405 !strcmp(qbuf,"*") ||
406 !strstr(qbuf,"WINEPS.DRV")
408 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
409 HKEY hkey;
411 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
412 WriteProfileStringA("windows","device",buf);
413 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
414 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
415 RegCloseKey(hkey);
417 HeapFree(GetProcessHeap(),0,buf);
421 static BOOL add_printer_driver(const char *name)
423 DRIVER_INFO_3A di3a;
425 static char driver_9x[] = "wineps16.drv",
426 driver_nt[] = "wineps.drv",
427 env_9x[] = "Windows 4.0",
428 env_nt[] = "Windows NT x86",
429 data_file[] = "generic.ppd",
430 default_data_type[] = "RAW";
432 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
433 di3a.cVersion = 3;
434 di3a.pName = (char *)name;
435 di3a.pEnvironment = env_nt;
436 di3a.pDriverPath = driver_nt;
437 di3a.pDataFile = data_file;
438 di3a.pConfigFile = driver_nt;
439 di3a.pDefaultDataType = default_data_type;
441 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
442 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
444 di3a.cVersion = 0;
445 di3a.pEnvironment = env_9x;
446 di3a.pDriverPath = driver_9x;
447 di3a.pConfigFile = driver_9x;
448 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
449 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
451 return TRUE;
454 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
455 debugstr_a(di3a.pEnvironment), GetLastError());
456 return FALSE;
459 #ifdef SONAME_LIBCUPS
460 static typeof(cupsFreeDests) *pcupsFreeDests;
461 static typeof(cupsGetDests) *pcupsGetDests;
462 static typeof(cupsGetPPD) *pcupsGetPPD;
463 static typeof(cupsPrintFile) *pcupsPrintFile;
464 static void *cupshandle;
466 static BOOL CUPS_LoadPrinters(void)
468 int i, nrofdests;
469 BOOL hadprinter = FALSE, haddefault = FALSE;
470 cups_dest_t *dests;
471 PRINTER_INFO_2A pinfo2a;
472 char *port,*devline;
473 HKEY hkeyPrinter, hkeyPrinters, hkey;
474 char loaderror[256];
476 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
477 if (!cupshandle) {
478 TRACE("%s\n", loaderror);
479 return FALSE;
481 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
483 #define DYNCUPS(x) \
484 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
485 if (!p##x) return FALSE;
487 DYNCUPS(cupsFreeDests);
488 DYNCUPS(cupsGetPPD);
489 DYNCUPS(cupsGetDests);
490 DYNCUPS(cupsPrintFile);
491 #undef DYNCUPS
493 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
494 ERROR_SUCCESS) {
495 ERR("Can't create Printers key\n");
496 return FALSE;
499 nrofdests = pcupsGetDests(&dests);
500 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
501 for (i=0;i<nrofdests;i++) {
502 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
503 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
504 sprintf(port,"LPR:%s", dests[i].name);
505 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
506 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
507 sprintf(devline, "WINEPS.DRV,%s", port);
508 WriteProfileStringA("devices", dests[i].name, devline);
509 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
510 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
511 RegCloseKey(hkey);
514 lstrcatA(devline, ",15,45");
515 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
516 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
517 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
518 RegCloseKey(hkey);
521 HeapFree(GetProcessHeap(), 0, devline);
523 TRACE("Printer %d: %s\n", i, dests[i].name);
524 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
525 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
526 and continue */
527 TRACE("Printer already exists\n");
528 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
529 RegCloseKey(hkeyPrinter);
530 } else {
531 static CHAR data_type[] = "RAW",
532 print_proc[] = "WinPrint",
533 comment[] = "WINEPS Printer using CUPS",
534 location[] = "<physical location of printer>",
535 params[] = "<parameters?>",
536 share_name[] = "<share name?>",
537 sep_file[] = "<sep file?>";
539 add_printer_driver(dests[i].name);
541 memset(&pinfo2a,0,sizeof(pinfo2a));
542 pinfo2a.pPrinterName = dests[i].name;
543 pinfo2a.pDatatype = data_type;
544 pinfo2a.pPrintProcessor = print_proc;
545 pinfo2a.pDriverName = dests[i].name;
546 pinfo2a.pComment = comment;
547 pinfo2a.pLocation = location;
548 pinfo2a.pPortName = port;
549 pinfo2a.pParameters = params;
550 pinfo2a.pShareName = share_name;
551 pinfo2a.pSepFile = sep_file;
553 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
554 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
555 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
558 HeapFree(GetProcessHeap(),0,port);
560 hadprinter = TRUE;
561 if (dests[i].is_default) {
562 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
563 haddefault = TRUE;
566 if (hadprinter & !haddefault)
567 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
568 pcupsFreeDests(nrofdests, dests);
569 RegCloseKey(hkeyPrinters);
570 return hadprinter;
572 #endif
574 static BOOL
575 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
576 PRINTER_INFO_2A pinfo2a;
577 char *e,*s,*name,*prettyname,*devname;
578 BOOL ret = FALSE, set_default = FALSE;
579 char *port = NULL, *devline,*env_default;
580 HKEY hkeyPrinter, hkeyPrinters, hkey;
582 while (isspace(*pent)) pent++;
583 s = strchr(pent,':');
584 if(s) *s='\0';
585 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
586 strcpy(name,pent);
587 if(s) {
588 *s=':';
589 pent = s;
590 } else
591 pent = "";
593 TRACE("name=%s entry=%s\n",name, pent);
595 if(ispunct(*name)) { /* a tc entry, not a real printer */
596 TRACE("skipping tc entry\n");
597 goto end;
600 if(strstr(pent,":server")) { /* server only version so skip */
601 TRACE("skipping server entry\n");
602 goto end;
605 /* Determine whether this is a postscript printer. */
607 ret = TRUE;
608 env_default = getenv("PRINTER");
609 prettyname = name;
610 /* Get longest name, usually the one at the right for later display. */
611 while((s=strchr(prettyname,'|'))) {
612 *s = '\0';
613 e = s;
614 while(isspace(*--e)) *e = '\0';
615 TRACE("\t%s\n", debugstr_a(prettyname));
616 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
617 for(prettyname = s+1; isspace(*prettyname); prettyname++)
620 e = prettyname + strlen(prettyname);
621 while(isspace(*--e)) *e = '\0';
622 TRACE("\t%s\n", debugstr_a(prettyname));
623 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
625 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
626 * if it is too long, we use it as comment below. */
627 devname = prettyname;
628 if (strlen(devname)>=CCHDEVICENAME-1)
629 devname = name;
630 if (strlen(devname)>=CCHDEVICENAME-1) {
631 ret = FALSE;
632 goto end;
635 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
636 sprintf(port,"LPR:%s",name);
638 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
639 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
640 sprintf(devline, "WINEPS.DRV,%s", port);
641 WriteProfileStringA("devices", devname, devline);
642 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
643 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
644 RegCloseKey(hkey);
647 lstrcatA(devline, ",15,45");
648 WriteProfileStringA("PrinterPorts", devname, devline);
649 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
650 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
651 RegCloseKey(hkey);
654 HeapFree(GetProcessHeap(),0,devline);
656 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
657 ERROR_SUCCESS) {
658 ERR("Can't create Printers key\n");
659 ret = FALSE;
660 goto end;
662 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
663 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
664 and continue */
665 TRACE("Printer already exists\n");
666 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
667 RegCloseKey(hkeyPrinter);
668 } else {
669 static CHAR data_type[] = "RAW",
670 print_proc[] = "WinPrint",
671 comment[] = "WINEPS Printer using LPR",
672 params[] = "<parameters?>",
673 share_name[] = "<share name?>",
674 sep_file[] = "<sep file?>";
676 add_printer_driver(devname);
678 memset(&pinfo2a,0,sizeof(pinfo2a));
679 pinfo2a.pPrinterName = devname;
680 pinfo2a.pDatatype = data_type;
681 pinfo2a.pPrintProcessor = print_proc;
682 pinfo2a.pDriverName = devname;
683 pinfo2a.pComment = comment;
684 pinfo2a.pLocation = prettyname;
685 pinfo2a.pPortName = port;
686 pinfo2a.pParameters = params;
687 pinfo2a.pShareName = share_name;
688 pinfo2a.pSepFile = sep_file;
690 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
691 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
692 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
695 RegCloseKey(hkeyPrinters);
697 if (isfirst || set_default)
698 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
700 end:
701 HeapFree(GetProcessHeap(), 0, port);
702 HeapFree(GetProcessHeap(), 0, name);
703 return ret;
706 static BOOL
707 PRINTCAP_LoadPrinters(void) {
708 BOOL hadprinter = FALSE;
709 char buf[200];
710 FILE *f;
711 char *pent = NULL;
712 BOOL had_bash = FALSE;
714 f = fopen("/etc/printcap","r");
715 if (!f)
716 return FALSE;
718 while(fgets(buf,sizeof(buf),f)) {
719 char *start, *end;
721 end=strchr(buf,'\n');
722 if (end) *end='\0';
724 start = buf;
725 while(isspace(*start)) start++;
726 if(*start == '#' || *start == '\0')
727 continue;
729 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
730 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
731 HeapFree(GetProcessHeap(),0,pent);
732 pent = NULL;
735 if (end && *--end == '\\') {
736 *end = '\0';
737 had_bash = TRUE;
738 } else
739 had_bash = FALSE;
741 if (pent) {
742 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
743 strcat(pent,start);
744 } else {
745 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
746 strcpy(pent,start);
750 if(pent) {
751 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
752 HeapFree(GetProcessHeap(),0,pent);
754 fclose(f);
755 return hadprinter;
758 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
760 if (value)
761 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
762 (lstrlenW(value) + 1) * sizeof(WCHAR));
763 else
764 return ERROR_FILE_NOT_FOUND;
767 /******************************************************************
768 * monitor_unload [internal]
770 * release a printmonitor and unload it from memory, when needed
773 static void monitor_unload(monitor_t * pm)
775 if (pm == NULL) return;
776 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
778 EnterCriticalSection(&monitor_handles_cs);
780 if (pm->refcount) pm->refcount--;
782 if (pm->refcount == 0) {
783 list_remove(&pm->entry);
784 FreeLibrary(pm->hdll);
785 HeapFree(GetProcessHeap(), 0, pm->name);
786 HeapFree(GetProcessHeap(), 0, pm->dllname);
787 HeapFree(GetProcessHeap(), 0, pm);
789 LeaveCriticalSection(&monitor_handles_cs);
792 /******************************************************************
793 * monitor_load [internal]
795 * load a printmonitor, get the dllname from the registry, when needed
796 * initialize the monitor and dump found function-pointers
798 * On failure, SetLastError() is called and NULL is returned
801 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
803 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
804 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
805 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
806 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
807 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
809 monitor_t * pm = NULL;
810 monitor_t * cursor;
811 LPWSTR regroot = NULL;
812 LPWSTR driver = dllname;
814 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
815 /* Is the Monitor already loaded? */
816 EnterCriticalSection(&monitor_handles_cs);
818 if (name) {
819 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
821 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
822 pm = cursor;
823 break;
828 if (pm == NULL) {
829 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
830 if (pm == NULL) goto cleanup;
831 list_add_tail(&monitor_handles, &pm->entry);
833 pm->refcount++;
835 if (pm->name == NULL) {
836 /* Load the monitor */
837 LPMONITOREX pmonitorEx;
838 DWORD len;
840 if (name) {
841 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
842 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
845 if (regroot) {
846 lstrcpyW(regroot, MonitorsW);
847 lstrcatW(regroot, name);
848 /* Get the Driver from the Registry */
849 if (driver == NULL) {
850 HKEY hroot;
851 DWORD namesize;
852 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
853 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
854 &namesize) == ERROR_SUCCESS) {
855 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
856 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
858 RegCloseKey(hroot);
863 pm->name = strdupW(name);
864 pm->dllname = strdupW(driver);
866 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
867 monitor_unload(pm);
868 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
869 pm = NULL;
870 goto cleanup;
873 pm->hdll = LoadLibraryW(driver);
874 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
876 if (pm->hdll == NULL) {
877 monitor_unload(pm);
878 SetLastError(ERROR_MOD_NOT_FOUND);
879 pm = NULL;
880 goto cleanup;
883 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
884 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
885 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
886 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
887 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
890 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
891 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
892 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
893 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
894 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
896 if (pInitializePrintMonitorUI != NULL) {
897 pm->monitorUI = pInitializePrintMonitorUI();
898 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
899 if (pm->monitorUI) {
900 TRACE( "0x%08x: dwMonitorSize (%d)\n",
901 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
906 if (pInitializePrintMonitor && regroot) {
907 pmonitorEx = pInitializePrintMonitor(regroot);
908 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
909 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
911 if (pmonitorEx) {
912 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
913 pm->monitor = &(pmonitorEx->Monitor);
917 if (pm->monitor) {
918 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
922 if (!pm->monitor && regroot) {
923 if (pInitializePrintMonitor2 != NULL) {
924 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
926 if (pInitializeMonitorEx != NULL) {
927 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
929 if (pInitializeMonitor != NULL) {
930 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
933 if (!pm->monitor && !pm->monitorUI) {
934 monitor_unload(pm);
935 SetLastError(ERROR_PROC_NOT_FOUND);
936 pm = NULL;
939 cleanup:
940 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
941 pm->refcount++;
942 pm_localport = pm;
944 LeaveCriticalSection(&monitor_handles_cs);
945 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
946 HeapFree(GetProcessHeap(), 0, regroot);
947 TRACE("=> %p\n", pm);
948 return pm;
951 /******************************************************************
952 * monitor_loadui [internal]
954 * load the userinterface-dll for a given portmonitor
956 * On failure, NULL is returned
959 static monitor_t * monitor_loadui(monitor_t * pm)
961 monitor_t * pui = NULL;
962 LPWSTR buffer[MAX_PATH];
963 HANDLE hXcv;
964 DWORD len;
965 DWORD res;
967 if (pm == NULL) return NULL;
968 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
970 /* Try the Portmonitor first; works for many monitors */
971 if (pm->monitorUI) {
972 EnterCriticalSection(&monitor_handles_cs);
973 pm->refcount++;
974 LeaveCriticalSection(&monitor_handles_cs);
975 return pm;
978 /* query the userinterface-dllname from the Portmonitor */
979 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
980 /* building (",XcvMonitor %s",pm->name) not needed yet */
981 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
982 TRACE("got %u with %p\n", res, hXcv);
983 if (res) {
984 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
985 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
986 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
987 pm->monitor->pfnXcvClosePort(hXcv);
990 return pui;
994 /******************************************************************
995 * monitor_load_by_port [internal]
997 * load a printmonitor for a given port
999 * On failure, NULL is returned
1002 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1004 HKEY hroot;
1005 HKEY hport;
1006 LPWSTR buffer;
1007 monitor_t * pm = NULL;
1008 DWORD registered = 0;
1009 DWORD id = 0;
1010 DWORD len;
1012 TRACE("(%s)\n", debugstr_w(portname));
1014 /* Try the Local Monitor first */
1015 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1016 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1017 /* found the portname */
1018 RegCloseKey(hroot);
1019 return monitor_load(LocalPortW, NULL);
1021 RegCloseKey(hroot);
1024 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1025 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1026 if (buffer == NULL) return NULL;
1028 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1029 EnterCriticalSection(&monitor_handles_cs);
1030 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1032 while ((pm == NULL) && (id < registered)) {
1033 buffer[0] = '\0';
1034 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1035 TRACE("testing %s\n", debugstr_w(buffer));
1036 len = lstrlenW(buffer);
1037 lstrcatW(buffer, bs_Ports_bsW);
1038 lstrcatW(buffer, portname);
1039 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1040 RegCloseKey(hport);
1041 buffer[len] = '\0'; /* use only the Monitor-Name */
1042 pm = monitor_load(buffer, NULL);
1044 id++;
1046 LeaveCriticalSection(&monitor_handles_cs);
1047 RegCloseKey(hroot);
1049 HeapFree(GetProcessHeap(), 0, buffer);
1050 return pm;
1053 /******************************************************************
1054 * get_servername_from_name (internal)
1056 * for an external server, a copy of the serverpart from the full name is returned
1059 static LPWSTR get_servername_from_name(LPCWSTR name)
1061 LPWSTR server;
1062 LPWSTR ptr;
1063 WCHAR buffer[MAX_PATH];
1064 DWORD len;
1066 if (name == NULL) return NULL;
1067 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1069 server = strdupW(&name[2]); /* skip over both backslash */
1070 if (server == NULL) return NULL;
1072 /* strip '\' and the printername */
1073 ptr = strchrW(server, '\\');
1074 if (ptr) ptr[0] = '\0';
1076 TRACE("found %s\n", debugstr_w(server));
1078 len = sizeof(buffer)/sizeof(buffer[0]);
1079 if (GetComputerNameW(buffer, &len)) {
1080 if (lstrcmpW(buffer, server) == 0) {
1081 /* The requested Servername is our computername */
1082 HeapFree(GetProcessHeap(), 0, server);
1083 return NULL;
1086 return server;
1089 /******************************************************************
1090 * get_basename_from_name (internal)
1092 * skip over the serverpart from the full name
1095 static LPCWSTR get_basename_from_name(LPCWSTR name)
1097 if (name == NULL) return NULL;
1098 if ((name[0] == '\\') && (name[1] == '\\')) {
1099 /* skip over the servername and search for the following '\' */
1100 name = strchrW(&name[2], '\\');
1101 if ((name) && (name[1])) {
1102 /* found a separator ('\') followed by a name:
1103 skip over the separator and return the rest */
1104 name++;
1106 else
1108 /* no basename present (we found only a servername) */
1109 return NULL;
1112 return name;
1115 /******************************************************************
1116 * get_opened_printer_entry
1117 * Get the first place empty in the opened printer table
1119 * ToDo:
1120 * - pDefault is ignored
1122 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1124 UINT_PTR handle = nb_printer_handles, i;
1125 jobqueue_t *queue = NULL;
1126 opened_printer_t *printer = NULL;
1127 LPWSTR servername;
1128 LPCWSTR printername;
1129 HKEY hkeyPrinters;
1130 HKEY hkeyPrinter;
1131 DWORD len;
1133 servername = get_servername_from_name(name);
1134 if (servername) {
1135 FIXME("server %s not supported\n", debugstr_w(servername));
1136 HeapFree(GetProcessHeap(), 0, servername);
1137 SetLastError(ERROR_INVALID_PRINTER_NAME);
1138 return NULL;
1141 printername = get_basename_from_name(name);
1142 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1144 /* an empty printername is invalid */
1145 if (printername && (!printername[0])) {
1146 SetLastError(ERROR_INVALID_PARAMETER);
1147 return NULL;
1150 EnterCriticalSection(&printer_handles_cs);
1152 for (i = 0; i < nb_printer_handles; i++)
1154 if (!printer_handles[i])
1156 if(handle == nb_printer_handles)
1157 handle = i;
1159 else
1161 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1162 queue = printer_handles[i]->queue;
1166 if (handle >= nb_printer_handles)
1168 opened_printer_t **new_array;
1169 if (printer_handles)
1170 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1171 (nb_printer_handles + 16) * sizeof(*new_array) );
1172 else
1173 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1174 (nb_printer_handles + 16) * sizeof(*new_array) );
1176 if (!new_array)
1178 handle = 0;
1179 goto end;
1181 printer_handles = new_array;
1182 nb_printer_handles += 16;
1185 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1187 handle = 0;
1188 goto end;
1192 /* clone the base name. This is NULL for the printserver */
1193 printer->printername = strdupW(printername);
1195 /* clone the full name */
1196 printer->name = strdupW(name);
1197 if (name && (!printer->name)) {
1198 handle = 0;
1199 goto end;
1202 if (printername) {
1203 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1204 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1205 /* OpenPrinter(",XcvMonitor " detected */
1206 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1207 printer->pm = monitor_load(&printername[len], NULL);
1208 if (printer->pm == NULL) {
1209 SetLastError(ERROR_UNKNOWN_PORT);
1210 handle = 0;
1211 goto end;
1214 else
1216 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1217 if (strncmpW( printername, XcvPortW, len) == 0) {
1218 /* OpenPrinter(",XcvPort " detected */
1219 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1220 printer->pm = monitor_load_by_port(&printername[len]);
1221 if (printer->pm == NULL) {
1222 SetLastError(ERROR_UNKNOWN_PORT);
1223 handle = 0;
1224 goto end;
1229 if (printer->pm) {
1230 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1231 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1232 pDefault ? pDefault->DesiredAccess : 0,
1233 &printer->hXcv);
1235 if (printer->hXcv == NULL) {
1236 SetLastError(ERROR_INVALID_PARAMETER);
1237 handle = 0;
1238 goto end;
1241 else
1243 /* Does the Printer exist? */
1244 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1245 ERR("Can't create Printers key\n");
1246 handle = 0;
1247 goto end;
1249 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1250 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1251 RegCloseKey(hkeyPrinters);
1252 SetLastError(ERROR_INVALID_PRINTER_NAME);
1253 handle = 0;
1254 goto end;
1256 RegCloseKey(hkeyPrinter);
1257 RegCloseKey(hkeyPrinters);
1260 else
1262 TRACE("using the local printserver\n");
1265 if(queue)
1266 printer->queue = queue;
1267 else
1269 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1270 if (!printer->queue) {
1271 handle = 0;
1272 goto end;
1274 list_init(&printer->queue->jobs);
1275 printer->queue->ref = 0;
1277 InterlockedIncrement(&printer->queue->ref);
1279 printer_handles[handle] = printer;
1280 handle++;
1281 end:
1282 LeaveCriticalSection(&printer_handles_cs);
1283 if (!handle && printer) {
1284 /* Something failed: Free all resources */
1285 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1286 monitor_unload(printer->pm);
1287 HeapFree(GetProcessHeap(), 0, printer->printername);
1288 HeapFree(GetProcessHeap(), 0, printer->name);
1289 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1290 HeapFree(GetProcessHeap(), 0, printer);
1293 return (HANDLE)handle;
1296 /******************************************************************
1297 * get_opened_printer
1298 * Get the pointer to the opened printer referred by the handle
1300 static opened_printer_t *get_opened_printer(HANDLE hprn)
1302 UINT_PTR idx = (UINT_PTR)hprn;
1303 opened_printer_t *ret = NULL;
1305 EnterCriticalSection(&printer_handles_cs);
1307 if ((idx > 0) && (idx <= nb_printer_handles)) {
1308 ret = printer_handles[idx - 1];
1310 LeaveCriticalSection(&printer_handles_cs);
1311 return ret;
1314 /******************************************************************
1315 * get_opened_printer_name
1316 * Get the pointer to the opened printer name referred by the handle
1318 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1320 opened_printer_t *printer = get_opened_printer(hprn);
1321 if(!printer) return NULL;
1322 return printer->name;
1325 /******************************************************************
1326 * WINSPOOL_GetOpenedPrinterRegKey
1329 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1331 LPCWSTR name = get_opened_printer_name(hPrinter);
1332 DWORD ret;
1333 HKEY hkeyPrinters;
1335 if(!name) return ERROR_INVALID_HANDLE;
1337 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1338 ERROR_SUCCESS)
1339 return ret;
1341 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1343 ERR("Can't find opened printer %s in registry\n",
1344 debugstr_w(name));
1345 RegCloseKey(hkeyPrinters);
1346 return ERROR_INVALID_PRINTER_NAME; /* ? */
1348 RegCloseKey(hkeyPrinters);
1349 return ERROR_SUCCESS;
1352 void WINSPOOL_LoadSystemPrinters(void)
1354 HKEY hkey, hkeyPrinters;
1355 HANDLE hprn;
1356 DWORD needed, num, i;
1357 WCHAR PrinterName[256];
1358 BOOL done = FALSE;
1360 /* This ensures that all printer entries have a valid Name value. If causes
1361 problems later if they don't. If one is found to be missed we create one
1362 and set it equal to the name of the key */
1363 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1364 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1365 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1366 for(i = 0; i < num; i++) {
1367 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1368 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1369 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1370 set_reg_szW(hkey, NameW, PrinterName);
1372 RegCloseKey(hkey);
1377 RegCloseKey(hkeyPrinters);
1380 /* We want to avoid calling AddPrinter on printers as much as
1381 possible, because on cups printers this will (eventually) lead
1382 to a call to cupsGetPPD which takes forever, even with non-cups
1383 printers AddPrinter takes a while. So we'll tag all printers that
1384 were automatically added last time around, if they still exist
1385 we'll leave them be otherwise we'll delete them. */
1386 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1387 if(needed) {
1388 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1389 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1390 for(i = 0; i < num; i++) {
1391 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1392 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1393 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1394 DWORD dw = 1;
1395 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1396 RegCloseKey(hkey);
1398 ClosePrinter(hprn);
1403 HeapFree(GetProcessHeap(), 0, pi);
1407 #ifdef SONAME_LIBCUPS
1408 done = CUPS_LoadPrinters();
1409 #endif
1411 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1412 PRINTCAP_LoadPrinters();
1414 /* Now enumerate the list again and delete any printers that are still tagged */
1415 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1416 if(needed) {
1417 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1418 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1419 for(i = 0; i < num; i++) {
1420 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1421 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1422 BOOL delete_driver = FALSE;
1423 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1424 DWORD dw, type, size = sizeof(dw);
1425 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1426 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1427 DeletePrinter(hprn);
1428 delete_driver = TRUE;
1430 RegCloseKey(hkey);
1432 ClosePrinter(hprn);
1433 if(delete_driver)
1434 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1439 HeapFree(GetProcessHeap(), 0, pi);
1442 return;
1446 /******************************************************************
1447 * get_job
1449 * Get the pointer to the specified job.
1450 * Should hold the printer_handles_cs before calling.
1452 static job_t *get_job(HANDLE hprn, DWORD JobId)
1454 opened_printer_t *printer = get_opened_printer(hprn);
1455 job_t *job;
1457 if(!printer) return NULL;
1458 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1460 if(job->job_id == JobId)
1461 return job;
1463 return NULL;
1466 /***********************************************************
1467 * DEVMODEcpyAtoW
1469 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1471 BOOL Formname;
1472 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1473 DWORD size;
1475 Formname = (dmA->dmSize > off_formname);
1476 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1477 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1478 dmW->dmDeviceName, CCHDEVICENAME);
1479 if(!Formname) {
1480 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1481 dmA->dmSize - CCHDEVICENAME);
1482 } else {
1483 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1484 off_formname - CCHDEVICENAME);
1485 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1486 dmW->dmFormName, CCHFORMNAME);
1487 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1488 (off_formname + CCHFORMNAME));
1490 dmW->dmSize = size;
1491 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1492 dmA->dmDriverExtra);
1493 return dmW;
1496 /***********************************************************
1497 * DEVMODEdupWtoA
1498 * Creates an ansi copy of supplied devmode
1500 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1502 LPDEVMODEA dmA;
1503 DWORD size;
1505 if (!dmW) return NULL;
1506 size = dmW->dmSize - CCHDEVICENAME -
1507 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1509 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1510 if (!dmA) return NULL;
1512 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1513 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1515 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1516 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1517 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1519 else
1521 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1522 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1523 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1524 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1526 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1529 dmA->dmSize = size;
1530 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1531 return dmA;
1534 /******************************************************************
1535 * convert_printerinfo_W_to_A [internal]
1538 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1539 DWORD level, DWORD outlen, DWORD numentries)
1541 DWORD id = 0;
1542 LPSTR ptr;
1543 INT len;
1545 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1547 len = pi_sizeof[level] * numentries;
1548 ptr = (LPSTR) out + len;
1549 outlen -= len;
1551 /* copy the numbers of all PRINTER_INFO_* first */
1552 memcpy(out, pPrintersW, len);
1554 while (id < numentries) {
1555 switch (level) {
1556 case 1:
1558 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1559 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1561 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1562 if (piW->pDescription) {
1563 piA->pDescription = ptr;
1564 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1565 ptr, outlen, NULL, NULL);
1566 ptr += len;
1567 outlen -= len;
1569 if (piW->pName) {
1570 piA->pName = ptr;
1571 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1572 ptr, outlen, NULL, NULL);
1573 ptr += len;
1574 outlen -= len;
1576 if (piW->pComment) {
1577 piA->pComment = ptr;
1578 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1579 ptr, outlen, NULL, NULL);
1580 ptr += len;
1581 outlen -= len;
1583 break;
1586 case 2:
1588 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1589 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1590 LPDEVMODEA dmA;
1592 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1593 if (piW->pServerName) {
1594 piA->pServerName = ptr;
1595 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1596 ptr, outlen, NULL, NULL);
1597 ptr += len;
1598 outlen -= len;
1600 if (piW->pPrinterName) {
1601 piA->pPrinterName = ptr;
1602 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1603 ptr, outlen, NULL, NULL);
1604 ptr += len;
1605 outlen -= len;
1607 if (piW->pShareName) {
1608 piA->pShareName = ptr;
1609 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1610 ptr, outlen, NULL, NULL);
1611 ptr += len;
1612 outlen -= len;
1614 if (piW->pPortName) {
1615 piA->pPortName = ptr;
1616 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1617 ptr, outlen, NULL, NULL);
1618 ptr += len;
1619 outlen -= len;
1621 if (piW->pDriverName) {
1622 piA->pDriverName = ptr;
1623 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1624 ptr, outlen, NULL, NULL);
1625 ptr += len;
1626 outlen -= len;
1628 if (piW->pComment) {
1629 piA->pComment = ptr;
1630 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1631 ptr, outlen, NULL, NULL);
1632 ptr += len;
1633 outlen -= len;
1635 if (piW->pLocation) {
1636 piA->pLocation = ptr;
1637 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1638 ptr, outlen, NULL, NULL);
1639 ptr += len;
1640 outlen -= len;
1643 dmA = DEVMODEdupWtoA(piW->pDevMode);
1644 if (dmA) {
1645 /* align DEVMODEA to a DWORD boundary */
1646 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1647 ptr += len;
1648 outlen -= len;
1650 piA->pDevMode = (LPDEVMODEA) ptr;
1651 len = dmA->dmSize + dmA->dmDriverExtra;
1652 memcpy(ptr, dmA, len);
1653 HeapFree(GetProcessHeap(), 0, dmA);
1655 ptr += len;
1656 outlen -= len;
1659 if (piW->pSepFile) {
1660 piA->pSepFile = ptr;
1661 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1662 ptr, outlen, NULL, NULL);
1663 ptr += len;
1664 outlen -= len;
1666 if (piW->pPrintProcessor) {
1667 piA->pPrintProcessor = ptr;
1668 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1669 ptr, outlen, NULL, NULL);
1670 ptr += len;
1671 outlen -= len;
1673 if (piW->pDatatype) {
1674 piA->pDatatype = ptr;
1675 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1676 ptr, outlen, NULL, NULL);
1677 ptr += len;
1678 outlen -= len;
1680 if (piW->pParameters) {
1681 piA->pParameters = ptr;
1682 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1683 ptr, outlen, NULL, NULL);
1684 ptr += len;
1685 outlen -= len;
1687 if (piW->pSecurityDescriptor) {
1688 piA->pSecurityDescriptor = NULL;
1689 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1691 break;
1694 case 4:
1696 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1697 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1699 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1701 if (piW->pPrinterName) {
1702 piA->pPrinterName = ptr;
1703 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1704 ptr, outlen, NULL, NULL);
1705 ptr += len;
1706 outlen -= len;
1708 if (piW->pServerName) {
1709 piA->pServerName = ptr;
1710 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1711 ptr, outlen, NULL, NULL);
1712 ptr += len;
1713 outlen -= len;
1715 break;
1718 case 5:
1720 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1721 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1723 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1725 if (piW->pPrinterName) {
1726 piA->pPrinterName = ptr;
1727 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1728 ptr, outlen, NULL, NULL);
1729 ptr += len;
1730 outlen -= len;
1732 if (piW->pPortName) {
1733 piA->pPortName = ptr;
1734 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1735 ptr, outlen, NULL, NULL);
1736 ptr += len;
1737 outlen -= len;
1739 break;
1742 default:
1743 FIXME("for level %u\n", level);
1745 pPrintersW += pi_sizeof[level];
1746 out += pi_sizeof[level];
1747 id++;
1751 /***********************************************************
1752 * PRINTER_INFO_2AtoW
1753 * Creates a unicode copy of PRINTER_INFO_2A on heap
1755 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1757 LPPRINTER_INFO_2W piW;
1758 UNICODE_STRING usBuffer;
1760 if(!piA) return NULL;
1761 piW = HeapAlloc(heap, 0, sizeof(*piW));
1762 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1764 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1765 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1766 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1767 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1768 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1769 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1770 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1771 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1772 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1773 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1774 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1775 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1776 return piW;
1779 /***********************************************************
1780 * FREE_PRINTER_INFO_2W
1781 * Free PRINTER_INFO_2W and all strings
1783 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1785 if(!piW) return;
1787 HeapFree(heap,0,piW->pServerName);
1788 HeapFree(heap,0,piW->pPrinterName);
1789 HeapFree(heap,0,piW->pShareName);
1790 HeapFree(heap,0,piW->pPortName);
1791 HeapFree(heap,0,piW->pDriverName);
1792 HeapFree(heap,0,piW->pComment);
1793 HeapFree(heap,0,piW->pLocation);
1794 HeapFree(heap,0,piW->pDevMode);
1795 HeapFree(heap,0,piW->pSepFile);
1796 HeapFree(heap,0,piW->pPrintProcessor);
1797 HeapFree(heap,0,piW->pDatatype);
1798 HeapFree(heap,0,piW->pParameters);
1799 HeapFree(heap,0,piW);
1800 return;
1803 /******************************************************************
1804 * DeviceCapabilities [WINSPOOL.@]
1805 * DeviceCapabilitiesA [WINSPOOL.@]
1808 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1809 LPSTR pOutput, LPDEVMODEA lpdm)
1811 INT ret;
1813 if (!GDI_CallDeviceCapabilities16)
1815 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1816 (LPCSTR)104 );
1817 if (!GDI_CallDeviceCapabilities16) return -1;
1819 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1821 /* If DC_PAPERSIZE map POINT16s to POINTs */
1822 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1823 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1824 POINT *pt = (POINT *)pOutput;
1825 INT i;
1826 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1827 for(i = 0; i < ret; i++, pt++)
1829 pt->x = tmp[i].x;
1830 pt->y = tmp[i].y;
1832 HeapFree( GetProcessHeap(), 0, tmp );
1834 return ret;
1838 /*****************************************************************************
1839 * DeviceCapabilitiesW [WINSPOOL.@]
1841 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1844 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1845 WORD fwCapability, LPWSTR pOutput,
1846 const DEVMODEW *pDevMode)
1848 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1849 LPSTR pDeviceA = strdupWtoA(pDevice);
1850 LPSTR pPortA = strdupWtoA(pPort);
1851 INT ret;
1853 if(pOutput && (fwCapability == DC_BINNAMES ||
1854 fwCapability == DC_FILEDEPENDENCIES ||
1855 fwCapability == DC_PAPERNAMES)) {
1856 /* These need A -> W translation */
1857 INT size = 0, i;
1858 LPSTR pOutputA;
1859 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1860 dmA);
1861 if(ret == -1)
1862 return ret;
1863 switch(fwCapability) {
1864 case DC_BINNAMES:
1865 size = 24;
1866 break;
1867 case DC_PAPERNAMES:
1868 case DC_FILEDEPENDENCIES:
1869 size = 64;
1870 break;
1872 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1873 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1874 dmA);
1875 for(i = 0; i < ret; i++)
1876 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1877 pOutput + (i * size), size);
1878 HeapFree(GetProcessHeap(), 0, pOutputA);
1879 } else {
1880 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1881 (LPSTR)pOutput, dmA);
1883 HeapFree(GetProcessHeap(),0,pPortA);
1884 HeapFree(GetProcessHeap(),0,pDeviceA);
1885 HeapFree(GetProcessHeap(),0,dmA);
1886 return ret;
1889 /******************************************************************
1890 * DocumentPropertiesA [WINSPOOL.@]
1892 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1894 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1895 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1896 LPDEVMODEA pDevModeInput,DWORD fMode )
1898 LPSTR lpName = pDeviceName;
1899 static CHAR port[] = "LPT1:";
1900 LONG ret;
1902 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1903 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1906 if(!pDeviceName) {
1907 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1908 if(!lpNameW) {
1909 ERR("no name from hPrinter?\n");
1910 SetLastError(ERROR_INVALID_HANDLE);
1911 return -1;
1913 lpName = strdupWtoA(lpNameW);
1916 if (!GDI_CallExtDeviceMode16)
1918 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1919 (LPCSTR)102 );
1920 if (!GDI_CallExtDeviceMode16) {
1921 ERR("No CallExtDeviceMode16?\n");
1922 return -1;
1925 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1926 pDevModeInput, NULL, fMode);
1928 if(!pDeviceName)
1929 HeapFree(GetProcessHeap(),0,lpName);
1930 return ret;
1934 /*****************************************************************************
1935 * DocumentPropertiesW (WINSPOOL.@)
1937 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1939 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1940 LPWSTR pDeviceName,
1941 LPDEVMODEW pDevModeOutput,
1942 LPDEVMODEW pDevModeInput, DWORD fMode)
1945 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1946 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1947 LPDEVMODEA pDevModeOutputA = NULL;
1948 LONG ret;
1950 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1951 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1952 fMode);
1953 if(pDevModeOutput) {
1954 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1955 if(ret < 0) return ret;
1956 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1958 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1959 pDevModeInputA, fMode);
1960 if(pDevModeOutput) {
1961 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1962 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1964 if(fMode == 0 && ret > 0)
1965 ret += (CCHDEVICENAME + CCHFORMNAME);
1966 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1967 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1968 return ret;
1971 /******************************************************************
1972 * OpenPrinterA [WINSPOOL.@]
1974 * See OpenPrinterW.
1977 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1978 LPPRINTER_DEFAULTSA pDefault)
1980 UNICODE_STRING lpPrinterNameW;
1981 UNICODE_STRING usBuffer;
1982 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1983 PWSTR pwstrPrinterNameW;
1984 BOOL ret;
1986 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1988 if(pDefault) {
1989 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1990 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1991 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1992 pDefaultW = &DefaultW;
1994 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1995 if(pDefault) {
1996 RtlFreeUnicodeString(&usBuffer);
1997 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1999 RtlFreeUnicodeString(&lpPrinterNameW);
2000 return ret;
2003 /******************************************************************
2004 * OpenPrinterW [WINSPOOL.@]
2006 * Open a Printer / Printserver or a Printer-Object
2008 * PARAMS
2009 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2010 * phPrinter [O] The resulting Handle is stored here
2011 * pDefault [I] PTR to Default Printer Settings or NULL
2013 * RETURNS
2014 * Success: TRUE
2015 * Failure: FALSE
2017 * NOTES
2018 * lpPrinterName is one of:
2019 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2020 *| Printer: "PrinterName"
2021 *| Printer-Object: "PrinterName,Job xxx"
2022 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2023 *| XcvPort: "Servername,XcvPort PortName"
2025 * BUGS
2026 *| Printer-Object not supported
2027 *| pDefaults is ignored
2030 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2033 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2034 if (pDefault) {
2035 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2036 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2039 if(!phPrinter) {
2040 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2041 SetLastError(ERROR_INVALID_PARAMETER);
2042 return FALSE;
2045 /* Get the unique handle of the printer or Printserver */
2046 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2047 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2048 return (*phPrinter != 0);
2051 /******************************************************************
2052 * AddMonitorA [WINSPOOL.@]
2054 * See AddMonitorW.
2057 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2059 LPWSTR nameW = NULL;
2060 INT len;
2061 BOOL res;
2062 LPMONITOR_INFO_2A mi2a;
2063 MONITOR_INFO_2W mi2w;
2065 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2066 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2067 debugstr_a(mi2a ? mi2a->pName : NULL),
2068 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2069 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2071 if (Level != 2) {
2072 SetLastError(ERROR_INVALID_LEVEL);
2073 return FALSE;
2076 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2077 if (mi2a == NULL) {
2078 return FALSE;
2081 if (pName) {
2082 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2083 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2084 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2087 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2088 if (mi2a->pName) {
2089 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2090 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2091 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2093 if (mi2a->pEnvironment) {
2094 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2095 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2096 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2098 if (mi2a->pDLLName) {
2099 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2100 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2101 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2104 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2106 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2107 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2108 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2110 HeapFree(GetProcessHeap(), 0, nameW);
2111 return (res);
2114 /******************************************************************************
2115 * AddMonitorW [WINSPOOL.@]
2117 * Install a Printmonitor
2119 * PARAMS
2120 * pName [I] Servername or NULL (local Computer)
2121 * Level [I] Structure-Level (Must be 2)
2122 * pMonitors [I] PTR to MONITOR_INFO_2
2124 * RETURNS
2125 * Success: TRUE
2126 * Failure: FALSE
2128 * NOTES
2129 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2132 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2134 LPMONITOR_INFO_2W mi2w;
2136 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2137 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2138 debugstr_w(mi2w ? mi2w->pName : NULL),
2139 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2140 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2142 if ((backend == NULL) && !load_backend()) return FALSE;
2144 if (Level != 2) {
2145 SetLastError(ERROR_INVALID_LEVEL);
2146 return FALSE;
2149 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2150 if (mi2w == NULL) {
2151 return FALSE;
2154 return backend->fpAddMonitor(pName, Level, pMonitors);
2157 /******************************************************************
2158 * DeletePrinterDriverA [WINSPOOL.@]
2161 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2163 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2166 /******************************************************************
2167 * DeletePrinterDriverW [WINSPOOL.@]
2170 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2172 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2175 /******************************************************************
2176 * DeleteMonitorA [WINSPOOL.@]
2178 * See DeleteMonitorW.
2181 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2183 LPWSTR nameW = NULL;
2184 LPWSTR EnvironmentW = NULL;
2185 LPWSTR MonitorNameW = NULL;
2186 BOOL res;
2187 INT len;
2189 if (pName) {
2190 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2191 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2192 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2195 if (pEnvironment) {
2196 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2197 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2198 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2200 if (pMonitorName) {
2201 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2202 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2203 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2206 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2208 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2209 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2210 HeapFree(GetProcessHeap(), 0, nameW);
2211 return (res);
2214 /******************************************************************
2215 * DeleteMonitorW [WINSPOOL.@]
2217 * Delete a specific Printmonitor from a Printing-Environment
2219 * PARAMS
2220 * pName [I] Servername or NULL (local Computer)
2221 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2222 * pMonitorName [I] Name of the Monitor, that should be deleted
2224 * RETURNS
2225 * Success: TRUE
2226 * Failure: FALSE
2228 * NOTES
2229 * pEnvironment is ignored in Windows for the local Computer.
2232 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2235 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2236 debugstr_w(pMonitorName));
2238 if ((backend == NULL) && !load_backend()) return FALSE;
2240 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2244 /******************************************************************
2245 * DeletePortA [WINSPOOL.@]
2247 * See DeletePortW.
2250 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2252 LPWSTR nameW = NULL;
2253 LPWSTR portW = NULL;
2254 INT len;
2255 DWORD res;
2257 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2259 /* convert servername to unicode */
2260 if (pName) {
2261 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2262 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2263 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2266 /* convert portname to unicode */
2267 if (pPortName) {
2268 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2269 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2270 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2273 res = DeletePortW(nameW, hWnd, portW);
2274 HeapFree(GetProcessHeap(), 0, nameW);
2275 HeapFree(GetProcessHeap(), 0, portW);
2276 return res;
2279 /******************************************************************
2280 * DeletePortW [WINSPOOL.@]
2282 * Delete a specific Port
2284 * PARAMS
2285 * pName [I] Servername or NULL (local Computer)
2286 * hWnd [I] Handle to parent Window for the Dialog-Box
2287 * pPortName [I] Name of the Port, that should be deleted
2289 * RETURNS
2290 * Success: TRUE
2291 * Failure: FALSE
2294 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2296 monitor_t * pm;
2297 monitor_t * pui;
2298 DWORD res;
2300 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2302 if (pName && pName[0]) {
2303 SetLastError(ERROR_INVALID_PARAMETER);
2304 return FALSE;
2307 if (!pPortName) {
2308 SetLastError(RPC_X_NULL_REF_POINTER);
2309 return FALSE;
2312 /* an empty Portname is Invalid */
2313 if (!pPortName[0]) {
2314 SetLastError(ERROR_NOT_SUPPORTED);
2315 return FALSE;
2318 pm = monitor_load_by_port(pPortName);
2319 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2320 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2321 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2322 TRACE("got %d with %u\n", res, GetLastError());
2324 else
2326 pui = monitor_loadui(pm);
2327 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2328 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2329 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2330 TRACE("got %d with %u\n", res, GetLastError());
2332 else
2334 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2335 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2337 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2338 SetLastError(ERROR_NOT_SUPPORTED);
2339 res = FALSE;
2341 monitor_unload(pui);
2343 monitor_unload(pm);
2345 TRACE("returning %d with %u\n", res, GetLastError());
2346 return res;
2349 /******************************************************************************
2350 * SetPrinterW [WINSPOOL.@]
2352 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2354 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2355 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2356 return FALSE;
2359 /******************************************************************************
2360 * WritePrinter [WINSPOOL.@]
2362 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2364 opened_printer_t *printer;
2365 BOOL ret = FALSE;
2367 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2369 EnterCriticalSection(&printer_handles_cs);
2370 printer = get_opened_printer(hPrinter);
2371 if(!printer)
2373 SetLastError(ERROR_INVALID_HANDLE);
2374 goto end;
2377 if(!printer->doc)
2379 SetLastError(ERROR_SPL_NO_STARTDOC);
2380 goto end;
2383 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2384 end:
2385 LeaveCriticalSection(&printer_handles_cs);
2386 return ret;
2389 /*****************************************************************************
2390 * AddFormA [WINSPOOL.@]
2392 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2394 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2395 return 1;
2398 /*****************************************************************************
2399 * AddFormW [WINSPOOL.@]
2401 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2403 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2404 return 1;
2407 /*****************************************************************************
2408 * AddJobA [WINSPOOL.@]
2410 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2412 BOOL ret;
2413 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2414 DWORD needed;
2416 if(Level != 1) {
2417 SetLastError(ERROR_INVALID_LEVEL);
2418 return FALSE;
2421 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2423 if(ret) {
2424 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2425 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2426 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2427 if(*pcbNeeded > cbBuf) {
2428 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2429 ret = FALSE;
2430 } else {
2431 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2432 addjobA->JobId = addjobW->JobId;
2433 addjobA->Path = (char *)(addjobA + 1);
2434 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2437 return ret;
2440 /*****************************************************************************
2441 * AddJobW [WINSPOOL.@]
2443 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2445 opened_printer_t *printer;
2446 job_t *job;
2447 BOOL ret = FALSE;
2448 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2449 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2450 WCHAR path[MAX_PATH], filename[MAX_PATH];
2451 DWORD len;
2452 ADDJOB_INFO_1W *addjob;
2454 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2456 EnterCriticalSection(&printer_handles_cs);
2458 printer = get_opened_printer(hPrinter);
2460 if(!printer) {
2461 SetLastError(ERROR_INVALID_HANDLE);
2462 goto end;
2465 if(Level != 1) {
2466 SetLastError(ERROR_INVALID_LEVEL);
2467 goto end;
2470 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2471 if(!job)
2472 goto end;
2474 job->job_id = InterlockedIncrement(&next_job_id);
2476 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2477 if(path[len - 1] != '\\')
2478 path[len++] = '\\';
2479 memcpy(path + len, spool_path, sizeof(spool_path));
2480 sprintfW(filename, fmtW, path, job->job_id);
2482 len = strlenW(filename);
2483 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2484 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2485 job->document_title = strdupW(default_doc_title);
2486 list_add_tail(&printer->queue->jobs, &job->entry);
2488 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2489 if(*pcbNeeded <= cbBuf) {
2490 addjob = (ADDJOB_INFO_1W*)pData;
2491 addjob->JobId = job->job_id;
2492 addjob->Path = (WCHAR *)(addjob + 1);
2493 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2494 ret = TRUE;
2495 } else
2496 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2498 end:
2499 LeaveCriticalSection(&printer_handles_cs);
2500 return ret;
2503 /*****************************************************************************
2504 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2506 * Return the PATH for the Print-Processors
2508 * See GetPrintProcessorDirectoryW.
2512 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2513 DWORD level, LPBYTE Info,
2514 DWORD cbBuf, LPDWORD pcbNeeded)
2516 LPWSTR serverW = NULL;
2517 LPWSTR envW = NULL;
2518 BOOL ret;
2519 INT len;
2521 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2522 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2525 if (server) {
2526 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2527 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2528 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2531 if (env) {
2532 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2533 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2534 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2537 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2538 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2540 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2541 cbBuf, pcbNeeded);
2543 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2544 cbBuf, NULL, NULL) > 0;
2547 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2548 HeapFree(GetProcessHeap(), 0, envW);
2549 HeapFree(GetProcessHeap(), 0, serverW);
2550 return ret;
2553 /*****************************************************************************
2554 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2556 * Return the PATH for the Print-Processors
2558 * PARAMS
2559 * server [I] Servername (NT only) or NULL (local Computer)
2560 * env [I] Printing-Environment (see below) or NULL (Default)
2561 * level [I] Structure-Level (must be 1)
2562 * Info [O] PTR to Buffer that receives the Result
2563 * cbBuf [I] Size of Buffer at "Info"
2564 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2565 * required for the Buffer at "Info"
2567 * RETURNS
2568 * Success: TRUE and in pcbNeeded the Bytes used in Info
2569 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2570 * if cbBuf is too small
2572 * Native Values returned in Info on Success:
2573 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2574 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2575 *| win9x(Windows 4.0): "%winsysdir%"
2577 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2579 * BUGS
2580 * Only NULL or "" is supported for server
2583 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2584 DWORD level, LPBYTE Info,
2585 DWORD cbBuf, LPDWORD pcbNeeded)
2587 DWORD needed;
2588 const printenv_t * env_t;
2590 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2591 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2593 if(server != NULL && server[0]) {
2594 FIXME("server not supported: %s\n", debugstr_w(server));
2595 SetLastError(ERROR_INVALID_PARAMETER);
2596 return FALSE;
2599 env_t = validate_envW(env);
2600 if(!env_t) return FALSE; /* environment invalid or unsupported */
2602 if(level != 1) {
2603 WARN("(Level: %d) is ignored in win9x\n", level);
2604 SetLastError(ERROR_INVALID_LEVEL);
2605 return FALSE;
2608 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2609 needed = GetSystemDirectoryW(NULL, 0);
2610 /* add the Size for the Subdirectories */
2611 needed += lstrlenW(spoolprtprocsW);
2612 needed += lstrlenW(env_t->subdir);
2613 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2615 if(pcbNeeded) *pcbNeeded = needed;
2616 TRACE ("required: 0x%x/%d\n", needed, needed);
2617 if (needed > cbBuf) {
2618 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2619 return FALSE;
2621 if(pcbNeeded == NULL) {
2622 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2623 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2624 SetLastError(RPC_X_NULL_REF_POINTER);
2625 return FALSE;
2627 if(Info == NULL) {
2628 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2629 SetLastError(RPC_X_NULL_REF_POINTER);
2630 return FALSE;
2633 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2634 /* add the Subdirectories */
2635 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2636 lstrcatW((LPWSTR) Info, env_t->subdir);
2637 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2638 return TRUE;
2641 /*****************************************************************************
2642 * WINSPOOL_OpenDriverReg [internal]
2644 * opens the registry for the printer drivers depending on the given input
2645 * variable pEnvironment
2647 * RETURNS:
2648 * the opened hkey on success
2649 * NULL on error
2651 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2653 HKEY retval = NULL;
2654 LPWSTR buffer;
2655 const printenv_t * env;
2657 TRACE("(%s, %d)\n",
2658 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2660 if (!pEnvironment || unicode) {
2661 /* pEnvironment was NULL or a Unicode-String: use it direct */
2662 env = validate_envW(pEnvironment);
2664 else
2666 /* pEnvironment was an ANSI-String: convert to unicode first */
2667 LPWSTR buffer;
2668 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2669 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2670 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2671 env = validate_envW(buffer);
2672 HeapFree(GetProcessHeap(), 0, buffer);
2674 if (!env) return NULL;
2676 buffer = HeapAlloc( GetProcessHeap(), 0,
2677 (strlenW(DriversW) + strlenW(env->envname) +
2678 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2679 if(buffer) {
2680 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2681 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2682 HeapFree(GetProcessHeap(), 0, buffer);
2684 return retval;
2687 /*****************************************************************************
2688 * AddPrinterW [WINSPOOL.@]
2690 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2692 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2693 LPDEVMODEA dmA;
2694 LPDEVMODEW dmW;
2695 HANDLE retval;
2696 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2697 LONG size;
2698 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2699 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2700 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2701 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2702 statusW[] = {'S','t','a','t','u','s',0},
2703 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2705 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2707 if(pName != NULL) {
2708 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2709 SetLastError(ERROR_INVALID_PARAMETER);
2710 return 0;
2712 if(Level != 2) {
2713 ERR("Level = %d, unsupported!\n", Level);
2714 SetLastError(ERROR_INVALID_LEVEL);
2715 return 0;
2717 if(!pPrinter) {
2718 SetLastError(ERROR_INVALID_PARAMETER);
2719 return 0;
2721 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2722 ERROR_SUCCESS) {
2723 ERR("Can't create Printers key\n");
2724 return 0;
2726 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2727 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2728 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2729 RegCloseKey(hkeyPrinter);
2730 RegCloseKey(hkeyPrinters);
2731 return 0;
2733 RegCloseKey(hkeyPrinter);
2735 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2736 if(!hkeyDrivers) {
2737 ERR("Can't create Drivers key\n");
2738 RegCloseKey(hkeyPrinters);
2739 return 0;
2741 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2742 ERROR_SUCCESS) {
2743 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2744 RegCloseKey(hkeyPrinters);
2745 RegCloseKey(hkeyDrivers);
2746 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2747 return 0;
2749 RegCloseKey(hkeyDriver);
2750 RegCloseKey(hkeyDrivers);
2752 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2753 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2754 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2755 RegCloseKey(hkeyPrinters);
2756 return 0;
2759 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2760 ERROR_SUCCESS) {
2761 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2762 SetLastError(ERROR_INVALID_PRINTER_NAME);
2763 RegCloseKey(hkeyPrinters);
2764 return 0;
2766 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2767 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2768 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2770 /* See if we can load the driver. We may need the devmode structure anyway
2772 * FIXME:
2773 * Note that DocumentPropertiesW will briefly try to open the printer we
2774 * just create to find a DEVMODEA struct (it will use the WINEPS default
2775 * one in case it is not there, so we are ok).
2777 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2779 if(size < 0) {
2780 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2781 size = sizeof(DEVMODEW);
2783 if(pi->pDevMode)
2784 dmW = pi->pDevMode;
2785 else
2787 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2788 dmW->dmSize = size;
2789 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2791 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2792 HeapFree(GetProcessHeap(),0,dmW);
2793 dmW=NULL;
2795 else
2797 /* set devmode to printer name */
2798 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2802 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2803 and we support these drivers. NT writes DEVMODEW so somehow
2804 we'll need to distinguish between these when we support NT
2805 drivers */
2806 if (dmW)
2808 dmA = DEVMODEdupWtoA(dmW);
2809 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2810 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2811 HeapFree(GetProcessHeap(), 0, dmA);
2812 if(!pi->pDevMode)
2813 HeapFree(GetProcessHeap(), 0, dmW);
2815 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2816 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2817 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2818 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2820 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2821 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2822 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2823 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2824 (LPBYTE)&pi->Priority, sizeof(DWORD));
2825 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2826 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2827 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2828 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2829 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2830 (LPBYTE)&pi->Status, sizeof(DWORD));
2831 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2832 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2834 RegCloseKey(hkeyPrinter);
2835 RegCloseKey(hkeyPrinters);
2836 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2837 ERR("OpenPrinter failing\n");
2838 return 0;
2840 return retval;
2843 /*****************************************************************************
2844 * AddPrinterA [WINSPOOL.@]
2846 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2848 UNICODE_STRING pNameW;
2849 PWSTR pwstrNameW;
2850 PRINTER_INFO_2W *piW;
2851 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2852 HANDLE ret;
2854 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2855 if(Level != 2) {
2856 ERR("Level = %d, unsupported!\n", Level);
2857 SetLastError(ERROR_INVALID_LEVEL);
2858 return 0;
2860 pwstrNameW = asciitounicode(&pNameW,pName);
2861 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2863 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2865 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2866 RtlFreeUnicodeString(&pNameW);
2867 return ret;
2871 /*****************************************************************************
2872 * ClosePrinter [WINSPOOL.@]
2874 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2876 UINT_PTR i = (UINT_PTR)hPrinter;
2877 opened_printer_t *printer = NULL;
2878 BOOL ret = FALSE;
2880 TRACE("(%p)\n", hPrinter);
2882 EnterCriticalSection(&printer_handles_cs);
2884 if ((i > 0) && (i <= nb_printer_handles))
2885 printer = printer_handles[i - 1];
2888 if(printer)
2890 struct list *cursor, *cursor2;
2892 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2893 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2894 printer->hXcv, debugstr_w(printer->name), printer->doc );
2896 if(printer->doc)
2897 EndDocPrinter(hPrinter);
2899 if(InterlockedDecrement(&printer->queue->ref) == 0)
2901 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2903 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2904 ScheduleJob(hPrinter, job->job_id);
2906 HeapFree(GetProcessHeap(), 0, printer->queue);
2908 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2909 monitor_unload(printer->pm);
2910 HeapFree(GetProcessHeap(), 0, printer->printername);
2911 HeapFree(GetProcessHeap(), 0, printer->name);
2912 HeapFree(GetProcessHeap(), 0, printer);
2913 printer_handles[i - 1] = NULL;
2914 ret = TRUE;
2916 LeaveCriticalSection(&printer_handles_cs);
2917 return ret;
2920 /*****************************************************************************
2921 * DeleteFormA [WINSPOOL.@]
2923 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2925 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2926 return 1;
2929 /*****************************************************************************
2930 * DeleteFormW [WINSPOOL.@]
2932 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2934 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2935 return 1;
2938 /*****************************************************************************
2939 * DeletePrinter [WINSPOOL.@]
2941 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2943 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2944 HKEY hkeyPrinters, hkey;
2946 if(!lpNameW) {
2947 SetLastError(ERROR_INVALID_HANDLE);
2948 return FALSE;
2950 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2951 RegDeleteTreeW(hkeyPrinters, lpNameW);
2952 RegCloseKey(hkeyPrinters);
2954 WriteProfileStringW(devicesW, lpNameW, NULL);
2955 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2957 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2958 RegDeleteValueW(hkey, lpNameW);
2959 RegCloseKey(hkey);
2962 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2963 RegDeleteValueW(hkey, lpNameW);
2964 RegCloseKey(hkey);
2966 return TRUE;
2969 /*****************************************************************************
2970 * SetPrinterA [WINSPOOL.@]
2972 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2973 DWORD Command)
2975 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2976 return FALSE;
2979 /*****************************************************************************
2980 * SetJobA [WINSPOOL.@]
2982 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2983 LPBYTE pJob, DWORD Command)
2985 BOOL ret;
2986 LPBYTE JobW;
2987 UNICODE_STRING usBuffer;
2989 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2991 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2992 are all ignored by SetJob, so we don't bother copying them */
2993 switch(Level)
2995 case 0:
2996 JobW = NULL;
2997 break;
2998 case 1:
3000 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3001 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3003 JobW = (LPBYTE)info1W;
3004 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3005 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3006 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3007 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3008 info1W->Status = info1A->Status;
3009 info1W->Priority = info1A->Priority;
3010 info1W->Position = info1A->Position;
3011 info1W->PagesPrinted = info1A->PagesPrinted;
3012 break;
3014 case 2:
3016 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3017 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3019 JobW = (LPBYTE)info2W;
3020 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3021 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3022 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3023 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3024 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3025 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3026 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3027 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3028 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3029 info2W->Status = info2A->Status;
3030 info2W->Priority = info2A->Priority;
3031 info2W->Position = info2A->Position;
3032 info2W->StartTime = info2A->StartTime;
3033 info2W->UntilTime = info2A->UntilTime;
3034 info2W->PagesPrinted = info2A->PagesPrinted;
3035 break;
3037 case 3:
3038 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3039 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3040 break;
3041 default:
3042 SetLastError(ERROR_INVALID_LEVEL);
3043 return FALSE;
3046 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3048 switch(Level)
3050 case 1:
3052 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3053 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3054 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3055 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3056 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3057 break;
3059 case 2:
3061 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3062 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3063 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3064 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3065 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3066 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3067 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3068 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3069 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3070 break;
3073 HeapFree(GetProcessHeap(), 0, JobW);
3075 return ret;
3078 /*****************************************************************************
3079 * SetJobW [WINSPOOL.@]
3081 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3082 LPBYTE pJob, DWORD Command)
3084 BOOL ret = FALSE;
3085 job_t *job;
3087 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3088 FIXME("Ignoring everything other than document title\n");
3090 EnterCriticalSection(&printer_handles_cs);
3091 job = get_job(hPrinter, JobId);
3092 if(!job)
3093 goto end;
3095 switch(Level)
3097 case 0:
3098 break;
3099 case 1:
3101 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3102 HeapFree(GetProcessHeap(), 0, job->document_title);
3103 job->document_title = strdupW(info1->pDocument);
3104 break;
3106 case 2:
3108 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3109 HeapFree(GetProcessHeap(), 0, job->document_title);
3110 job->document_title = strdupW(info2->pDocument);
3111 break;
3113 case 3:
3114 break;
3115 default:
3116 SetLastError(ERROR_INVALID_LEVEL);
3117 goto end;
3119 ret = TRUE;
3120 end:
3121 LeaveCriticalSection(&printer_handles_cs);
3122 return ret;
3125 /*****************************************************************************
3126 * EndDocPrinter [WINSPOOL.@]
3128 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3130 opened_printer_t *printer;
3131 BOOL ret = FALSE;
3132 TRACE("(%p)\n", hPrinter);
3134 EnterCriticalSection(&printer_handles_cs);
3136 printer = get_opened_printer(hPrinter);
3137 if(!printer)
3139 SetLastError(ERROR_INVALID_HANDLE);
3140 goto end;
3143 if(!printer->doc)
3145 SetLastError(ERROR_SPL_NO_STARTDOC);
3146 goto end;
3149 CloseHandle(printer->doc->hf);
3150 ScheduleJob(hPrinter, printer->doc->job_id);
3151 HeapFree(GetProcessHeap(), 0, printer->doc);
3152 printer->doc = NULL;
3153 ret = TRUE;
3154 end:
3155 LeaveCriticalSection(&printer_handles_cs);
3156 return ret;
3159 /*****************************************************************************
3160 * EndPagePrinter [WINSPOOL.@]
3162 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3164 FIXME("(%p): stub\n", hPrinter);
3165 return TRUE;
3168 /*****************************************************************************
3169 * StartDocPrinterA [WINSPOOL.@]
3171 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3173 UNICODE_STRING usBuffer;
3174 DOC_INFO_2W doc2W;
3175 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3176 DWORD ret;
3178 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3179 or one (DOC_INFO_3) extra DWORDs */
3181 switch(Level) {
3182 case 2:
3183 doc2W.JobId = doc2->JobId;
3184 /* fall through */
3185 case 3:
3186 doc2W.dwMode = doc2->dwMode;
3187 /* fall through */
3188 case 1:
3189 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3190 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3191 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3192 break;
3194 default:
3195 SetLastError(ERROR_INVALID_LEVEL);
3196 return FALSE;
3199 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3201 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3202 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3203 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3205 return ret;
3208 /*****************************************************************************
3209 * StartDocPrinterW [WINSPOOL.@]
3211 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3213 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3214 opened_printer_t *printer;
3215 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3216 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3217 JOB_INFO_1W job_info;
3218 DWORD needed, ret = 0;
3219 HANDLE hf;
3220 WCHAR *filename;
3222 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3223 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3224 debugstr_w(doc->pDatatype));
3226 if(Level < 1 || Level > 3)
3228 SetLastError(ERROR_INVALID_LEVEL);
3229 return 0;
3232 EnterCriticalSection(&printer_handles_cs);
3233 printer = get_opened_printer(hPrinter);
3234 if(!printer)
3236 SetLastError(ERROR_INVALID_HANDLE);
3237 goto end;
3240 if(printer->doc)
3242 SetLastError(ERROR_INVALID_PRINTER_STATE);
3243 goto end;
3246 /* Even if we're printing to a file we still add a print job, we'll
3247 just ignore the spool file name */
3249 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3251 ERR("AddJob failed gle %u\n", GetLastError());
3252 goto end;
3255 if(doc->pOutputFile)
3256 filename = doc->pOutputFile;
3257 else
3258 filename = addjob->Path;
3260 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3261 if(hf == INVALID_HANDLE_VALUE)
3262 goto end;
3264 memset(&job_info, 0, sizeof(job_info));
3265 job_info.pDocument = doc->pDocName;
3266 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3268 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3269 printer->doc->hf = hf;
3270 ret = printer->doc->job_id = addjob->JobId;
3271 end:
3272 LeaveCriticalSection(&printer_handles_cs);
3274 return ret;
3277 /*****************************************************************************
3278 * StartPagePrinter [WINSPOOL.@]
3280 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3282 FIXME("(%p): stub\n", hPrinter);
3283 return TRUE;
3286 /*****************************************************************************
3287 * GetFormA [WINSPOOL.@]
3289 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3290 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3292 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3293 Level,pForm,cbBuf,pcbNeeded);
3294 return FALSE;
3297 /*****************************************************************************
3298 * GetFormW [WINSPOOL.@]
3300 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3301 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3303 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3304 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3305 return FALSE;
3308 /*****************************************************************************
3309 * SetFormA [WINSPOOL.@]
3311 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3312 LPBYTE pForm)
3314 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3315 return FALSE;
3318 /*****************************************************************************
3319 * SetFormW [WINSPOOL.@]
3321 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3322 LPBYTE pForm)
3324 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3325 return FALSE;
3328 /*****************************************************************************
3329 * ReadPrinter [WINSPOOL.@]
3331 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3332 LPDWORD pNoBytesRead)
3334 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3335 return FALSE;
3338 /*****************************************************************************
3339 * ResetPrinterA [WINSPOOL.@]
3341 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3343 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3344 return FALSE;
3347 /*****************************************************************************
3348 * ResetPrinterW [WINSPOOL.@]
3350 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3352 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3353 return FALSE;
3356 /*****************************************************************************
3357 * WINSPOOL_GetDWORDFromReg
3359 * Return DWORD associated with ValueName from hkey.
3361 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3363 DWORD sz = sizeof(DWORD), type, value = 0;
3364 LONG ret;
3366 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3368 if(ret != ERROR_SUCCESS) {
3369 WARN("Got ret = %d on name %s\n", ret, ValueName);
3370 return 0;
3372 if(type != REG_DWORD) {
3373 ERR("Got type %d\n", type);
3374 return 0;
3376 return value;
3380 /*****************************************************************************
3381 * get_filename_from_reg [internal]
3383 * Get ValueName from hkey storing result in out
3384 * when the Value in the registry has only a filename, use driverdir as prefix
3385 * outlen is space left in out
3386 * String is stored either as unicode or ascii
3390 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3391 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3393 WCHAR filename[MAX_PATH];
3394 DWORD size;
3395 DWORD type;
3396 LONG ret;
3397 LPWSTR buffer = filename;
3398 LPWSTR ptr;
3400 *needed = 0;
3401 size = sizeof(filename);
3402 buffer[0] = '\0';
3403 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3404 if (ret == ERROR_MORE_DATA) {
3405 TRACE("need dynamic buffer: %u\n", size);
3406 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3407 if (!buffer) {
3408 /* No Memory is bad */
3409 return FALSE;
3411 buffer[0] = '\0';
3412 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3415 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3416 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3417 return FALSE;
3420 ptr = buffer;
3421 while (ptr) {
3422 /* do we have a full path ? */
3423 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3424 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3426 if (!ret) {
3427 /* we must build the full Path */
3428 *needed += dirlen;
3429 if ((out) && (outlen > dirlen)) {
3430 if (unicode) {
3431 lstrcpyW((LPWSTR)out, driverdir);
3433 else
3435 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3437 out += dirlen;
3438 outlen -= dirlen;
3440 else
3441 out = NULL;
3444 /* write the filename */
3445 if (unicode) {
3446 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3447 if ((out) && (outlen >= size)) {
3448 lstrcpyW((LPWSTR)out, ptr);
3449 out += size;
3450 outlen -= size;
3452 else
3453 out = NULL;
3455 else
3457 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3458 if ((out) && (outlen >= size)) {
3459 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3460 out += size;
3461 outlen -= size;
3463 else
3464 out = NULL;
3466 *needed += size;
3467 ptr += lstrlenW(ptr)+1;
3468 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3471 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3473 /* write the multisz-termination */
3474 if (type == REG_MULTI_SZ) {
3475 size = (unicode) ? sizeof(WCHAR) : 1;
3477 *needed += size;
3478 if (out && (outlen >= size)) {
3479 memset (out, 0, size);
3482 return TRUE;
3485 /*****************************************************************************
3486 * WINSPOOL_GetStringFromReg
3488 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3489 * String is stored either as unicode or ascii.
3490 * Bit of a hack here to get the ValueName if we want ascii.
3492 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3493 DWORD buflen, DWORD *needed,
3494 BOOL unicode)
3496 DWORD sz = buflen, type;
3497 LONG ret;
3499 if(unicode)
3500 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3501 else {
3502 LPSTR ValueNameA = strdupWtoA(ValueName);
3503 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3504 HeapFree(GetProcessHeap(),0,ValueNameA);
3506 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3507 WARN("Got ret = %d\n", ret);
3508 *needed = 0;
3509 return FALSE;
3511 /* add space for terminating '\0' */
3512 sz += unicode ? sizeof(WCHAR) : 1;
3513 *needed = sz;
3515 if (ptr)
3516 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3518 return TRUE;
3521 /*****************************************************************************
3522 * WINSPOOL_GetDefaultDevMode
3524 * Get a default DevMode values for wineps.
3525 * FIXME - use ppd.
3528 static void WINSPOOL_GetDefaultDevMode(
3529 LPBYTE ptr,
3530 DWORD buflen, DWORD *needed,
3531 BOOL unicode)
3533 DEVMODEA dm;
3534 static const char szwps[] = "wineps.drv";
3536 /* fill default DEVMODE - should be read from ppd... */
3537 ZeroMemory( &dm, sizeof(dm) );
3538 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3539 dm.dmSpecVersion = DM_SPECVERSION;
3540 dm.dmDriverVersion = 1;
3541 dm.dmSize = sizeof(DEVMODEA);
3542 dm.dmDriverExtra = 0;
3543 dm.dmFields =
3544 DM_ORIENTATION | DM_PAPERSIZE |
3545 DM_PAPERLENGTH | DM_PAPERWIDTH |
3546 DM_SCALE |
3547 DM_COPIES |
3548 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3549 DM_YRESOLUTION | DM_TTOPTION;
3551 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3552 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3553 dm.u1.s1.dmPaperLength = 2970;
3554 dm.u1.s1.dmPaperWidth = 2100;
3556 dm.u1.s1.dmScale = 100;
3557 dm.u1.s1.dmCopies = 1;
3558 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3559 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3560 /* dm.dmColor */
3561 /* dm.dmDuplex */
3562 dm.dmYResolution = 300; /* 300dpi */
3563 dm.dmTTOption = DMTT_BITMAP;
3564 /* dm.dmCollate */
3565 /* dm.dmFormName */
3566 /* dm.dmLogPixels */
3567 /* dm.dmBitsPerPel */
3568 /* dm.dmPelsWidth */
3569 /* dm.dmPelsHeight */
3570 /* dm.u2.dmDisplayFlags */
3571 /* dm.dmDisplayFrequency */
3572 /* dm.dmICMMethod */
3573 /* dm.dmICMIntent */
3574 /* dm.dmMediaType */
3575 /* dm.dmDitherType */
3576 /* dm.dmReserved1 */
3577 /* dm.dmReserved2 */
3578 /* dm.dmPanningWidth */
3579 /* dm.dmPanningHeight */
3581 if(unicode) {
3582 if(buflen >= sizeof(DEVMODEW)) {
3583 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3584 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3585 HeapFree(GetProcessHeap(),0,pdmW);
3587 *needed = sizeof(DEVMODEW);
3589 else
3591 if(buflen >= sizeof(DEVMODEA)) {
3592 memcpy(ptr, &dm, sizeof(DEVMODEA));
3594 *needed = sizeof(DEVMODEA);
3598 /*****************************************************************************
3599 * WINSPOOL_GetDevModeFromReg
3601 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3602 * DevMode is stored either as unicode or ascii.
3604 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3605 LPBYTE ptr,
3606 DWORD buflen, DWORD *needed,
3607 BOOL unicode)
3609 DWORD sz = buflen, type;
3610 LONG ret;
3612 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3613 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3614 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3615 if (sz < sizeof(DEVMODEA))
3617 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3618 return FALSE;
3620 /* ensures that dmSize is not erratically bogus if registry is invalid */
3621 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3622 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3623 if(unicode) {
3624 sz += (CCHDEVICENAME + CCHFORMNAME);
3625 if(buflen >= sz) {
3626 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3627 memcpy(ptr, dmW, sz);
3628 HeapFree(GetProcessHeap(),0,dmW);
3631 *needed = sz;
3632 return TRUE;
3635 /*********************************************************************
3636 * WINSPOOL_GetPrinter_1
3638 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3639 * The strings are either stored as unicode or ascii.
3641 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3642 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3643 BOOL unicode)
3645 DWORD size, left = cbBuf;
3646 BOOL space = (cbBuf > 0);
3647 LPBYTE ptr = buf;
3649 *pcbNeeded = 0;
3651 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3652 unicode)) {
3653 if(space && size <= left) {
3654 pi1->pName = (LPWSTR)ptr;
3655 ptr += size;
3656 left -= size;
3657 } else
3658 space = FALSE;
3659 *pcbNeeded += size;
3662 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3664 unicode)) {
3665 if(space && size <= left) {
3666 pi1->pDescription = (LPWSTR)ptr;
3667 ptr += size;
3668 left -= size;
3669 } else
3670 space = FALSE;
3671 *pcbNeeded += size;
3674 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3675 unicode)) {
3676 if(space && size <= left) {
3677 pi1->pComment = (LPWSTR)ptr;
3678 ptr += size;
3679 left -= size;
3680 } else
3681 space = FALSE;
3682 *pcbNeeded += size;
3685 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3687 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3688 memset(pi1, 0, sizeof(*pi1));
3690 return space;
3692 /*********************************************************************
3693 * WINSPOOL_GetPrinter_2
3695 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3696 * The strings are either stored as unicode or ascii.
3698 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3699 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3700 BOOL unicode)
3702 DWORD size, left = cbBuf;
3703 BOOL space = (cbBuf > 0);
3704 LPBYTE ptr = buf;
3706 *pcbNeeded = 0;
3708 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3709 unicode)) {
3710 if(space && size <= left) {
3711 pi2->pPrinterName = (LPWSTR)ptr;
3712 ptr += size;
3713 left -= size;
3714 } else
3715 space = FALSE;
3716 *pcbNeeded += size;
3718 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3719 unicode)) {
3720 if(space && size <= left) {
3721 pi2->pShareName = (LPWSTR)ptr;
3722 ptr += size;
3723 left -= size;
3724 } else
3725 space = FALSE;
3726 *pcbNeeded += size;
3728 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3729 unicode)) {
3730 if(space && size <= left) {
3731 pi2->pPortName = (LPWSTR)ptr;
3732 ptr += size;
3733 left -= size;
3734 } else
3735 space = FALSE;
3736 *pcbNeeded += size;
3738 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3739 &size, unicode)) {
3740 if(space && size <= left) {
3741 pi2->pDriverName = (LPWSTR)ptr;
3742 ptr += size;
3743 left -= size;
3744 } else
3745 space = FALSE;
3746 *pcbNeeded += size;
3748 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3749 unicode)) {
3750 if(space && size <= left) {
3751 pi2->pComment = (LPWSTR)ptr;
3752 ptr += size;
3753 left -= size;
3754 } else
3755 space = FALSE;
3756 *pcbNeeded += size;
3758 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3759 unicode)) {
3760 if(space && size <= left) {
3761 pi2->pLocation = (LPWSTR)ptr;
3762 ptr += size;
3763 left -= size;
3764 } else
3765 space = FALSE;
3766 *pcbNeeded += size;
3768 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3769 &size, unicode)) {
3770 if(space && size <= left) {
3771 pi2->pDevMode = (LPDEVMODEW)ptr;
3772 ptr += size;
3773 left -= size;
3774 } else
3775 space = FALSE;
3776 *pcbNeeded += size;
3778 else
3780 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3781 if(space && size <= left) {
3782 pi2->pDevMode = (LPDEVMODEW)ptr;
3783 ptr += size;
3784 left -= size;
3785 } else
3786 space = FALSE;
3787 *pcbNeeded += size;
3789 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3790 &size, unicode)) {
3791 if(space && size <= left) {
3792 pi2->pSepFile = (LPWSTR)ptr;
3793 ptr += size;
3794 left -= size;
3795 } else
3796 space = FALSE;
3797 *pcbNeeded += size;
3799 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3800 &size, unicode)) {
3801 if(space && size <= left) {
3802 pi2->pPrintProcessor = (LPWSTR)ptr;
3803 ptr += size;
3804 left -= size;
3805 } else
3806 space = FALSE;
3807 *pcbNeeded += size;
3809 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3810 &size, unicode)) {
3811 if(space && size <= left) {
3812 pi2->pDatatype = (LPWSTR)ptr;
3813 ptr += size;
3814 left -= size;
3815 } else
3816 space = FALSE;
3817 *pcbNeeded += size;
3819 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3820 &size, unicode)) {
3821 if(space && size <= left) {
3822 pi2->pParameters = (LPWSTR)ptr;
3823 ptr += size;
3824 left -= size;
3825 } else
3826 space = FALSE;
3827 *pcbNeeded += size;
3829 if(pi2) {
3830 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3831 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3832 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3833 "Default Priority");
3834 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3835 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3838 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3839 memset(pi2, 0, sizeof(*pi2));
3841 return space;
3844 /*********************************************************************
3845 * WINSPOOL_GetPrinter_4
3847 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3849 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3850 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3851 BOOL unicode)
3853 DWORD size, left = cbBuf;
3854 BOOL space = (cbBuf > 0);
3855 LPBYTE ptr = buf;
3857 *pcbNeeded = 0;
3859 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3860 unicode)) {
3861 if(space && size <= left) {
3862 pi4->pPrinterName = (LPWSTR)ptr;
3863 ptr += size;
3864 left -= size;
3865 } else
3866 space = FALSE;
3867 *pcbNeeded += size;
3869 if(pi4) {
3870 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3873 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3874 memset(pi4, 0, sizeof(*pi4));
3876 return space;
3879 /*********************************************************************
3880 * WINSPOOL_GetPrinter_5
3882 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3884 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3885 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3886 BOOL unicode)
3888 DWORD size, left = cbBuf;
3889 BOOL space = (cbBuf > 0);
3890 LPBYTE ptr = buf;
3892 *pcbNeeded = 0;
3894 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3895 unicode)) {
3896 if(space && size <= left) {
3897 pi5->pPrinterName = (LPWSTR)ptr;
3898 ptr += size;
3899 left -= size;
3900 } else
3901 space = FALSE;
3902 *pcbNeeded += size;
3904 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3905 unicode)) {
3906 if(space && size <= left) {
3907 pi5->pPortName = (LPWSTR)ptr;
3908 ptr += size;
3909 left -= size;
3910 } else
3911 space = FALSE;
3912 *pcbNeeded += size;
3914 if(pi5) {
3915 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3916 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3917 "dnsTimeout");
3918 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3919 "txTimeout");
3922 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3923 memset(pi5, 0, sizeof(*pi5));
3925 return space;
3928 /*********************************************************************
3929 * WINSPOOL_GetPrinter_7
3931 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3933 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3934 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3936 DWORD size, left = cbBuf;
3937 BOOL space = (cbBuf > 0);
3938 LPBYTE ptr = buf;
3940 *pcbNeeded = 0;
3942 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3944 if (space && size <= left) {
3945 pi7->pszObjectGUID = (LPWSTR)ptr;
3946 ptr += size;
3947 left -= size;
3948 } else
3949 space = FALSE;
3950 *pcbNeeded += size;
3952 if (pi7) {
3953 /* We do not have a Directory Service */
3954 pi7->dwAction = DSPRINT_UNPUBLISH;
3957 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3958 memset(pi7, 0, sizeof(*pi7));
3960 return space;
3963 /*********************************************************************
3964 * WINSPOOL_GetPrinter_9
3966 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3967 * The strings are either stored as unicode or ascii.
3969 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3970 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3972 DWORD size;
3973 BOOL space = (cbBuf > 0);
3975 *pcbNeeded = 0;
3977 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3978 if(space && size <= cbBuf) {
3979 pi9->pDevMode = (LPDEVMODEW)buf;
3980 } else
3981 space = FALSE;
3982 *pcbNeeded += size;
3984 else
3986 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3987 if(space && size <= cbBuf) {
3988 pi9->pDevMode = (LPDEVMODEW)buf;
3989 } else
3990 space = FALSE;
3991 *pcbNeeded += size;
3994 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3995 memset(pi9, 0, sizeof(*pi9));
3997 return space;
4000 /*****************************************************************************
4001 * WINSPOOL_GetPrinter
4003 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4004 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4005 * just a collection of pointers to strings.
4007 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4008 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4010 LPCWSTR name;
4011 DWORD size, needed = 0;
4012 LPBYTE ptr = NULL;
4013 HKEY hkeyPrinter, hkeyPrinters;
4014 BOOL ret;
4016 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4018 if (!(name = get_opened_printer_name(hPrinter))) {
4019 SetLastError(ERROR_INVALID_HANDLE);
4020 return FALSE;
4023 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4024 ERROR_SUCCESS) {
4025 ERR("Can't create Printers key\n");
4026 return FALSE;
4028 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4030 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4031 RegCloseKey(hkeyPrinters);
4032 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4033 return FALSE;
4036 switch(Level) {
4037 case 2:
4039 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4041 size = sizeof(PRINTER_INFO_2W);
4042 if(size <= cbBuf) {
4043 ptr = pPrinter + size;
4044 cbBuf -= size;
4045 memset(pPrinter, 0, size);
4046 } else {
4047 pi2 = NULL;
4048 cbBuf = 0;
4050 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4051 unicode);
4052 needed += size;
4053 break;
4056 case 4:
4058 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4060 size = sizeof(PRINTER_INFO_4W);
4061 if(size <= cbBuf) {
4062 ptr = pPrinter + size;
4063 cbBuf -= size;
4064 memset(pPrinter, 0, size);
4065 } else {
4066 pi4 = NULL;
4067 cbBuf = 0;
4069 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4070 unicode);
4071 needed += size;
4072 break;
4076 case 5:
4078 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4080 size = sizeof(PRINTER_INFO_5W);
4081 if(size <= cbBuf) {
4082 ptr = pPrinter + size;
4083 cbBuf -= size;
4084 memset(pPrinter, 0, size);
4085 } else {
4086 pi5 = NULL;
4087 cbBuf = 0;
4090 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4091 unicode);
4092 needed += size;
4093 break;
4097 case 6:
4099 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4101 size = sizeof(PRINTER_INFO_6);
4102 if (size <= cbBuf) {
4103 /* FIXME: We do not update the status yet */
4104 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4105 ret = TRUE;
4106 } else {
4107 ret = FALSE;
4110 needed += size;
4111 break;
4114 case 7:
4116 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4118 size = sizeof(PRINTER_INFO_7W);
4119 if (size <= cbBuf) {
4120 ptr = pPrinter + size;
4121 cbBuf -= size;
4122 memset(pPrinter, 0, size);
4123 } else {
4124 pi7 = NULL;
4125 cbBuf = 0;
4128 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4129 needed += size;
4130 break;
4134 case 9:
4136 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4138 size = sizeof(PRINTER_INFO_9W);
4139 if(size <= cbBuf) {
4140 ptr = pPrinter + size;
4141 cbBuf -= size;
4142 memset(pPrinter, 0, size);
4143 } else {
4144 pi9 = NULL;
4145 cbBuf = 0;
4148 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4149 needed += size;
4150 break;
4154 default:
4155 FIXME("Unimplemented level %d\n", Level);
4156 SetLastError(ERROR_INVALID_LEVEL);
4157 RegCloseKey(hkeyPrinters);
4158 RegCloseKey(hkeyPrinter);
4159 return FALSE;
4162 RegCloseKey(hkeyPrinter);
4163 RegCloseKey(hkeyPrinters);
4165 TRACE("returning %d needed = %d\n", ret, needed);
4166 if(pcbNeeded) *pcbNeeded = needed;
4167 if(!ret)
4168 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4169 return ret;
4172 /*****************************************************************************
4173 * GetPrinterW [WINSPOOL.@]
4175 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4176 DWORD cbBuf, LPDWORD pcbNeeded)
4178 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4179 TRUE);
4182 /*****************************************************************************
4183 * GetPrinterA [WINSPOOL.@]
4185 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4186 DWORD cbBuf, LPDWORD pcbNeeded)
4188 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4189 FALSE);
4192 /*****************************************************************************
4193 * WINSPOOL_EnumPrinters
4195 * Implementation of EnumPrintersA|W
4197 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4198 DWORD dwLevel, LPBYTE lpbPrinters,
4199 DWORD cbBuf, LPDWORD lpdwNeeded,
4200 LPDWORD lpdwReturned, BOOL unicode)
4203 HKEY hkeyPrinters, hkeyPrinter;
4204 WCHAR PrinterName[255];
4205 DWORD needed = 0, number = 0;
4206 DWORD used, i, left;
4207 PBYTE pi, buf;
4209 if(lpbPrinters)
4210 memset(lpbPrinters, 0, cbBuf);
4211 if(lpdwReturned)
4212 *lpdwReturned = 0;
4213 if(lpdwNeeded)
4214 *lpdwNeeded = 0;
4216 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4217 if(dwType == PRINTER_ENUM_DEFAULT)
4218 return TRUE;
4220 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4221 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4222 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4223 if (!dwType) {
4224 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4225 *lpdwNeeded = 0;
4226 *lpdwReturned = 0;
4227 return TRUE;
4232 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4233 FIXME("dwType = %08x\n", dwType);
4234 SetLastError(ERROR_INVALID_FLAGS);
4235 return FALSE;
4238 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4239 ERROR_SUCCESS) {
4240 ERR("Can't create Printers key\n");
4241 return FALSE;
4244 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4245 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4246 RegCloseKey(hkeyPrinters);
4247 ERR("Can't query Printers key\n");
4248 return FALSE;
4250 TRACE("Found %d printers\n", number);
4252 switch(dwLevel) {
4253 case 1:
4254 used = number * sizeof(PRINTER_INFO_1W);
4255 break;
4256 case 2:
4257 used = number * sizeof(PRINTER_INFO_2W);
4258 break;
4259 case 4:
4260 used = number * sizeof(PRINTER_INFO_4W);
4261 break;
4262 case 5:
4263 used = number * sizeof(PRINTER_INFO_5W);
4264 break;
4266 default:
4267 SetLastError(ERROR_INVALID_LEVEL);
4268 RegCloseKey(hkeyPrinters);
4269 return FALSE;
4271 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4273 for(i = 0; i < number; i++) {
4274 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4275 ERROR_SUCCESS) {
4276 ERR("Can't enum key number %d\n", i);
4277 RegCloseKey(hkeyPrinters);
4278 return FALSE;
4280 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4281 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4282 ERROR_SUCCESS) {
4283 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4284 RegCloseKey(hkeyPrinters);
4285 return FALSE;
4288 if(cbBuf > used) {
4289 buf = lpbPrinters + used;
4290 left = cbBuf - used;
4291 } else {
4292 buf = NULL;
4293 left = 0;
4296 switch(dwLevel) {
4297 case 1:
4298 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4299 left, &needed, unicode);
4300 used += needed;
4301 if(pi) pi += sizeof(PRINTER_INFO_1W);
4302 break;
4303 case 2:
4304 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4305 left, &needed, unicode);
4306 used += needed;
4307 if(pi) pi += sizeof(PRINTER_INFO_2W);
4308 break;
4309 case 4:
4310 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4311 left, &needed, unicode);
4312 used += needed;
4313 if(pi) pi += sizeof(PRINTER_INFO_4W);
4314 break;
4315 case 5:
4316 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4317 left, &needed, unicode);
4318 used += needed;
4319 if(pi) pi += sizeof(PRINTER_INFO_5W);
4320 break;
4321 default:
4322 ERR("Shouldn't be here!\n");
4323 RegCloseKey(hkeyPrinter);
4324 RegCloseKey(hkeyPrinters);
4325 return FALSE;
4327 RegCloseKey(hkeyPrinter);
4329 RegCloseKey(hkeyPrinters);
4331 if(lpdwNeeded)
4332 *lpdwNeeded = used;
4334 if(used > cbBuf) {
4335 if(lpbPrinters)
4336 memset(lpbPrinters, 0, cbBuf);
4337 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4338 return FALSE;
4340 if(lpdwReturned)
4341 *lpdwReturned = number;
4342 SetLastError(ERROR_SUCCESS);
4343 return TRUE;
4347 /******************************************************************
4348 * EnumPrintersW [WINSPOOL.@]
4350 * Enumerates the available printers, print servers and print
4351 * providers, depending on the specified flags, name and level.
4353 * RETURNS:
4355 * If level is set to 1:
4356 * Returns an array of PRINTER_INFO_1 data structures in the
4357 * lpbPrinters buffer.
4359 * If level is set to 2:
4360 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4361 * Returns an array of PRINTER_INFO_2 data structures in the
4362 * lpbPrinters buffer. Note that according to MSDN also an
4363 * OpenPrinter should be performed on every remote printer.
4365 * If level is set to 4 (officially WinNT only):
4366 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4367 * Fast: Only the registry is queried to retrieve printer names,
4368 * no connection to the driver is made.
4369 * Returns an array of PRINTER_INFO_4 data structures in the
4370 * lpbPrinters buffer.
4372 * If level is set to 5 (officially WinNT4/Win9x only):
4373 * Fast: Only the registry is queried to retrieve printer names,
4374 * no connection to the driver is made.
4375 * Returns an array of PRINTER_INFO_5 data structures in the
4376 * lpbPrinters buffer.
4378 * If level set to 3 or 6+:
4379 * returns zero (failure!)
4381 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4382 * for information.
4384 * BUGS:
4385 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4386 * - Only levels 2, 4 and 5 are implemented at the moment.
4387 * - 16-bit printer drivers are not enumerated.
4388 * - Returned amount of bytes used/needed does not match the real Windoze
4389 * implementation (as in this implementation, all strings are part
4390 * of the buffer, whereas Win32 keeps them somewhere else)
4391 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4393 * NOTE:
4394 * - In a regular Wine installation, no registry settings for printers
4395 * exist, which makes this function return an empty list.
4397 BOOL WINAPI EnumPrintersW(
4398 DWORD dwType, /* [in] Types of print objects to enumerate */
4399 LPWSTR lpszName, /* [in] name of objects to enumerate */
4400 DWORD dwLevel, /* [in] type of printer info structure */
4401 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4402 DWORD cbBuf, /* [in] max size of buffer in bytes */
4403 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4404 LPDWORD lpdwReturned /* [out] number of entries returned */
4407 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4408 lpdwNeeded, lpdwReturned, TRUE);
4411 /******************************************************************
4412 * EnumPrintersA [WINSPOOL.@]
4414 * See EnumPrintersW
4417 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4418 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4420 BOOL ret;
4421 UNICODE_STRING pNameU;
4422 LPWSTR pNameW;
4423 LPBYTE pPrintersW;
4425 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4426 pPrinters, cbBuf, pcbNeeded, pcReturned);
4428 pNameW = asciitounicode(&pNameU, pName);
4430 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4431 MS Office need this */
4432 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4434 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4436 RtlFreeUnicodeString(&pNameU);
4437 if (ret) {
4438 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4440 HeapFree(GetProcessHeap(), 0, pPrintersW);
4441 return ret;
4444 /*****************************************************************************
4445 * WINSPOOL_GetDriverInfoFromReg [internal]
4447 * Enters the information from the registry into the DRIVER_INFO struct
4449 * RETURNS
4450 * zero if the printer driver does not exist in the registry
4451 * (only if Level > 1) otherwise nonzero
4453 static BOOL WINSPOOL_GetDriverInfoFromReg(
4454 HKEY hkeyDrivers,
4455 LPWSTR DriverName,
4456 const printenv_t * env,
4457 DWORD Level,
4458 LPBYTE ptr, /* DRIVER_INFO */
4459 LPBYTE pDriverStrings, /* strings buffer */
4460 DWORD cbBuf, /* size of string buffer */
4461 LPDWORD pcbNeeded, /* space needed for str. */
4462 BOOL unicode) /* type of strings */
4464 DWORD size, tmp;
4465 HKEY hkeyDriver;
4466 WCHAR driverdir[MAX_PATH];
4467 DWORD dirlen;
4468 LPBYTE strPtr = pDriverStrings;
4469 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4471 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4472 debugstr_w(DriverName), env,
4473 Level, di, pDriverStrings, cbBuf, unicode);
4475 if (di) ZeroMemory(di, di_sizeof[Level]);
4477 if (unicode) {
4478 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4479 if (*pcbNeeded <= cbBuf)
4480 strcpyW((LPWSTR)strPtr, DriverName);
4482 else
4484 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4485 if (*pcbNeeded <= cbBuf)
4486 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4489 /* pName for level 1 has a different offset! */
4490 if (Level == 1) {
4491 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4492 return TRUE;
4495 /* .cVersion and .pName for level > 1 */
4496 if (di) {
4497 di->cVersion = env->driverversion;
4498 di->pName = (LPWSTR) strPtr;
4499 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4502 /* Reserve Space for the largest subdir and a Backslash*/
4503 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4504 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4505 /* Should never Fail */
4506 return FALSE;
4508 lstrcatW(driverdir, env->versionsubdir);
4509 lstrcatW(driverdir, backslashW);
4511 /* dirlen must not include the terminating zero */
4512 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4513 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4515 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4516 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4517 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4518 return FALSE;
4521 /* pEnvironment */
4522 if (unicode)
4523 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4524 else
4525 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4527 *pcbNeeded += size;
4528 if (*pcbNeeded <= cbBuf) {
4529 if (unicode) {
4530 lstrcpyW((LPWSTR)strPtr, env->envname);
4532 else
4534 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4536 if (di) di->pEnvironment = (LPWSTR)strPtr;
4537 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4540 /* .pDriverPath is the Graphics rendering engine.
4541 The full Path is required to avoid a crash in some apps */
4542 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4543 *pcbNeeded += size;
4544 if (*pcbNeeded <= cbBuf)
4545 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4547 if (di) di->pDriverPath = (LPWSTR)strPtr;
4548 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4551 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4552 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4553 *pcbNeeded += size;
4554 if (*pcbNeeded <= cbBuf)
4555 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4557 if (di) di->pDataFile = (LPWSTR)strPtr;
4558 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4561 /* .pConfigFile is the Driver user Interface */
4562 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4563 *pcbNeeded += size;
4564 if (*pcbNeeded <= cbBuf)
4565 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4567 if (di) di->pConfigFile = (LPWSTR)strPtr;
4568 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4571 if (Level == 2 ) {
4572 RegCloseKey(hkeyDriver);
4573 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4574 return TRUE;
4577 if (Level == 5 ) {
4578 RegCloseKey(hkeyDriver);
4579 FIXME("level 5: incomplete\n");
4580 return TRUE;
4583 /* .pHelpFile */
4584 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4585 *pcbNeeded += size;
4586 if (*pcbNeeded <= cbBuf)
4587 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4589 if (di) di->pHelpFile = (LPWSTR)strPtr;
4590 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4593 /* .pDependentFiles */
4594 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4595 *pcbNeeded += size;
4596 if (*pcbNeeded <= cbBuf)
4597 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4599 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4600 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4602 else if (GetVersion() & 0x80000000) {
4603 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4604 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4605 *pcbNeeded += size;
4606 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4608 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4609 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4612 /* .pMonitorName is the optional Language Monitor */
4613 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4614 *pcbNeeded += size;
4615 if (*pcbNeeded <= cbBuf)
4616 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4618 if (di) di->pMonitorName = (LPWSTR)strPtr;
4619 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4622 /* .pDefaultDataType */
4623 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4624 *pcbNeeded += size;
4625 if(*pcbNeeded <= cbBuf)
4626 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4628 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4629 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4632 if (Level == 3 ) {
4633 RegCloseKey(hkeyDriver);
4634 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4635 return TRUE;
4638 /* .pszzPreviousNames */
4639 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4640 *pcbNeeded += size;
4641 if(*pcbNeeded <= cbBuf)
4642 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4644 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4645 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4648 if (Level == 4 ) {
4649 RegCloseKey(hkeyDriver);
4650 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4651 return TRUE;
4654 /* support is missing, but not important enough for a FIXME */
4655 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4657 /* .pszMfgName */
4658 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4659 *pcbNeeded += size;
4660 if(*pcbNeeded <= cbBuf)
4661 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4663 if (di) di->pszMfgName = (LPWSTR)strPtr;
4664 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4667 /* .pszOEMUrl */
4668 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4669 *pcbNeeded += size;
4670 if(*pcbNeeded <= cbBuf)
4671 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4673 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4674 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4677 /* .pszHardwareID */
4678 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4679 *pcbNeeded += size;
4680 if(*pcbNeeded <= cbBuf)
4681 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4683 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4684 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4687 /* .pszProvider */
4688 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4689 *pcbNeeded += size;
4690 if(*pcbNeeded <= cbBuf)
4691 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4693 if (di) di->pszProvider = (LPWSTR)strPtr;
4694 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4697 if (Level == 6 ) {
4698 RegCloseKey(hkeyDriver);
4699 return TRUE;
4702 /* support is missing, but not important enough for a FIXME */
4703 TRACE("level 8: incomplete\n");
4705 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4706 RegCloseKey(hkeyDriver);
4707 return TRUE;
4710 /*****************************************************************************
4711 * WINSPOOL_GetPrinterDriver
4713 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4714 DWORD Level, LPBYTE pDriverInfo,
4715 DWORD cbBuf, LPDWORD pcbNeeded,
4716 BOOL unicode)
4718 LPCWSTR name;
4719 WCHAR DriverName[100];
4720 DWORD ret, type, size, needed = 0;
4721 LPBYTE ptr = NULL;
4722 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4723 const printenv_t * env;
4725 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4726 Level,pDriverInfo,cbBuf, pcbNeeded);
4729 if (!(name = get_opened_printer_name(hPrinter))) {
4730 SetLastError(ERROR_INVALID_HANDLE);
4731 return FALSE;
4734 if (Level < 1 || Level == 7 || Level > 8) {
4735 SetLastError(ERROR_INVALID_LEVEL);
4736 return FALSE;
4739 env = validate_envW(pEnvironment);
4740 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4742 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4743 ERROR_SUCCESS) {
4744 ERR("Can't create Printers key\n");
4745 return FALSE;
4747 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4748 != ERROR_SUCCESS) {
4749 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4750 RegCloseKey(hkeyPrinters);
4751 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4752 return FALSE;
4754 size = sizeof(DriverName);
4755 DriverName[0] = 0;
4756 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4757 (LPBYTE)DriverName, &size);
4758 RegCloseKey(hkeyPrinter);
4759 RegCloseKey(hkeyPrinters);
4760 if(ret != ERROR_SUCCESS) {
4761 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4762 return FALSE;
4765 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4766 if(!hkeyDrivers) {
4767 ERR("Can't create Drivers key\n");
4768 return FALSE;
4771 size = di_sizeof[Level];
4772 if ((size <= cbBuf) && pDriverInfo)
4773 ptr = pDriverInfo + size;
4775 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4776 env, Level, pDriverInfo, ptr,
4777 (cbBuf < size) ? 0 : cbBuf - size,
4778 &needed, unicode)) {
4779 RegCloseKey(hkeyDrivers);
4780 return FALSE;
4783 RegCloseKey(hkeyDrivers);
4785 if(pcbNeeded) *pcbNeeded = size + needed;
4786 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4787 if(cbBuf >= needed) return TRUE;
4788 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4789 return FALSE;
4792 /*****************************************************************************
4793 * GetPrinterDriverA [WINSPOOL.@]
4795 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4796 DWORD Level, LPBYTE pDriverInfo,
4797 DWORD cbBuf, LPDWORD pcbNeeded)
4799 BOOL ret;
4800 UNICODE_STRING pEnvW;
4801 PWSTR pwstrEnvW;
4803 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4804 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4805 cbBuf, pcbNeeded, FALSE);
4806 RtlFreeUnicodeString(&pEnvW);
4807 return ret;
4809 /*****************************************************************************
4810 * GetPrinterDriverW [WINSPOOL.@]
4812 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4813 DWORD Level, LPBYTE pDriverInfo,
4814 DWORD cbBuf, LPDWORD pcbNeeded)
4816 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4817 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4820 /*****************************************************************************
4821 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4823 * Return the PATH for the Printer-Drivers (UNICODE)
4825 * PARAMS
4826 * pName [I] Servername (NT only) or NULL (local Computer)
4827 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4828 * Level [I] Structure-Level (must be 1)
4829 * pDriverDirectory [O] PTR to Buffer that receives the Result
4830 * cbBuf [I] Size of Buffer at pDriverDirectory
4831 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4832 * required for pDriverDirectory
4834 * RETURNS
4835 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4836 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4837 * if cbBuf is too small
4839 * Native Values returned in pDriverDirectory on Success:
4840 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4841 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4842 *| win9x(Windows 4.0): "%winsysdir%"
4844 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4846 * FIXME
4847 *- Only NULL or "" is supported for pName
4850 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4851 DWORD Level, LPBYTE pDriverDirectory,
4852 DWORD cbBuf, LPDWORD pcbNeeded)
4854 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4855 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4857 if ((backend == NULL) && !load_backend()) return FALSE;
4859 if (Level != 1) {
4860 /* (Level != 1) is ignored in win9x */
4861 SetLastError(ERROR_INVALID_LEVEL);
4862 return FALSE;
4864 if (pcbNeeded == NULL) {
4865 /* (pcbNeeded == NULL) is ignored in win9x */
4866 SetLastError(RPC_X_NULL_REF_POINTER);
4867 return FALSE;
4870 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4871 pDriverDirectory, cbBuf, pcbNeeded);
4876 /*****************************************************************************
4877 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4879 * Return the PATH for the Printer-Drivers (ANSI)
4881 * See GetPrinterDriverDirectoryW.
4883 * NOTES
4884 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4887 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4888 DWORD Level, LPBYTE pDriverDirectory,
4889 DWORD cbBuf, LPDWORD pcbNeeded)
4891 UNICODE_STRING nameW, environmentW;
4892 BOOL ret;
4893 DWORD pcbNeededW;
4894 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4895 WCHAR *driverDirectoryW = NULL;
4897 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4898 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4900 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4902 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4903 else nameW.Buffer = NULL;
4904 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4905 else environmentW.Buffer = NULL;
4907 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4908 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4909 if (ret) {
4910 DWORD needed;
4911 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4912 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4913 if(pcbNeeded)
4914 *pcbNeeded = needed;
4915 ret = (needed <= cbBuf) ? TRUE : FALSE;
4916 } else
4917 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4919 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4921 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4922 RtlFreeUnicodeString(&environmentW);
4923 RtlFreeUnicodeString(&nameW);
4925 return ret;
4928 /*****************************************************************************
4929 * AddPrinterDriverA [WINSPOOL.@]
4931 * See AddPrinterDriverW.
4934 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4936 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4937 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4940 /******************************************************************************
4941 * AddPrinterDriverW (WINSPOOL.@)
4943 * Install a Printer Driver
4945 * PARAMS
4946 * pName [I] Servername or NULL (local Computer)
4947 * level [I] Level for the supplied DRIVER_INFO_*W struct
4948 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4950 * RESULTS
4951 * Success: TRUE
4952 * Failure: FALSE
4955 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4957 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4958 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4961 /*****************************************************************************
4962 * AddPrintProcessorA [WINSPOOL.@]
4964 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4965 LPSTR pPrintProcessorName)
4967 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4968 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4969 return FALSE;
4972 /*****************************************************************************
4973 * AddPrintProcessorW [WINSPOOL.@]
4975 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4976 LPWSTR pPrintProcessorName)
4978 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4979 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4980 return FALSE;
4983 /*****************************************************************************
4984 * AddPrintProvidorA [WINSPOOL.@]
4986 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4988 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4989 return FALSE;
4992 /*****************************************************************************
4993 * AddPrintProvidorW [WINSPOOL.@]
4995 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4997 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4998 return FALSE;
5001 /*****************************************************************************
5002 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5004 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5005 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5007 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5008 pDevModeOutput, pDevModeInput);
5009 return 0;
5012 /*****************************************************************************
5013 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5015 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5016 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5018 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5019 pDevModeOutput, pDevModeInput);
5020 return 0;
5023 /*****************************************************************************
5024 * PrinterProperties [WINSPOOL.@]
5026 * Displays a dialog to set the properties of the printer.
5028 * RETURNS
5029 * nonzero on success or zero on failure
5031 * BUGS
5032 * implemented as stub only
5034 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5035 HANDLE hPrinter /* [in] handle to printer object */
5037 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5038 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5039 return FALSE;
5042 /*****************************************************************************
5043 * EnumJobsA [WINSPOOL.@]
5046 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5047 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5048 LPDWORD pcReturned)
5050 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5051 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5053 if(pcbNeeded) *pcbNeeded = 0;
5054 if(pcReturned) *pcReturned = 0;
5055 return FALSE;
5059 /*****************************************************************************
5060 * EnumJobsW [WINSPOOL.@]
5063 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5064 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5065 LPDWORD pcReturned)
5067 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5068 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5070 if(pcbNeeded) *pcbNeeded = 0;
5071 if(pcReturned) *pcReturned = 0;
5072 return FALSE;
5075 /*****************************************************************************
5076 * WINSPOOL_EnumPrinterDrivers [internal]
5078 * Delivers information about all printer drivers installed on the
5079 * localhost or a given server
5081 * RETURNS
5082 * nonzero on success or zero on failure. If the buffer for the returned
5083 * information is too small the function will return an error
5085 * BUGS
5086 * - only implemented for localhost, foreign hosts will return an error
5088 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5089 DWORD Level, LPBYTE pDriverInfo,
5090 DWORD cbBuf, LPDWORD pcbNeeded,
5091 LPDWORD pcReturned, BOOL unicode)
5093 { HKEY hkeyDrivers;
5094 DWORD i, needed, number = 0, size = 0;
5095 WCHAR DriverNameW[255];
5096 PBYTE ptr;
5097 const printenv_t * env;
5099 TRACE("%s,%s,%d,%p,%d,%d\n",
5100 debugstr_w(pName), debugstr_w(pEnvironment),
5101 Level, pDriverInfo, cbBuf, unicode);
5103 /* check for local drivers */
5104 if((pName) && (pName[0])) {
5105 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5106 SetLastError(ERROR_ACCESS_DENIED);
5107 return FALSE;
5110 env = validate_envW(pEnvironment);
5111 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5113 /* check input parameter */
5114 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5115 SetLastError(ERROR_INVALID_LEVEL);
5116 return FALSE;
5119 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5120 SetLastError(RPC_X_NULL_REF_POINTER);
5121 return FALSE;
5124 /* initialize return values */
5125 if(pDriverInfo)
5126 memset( pDriverInfo, 0, cbBuf);
5127 *pcbNeeded = 0;
5128 *pcReturned = 0;
5130 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5131 if(!hkeyDrivers) {
5132 ERR("Can't open Drivers key\n");
5133 return FALSE;
5136 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5137 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5138 RegCloseKey(hkeyDrivers);
5139 ERR("Can't query Drivers key\n");
5140 return FALSE;
5142 TRACE("Found %d Drivers\n", number);
5144 /* get size of single struct
5145 * unicode and ascii structure have the same size
5147 size = di_sizeof[Level];
5149 /* calculate required buffer size */
5150 *pcbNeeded = size * number;
5152 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5153 i < number;
5154 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5155 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5156 != ERROR_SUCCESS) {
5157 ERR("Can't enum key number %d\n", i);
5158 RegCloseKey(hkeyDrivers);
5159 return FALSE;
5161 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5162 env, Level, ptr,
5163 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5164 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5165 &needed, unicode)) {
5166 RegCloseKey(hkeyDrivers);
5167 return FALSE;
5169 *pcbNeeded += needed;
5172 RegCloseKey(hkeyDrivers);
5174 if(cbBuf < *pcbNeeded){
5175 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5176 return FALSE;
5179 *pcReturned = number;
5180 return TRUE;
5183 /*****************************************************************************
5184 * EnumPrinterDriversW [WINSPOOL.@]
5186 * see function EnumPrinterDrivers for RETURNS, BUGS
5188 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5189 LPBYTE pDriverInfo, DWORD cbBuf,
5190 LPDWORD pcbNeeded, LPDWORD pcReturned)
5192 static const WCHAR allW[] = {'a','l','l',0};
5194 if (pEnvironment && !strcmpW(pEnvironment, allW))
5196 BOOL ret;
5197 DWORD i, needed, returned, bufsize = cbBuf;
5199 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5201 needed = returned = 0;
5202 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5203 pDriverInfo, bufsize, &needed, &returned, TRUE);
5204 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5205 else if (ret)
5207 bufsize -= needed;
5208 if (pDriverInfo) pDriverInfo += needed;
5209 if (pcReturned) *pcReturned += returned;
5211 if (pcbNeeded) *pcbNeeded += needed;
5213 return ret;
5215 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5216 cbBuf, pcbNeeded, pcReturned, TRUE);
5219 /*****************************************************************************
5220 * EnumPrinterDriversA [WINSPOOL.@]
5222 * see function EnumPrinterDrivers for RETURNS, BUGS
5224 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5225 LPBYTE pDriverInfo, DWORD cbBuf,
5226 LPDWORD pcbNeeded, LPDWORD pcReturned)
5228 BOOL ret;
5229 UNICODE_STRING pNameW, pEnvironmentW;
5230 PWSTR pwstrNameW, pwstrEnvironmentW;
5232 pwstrNameW = asciitounicode(&pNameW, pName);
5233 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5235 if (pEnvironment && !strcmp(pEnvironment, "all"))
5237 DWORD i, needed, returned, bufsize = cbBuf;
5239 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5241 needed = returned = 0;
5242 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
5243 pDriverInfo, bufsize, &needed, &returned, FALSE);
5244 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
5245 else if (ret)
5247 bufsize -= needed;
5248 if (pDriverInfo) pDriverInfo += needed;
5249 if (pcReturned) *pcReturned += returned;
5251 if (pcbNeeded) *pcbNeeded += needed;
5254 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5255 Level, pDriverInfo, cbBuf, pcbNeeded,
5256 pcReturned, FALSE);
5257 RtlFreeUnicodeString(&pNameW);
5258 RtlFreeUnicodeString(&pEnvironmentW);
5260 return ret;
5263 /******************************************************************************
5264 * EnumPortsA (WINSPOOL.@)
5266 * See EnumPortsW.
5269 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5270 LPDWORD pcbNeeded, LPDWORD pcReturned)
5272 BOOL res;
5273 LPBYTE bufferW = NULL;
5274 LPWSTR nameW = NULL;
5275 DWORD needed = 0;
5276 DWORD numentries = 0;
5277 INT len;
5279 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5280 cbBuf, pcbNeeded, pcReturned);
5282 /* convert servername to unicode */
5283 if (pName) {
5284 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5285 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5286 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5288 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5289 needed = cbBuf * sizeof(WCHAR);
5290 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5291 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5293 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5294 if (pcbNeeded) needed = *pcbNeeded;
5295 /* HeapReAlloc return NULL, when bufferW was NULL */
5296 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5297 HeapAlloc(GetProcessHeap(), 0, needed);
5299 /* Try again with the large Buffer */
5300 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5302 needed = pcbNeeded ? *pcbNeeded : 0;
5303 numentries = pcReturned ? *pcReturned : 0;
5306 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5307 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5309 if (res) {
5310 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5311 DWORD entrysize = 0;
5312 DWORD index;
5313 LPSTR ptr;
5314 LPPORT_INFO_2W pi2w;
5315 LPPORT_INFO_2A pi2a;
5317 needed = 0;
5318 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5320 /* First pass: calculate the size for all Entries */
5321 pi2w = (LPPORT_INFO_2W) bufferW;
5322 pi2a = (LPPORT_INFO_2A) pPorts;
5323 index = 0;
5324 while (index < numentries) {
5325 index++;
5326 needed += entrysize; /* PORT_INFO_?A */
5327 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5329 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5330 NULL, 0, NULL, NULL);
5331 if (Level > 1) {
5332 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5333 NULL, 0, NULL, NULL);
5334 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5335 NULL, 0, NULL, NULL);
5337 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5338 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5339 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5342 /* check for errors and quit on failure */
5343 if (cbBuf < needed) {
5344 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5345 res = FALSE;
5346 goto cleanup;
5348 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5349 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5350 cbBuf -= len ; /* free Bytes in the user-Buffer */
5351 pi2w = (LPPORT_INFO_2W) bufferW;
5352 pi2a = (LPPORT_INFO_2A) pPorts;
5353 index = 0;
5354 /* Second Pass: Fill the User Buffer (if we have one) */
5355 while ((index < numentries) && pPorts) {
5356 index++;
5357 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5358 pi2a->pPortName = ptr;
5359 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5360 ptr, cbBuf , NULL, NULL);
5361 ptr += len;
5362 cbBuf -= len;
5363 if (Level > 1) {
5364 pi2a->pMonitorName = ptr;
5365 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5366 ptr, cbBuf, NULL, NULL);
5367 ptr += len;
5368 cbBuf -= len;
5370 pi2a->pDescription = ptr;
5371 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5372 ptr, cbBuf, NULL, NULL);
5373 ptr += len;
5374 cbBuf -= len;
5376 pi2a->fPortType = pi2w->fPortType;
5377 pi2a->Reserved = 0; /* documented: "must be zero" */
5380 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5381 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5382 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5386 cleanup:
5387 if (pcbNeeded) *pcbNeeded = needed;
5388 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5390 HeapFree(GetProcessHeap(), 0, nameW);
5391 HeapFree(GetProcessHeap(), 0, bufferW);
5393 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5394 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5396 return (res);
5400 /******************************************************************************
5401 * EnumPortsW (WINSPOOL.@)
5403 * Enumerate available Ports
5405 * PARAMS
5406 * pName [I] Servername or NULL (local Computer)
5407 * Level [I] Structure-Level (1 or 2)
5408 * pPorts [O] PTR to Buffer that receives the Result
5409 * cbBuf [I] Size of Buffer at pPorts
5410 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5411 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5413 * RETURNS
5414 * Success: TRUE
5415 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5418 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5421 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5422 cbBuf, pcbNeeded, pcReturned);
5424 if ((backend == NULL) && !load_backend()) return FALSE;
5426 /* Level is not checked in win9x */
5427 if (!Level || (Level > 2)) {
5428 WARN("level (%d) is ignored in win9x\n", Level);
5429 SetLastError(ERROR_INVALID_LEVEL);
5430 return FALSE;
5432 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5433 SetLastError(RPC_X_NULL_REF_POINTER);
5434 return FALSE;
5437 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5440 /******************************************************************************
5441 * GetDefaultPrinterW (WINSPOOL.@)
5443 * FIXME
5444 * This function must read the value from data 'device' of key
5445 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5447 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5449 BOOL retval = TRUE;
5450 DWORD insize, len;
5451 WCHAR *buffer, *ptr;
5453 if (!namesize)
5455 SetLastError(ERROR_INVALID_PARAMETER);
5456 return FALSE;
5459 /* make the buffer big enough for the stuff from the profile/registry,
5460 * the content must fit into the local buffer to compute the correct
5461 * size even if the extern buffer is too small or not given.
5462 * (20 for ,driver,port) */
5463 insize = *namesize;
5464 len = max(100, (insize + 20));
5465 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5467 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5469 SetLastError (ERROR_FILE_NOT_FOUND);
5470 retval = FALSE;
5471 goto end;
5473 TRACE("%s\n", debugstr_w(buffer));
5475 if ((ptr = strchrW(buffer, ',')) == NULL)
5477 SetLastError(ERROR_INVALID_NAME);
5478 retval = FALSE;
5479 goto end;
5482 *ptr = 0;
5483 *namesize = strlenW(buffer) + 1;
5484 if(!name || (*namesize > insize))
5486 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5487 retval = FALSE;
5488 goto end;
5490 strcpyW(name, buffer);
5492 end:
5493 HeapFree( GetProcessHeap(), 0, buffer);
5494 return retval;
5498 /******************************************************************************
5499 * GetDefaultPrinterA (WINSPOOL.@)
5501 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5503 BOOL retval = TRUE;
5504 DWORD insize = 0;
5505 WCHAR *bufferW = NULL;
5507 if (!namesize)
5509 SetLastError(ERROR_INVALID_PARAMETER);
5510 return FALSE;
5513 if(name && *namesize) {
5514 insize = *namesize;
5515 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5518 if(!GetDefaultPrinterW( bufferW, namesize)) {
5519 retval = FALSE;
5520 goto end;
5523 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5524 NULL, NULL);
5525 if (!*namesize)
5527 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5528 retval = FALSE;
5530 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5532 end:
5533 HeapFree( GetProcessHeap(), 0, bufferW);
5534 return retval;
5538 /******************************************************************************
5539 * SetDefaultPrinterW (WINSPOOL.204)
5541 * Set the Name of the Default Printer
5543 * PARAMS
5544 * pszPrinter [I] Name of the Printer or NULL
5546 * RETURNS
5547 * Success: True
5548 * Failure: FALSE
5550 * NOTES
5551 * When the Parameter is NULL or points to an Empty String and
5552 * a Default Printer was already present, then this Function changes nothing.
5553 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5554 * the First enumerated local Printer is used.
5557 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5560 TRACE("(%s)\n", debugstr_w(pszPrinter));
5562 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5563 return FALSE;
5566 /******************************************************************************
5567 * SetDefaultPrinterA (WINSPOOL.202)
5569 * See SetDefaultPrinterW.
5572 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5575 TRACE("(%s)\n", debugstr_a(pszPrinter));
5577 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5578 return FALSE;
5582 /******************************************************************************
5583 * SetPrinterDataExA (WINSPOOL.@)
5585 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5586 LPCSTR pValueName, DWORD Type,
5587 LPBYTE pData, DWORD cbData)
5589 HKEY hkeyPrinter, hkeySubkey;
5590 DWORD ret;
5592 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5593 debugstr_a(pValueName), Type, pData, cbData);
5595 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5596 != ERROR_SUCCESS)
5597 return ret;
5599 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5600 != ERROR_SUCCESS) {
5601 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5602 RegCloseKey(hkeyPrinter);
5603 return ret;
5605 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5606 RegCloseKey(hkeySubkey);
5607 RegCloseKey(hkeyPrinter);
5608 return ret;
5611 /******************************************************************************
5612 * SetPrinterDataExW (WINSPOOL.@)
5614 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5615 LPCWSTR pValueName, DWORD Type,
5616 LPBYTE pData, DWORD cbData)
5618 HKEY hkeyPrinter, hkeySubkey;
5619 DWORD ret;
5621 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5622 debugstr_w(pValueName), Type, pData, cbData);
5624 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5625 != ERROR_SUCCESS)
5626 return ret;
5628 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5629 != ERROR_SUCCESS) {
5630 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5631 RegCloseKey(hkeyPrinter);
5632 return ret;
5634 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5635 RegCloseKey(hkeySubkey);
5636 RegCloseKey(hkeyPrinter);
5637 return ret;
5640 /******************************************************************************
5641 * SetPrinterDataA (WINSPOOL.@)
5643 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5644 LPBYTE pData, DWORD cbData)
5646 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5647 pData, cbData);
5650 /******************************************************************************
5651 * SetPrinterDataW (WINSPOOL.@)
5653 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5654 LPBYTE pData, DWORD cbData)
5656 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5657 pData, cbData);
5660 /******************************************************************************
5661 * GetPrinterDataExA (WINSPOOL.@)
5663 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5664 LPCSTR pValueName, LPDWORD pType,
5665 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5667 HKEY hkeyPrinter, hkeySubkey;
5668 DWORD ret;
5670 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5671 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5672 pcbNeeded);
5674 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5675 != ERROR_SUCCESS)
5676 return ret;
5678 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5679 != ERROR_SUCCESS) {
5680 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5681 RegCloseKey(hkeyPrinter);
5682 return ret;
5684 *pcbNeeded = nSize;
5685 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5686 RegCloseKey(hkeySubkey);
5687 RegCloseKey(hkeyPrinter);
5688 return ret;
5691 /******************************************************************************
5692 * GetPrinterDataExW (WINSPOOL.@)
5694 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5695 LPCWSTR pValueName, LPDWORD pType,
5696 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5698 HKEY hkeyPrinter, hkeySubkey;
5699 DWORD ret;
5701 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5702 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5703 pcbNeeded);
5705 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5706 != ERROR_SUCCESS)
5707 return ret;
5709 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5710 != ERROR_SUCCESS) {
5711 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5712 RegCloseKey(hkeyPrinter);
5713 return ret;
5715 *pcbNeeded = nSize;
5716 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5717 RegCloseKey(hkeySubkey);
5718 RegCloseKey(hkeyPrinter);
5719 return ret;
5722 /******************************************************************************
5723 * GetPrinterDataA (WINSPOOL.@)
5725 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5726 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5728 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5729 pData, nSize, pcbNeeded);
5732 /******************************************************************************
5733 * GetPrinterDataW (WINSPOOL.@)
5735 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5736 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5738 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5739 pData, nSize, pcbNeeded);
5742 /*******************************************************************************
5743 * EnumPrinterDataExW [WINSPOOL.@]
5745 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5746 LPBYTE pEnumValues, DWORD cbEnumValues,
5747 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5749 HKEY hkPrinter, hkSubKey;
5750 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5751 cbValueNameLen, cbMaxValueLen, cbValueLen,
5752 cbBufSize, dwType;
5753 LPWSTR lpValueName;
5754 HANDLE hHeap;
5755 PBYTE lpValue;
5756 PPRINTER_ENUM_VALUESW ppev;
5758 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5760 if (pKeyName == NULL || *pKeyName == 0)
5761 return ERROR_INVALID_PARAMETER;
5763 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5764 if (ret != ERROR_SUCCESS)
5766 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5767 hPrinter, ret);
5768 return ret;
5771 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5772 if (ret != ERROR_SUCCESS)
5774 r = RegCloseKey (hkPrinter);
5775 if (r != ERROR_SUCCESS)
5776 WARN ("RegCloseKey returned %i\n", r);
5777 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5778 debugstr_w (pKeyName), ret);
5779 return ret;
5782 ret = RegCloseKey (hkPrinter);
5783 if (ret != ERROR_SUCCESS)
5785 ERR ("RegCloseKey returned %i\n", ret);
5786 r = RegCloseKey (hkSubKey);
5787 if (r != ERROR_SUCCESS)
5788 WARN ("RegCloseKey returned %i\n", r);
5789 return ret;
5792 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5793 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5794 if (ret != ERROR_SUCCESS)
5796 r = RegCloseKey (hkSubKey);
5797 if (r != ERROR_SUCCESS)
5798 WARN ("RegCloseKey returned %i\n", r);
5799 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5800 return ret;
5803 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5804 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5806 if (cValues == 0) /* empty key */
5808 r = RegCloseKey (hkSubKey);
5809 if (r != ERROR_SUCCESS)
5810 WARN ("RegCloseKey returned %i\n", r);
5811 *pcbEnumValues = *pnEnumValues = 0;
5812 return ERROR_SUCCESS;
5815 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5817 hHeap = GetProcessHeap ();
5818 if (hHeap == NULL)
5820 ERR ("GetProcessHeap failed\n");
5821 r = RegCloseKey (hkSubKey);
5822 if (r != ERROR_SUCCESS)
5823 WARN ("RegCloseKey returned %i\n", r);
5824 return ERROR_OUTOFMEMORY;
5827 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5828 if (lpValueName == NULL)
5830 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5831 r = RegCloseKey (hkSubKey);
5832 if (r != ERROR_SUCCESS)
5833 WARN ("RegCloseKey returned %i\n", r);
5834 return ERROR_OUTOFMEMORY;
5837 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5838 if (lpValue == NULL)
5840 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5841 if (HeapFree (hHeap, 0, lpValueName) == 0)
5842 WARN ("HeapFree failed with code %i\n", GetLastError ());
5843 r = RegCloseKey (hkSubKey);
5844 if (r != ERROR_SUCCESS)
5845 WARN ("RegCloseKey returned %i\n", r);
5846 return ERROR_OUTOFMEMORY;
5849 TRACE ("pass 1: calculating buffer required for all names and values\n");
5851 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5853 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5855 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5857 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5858 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5859 NULL, NULL, lpValue, &cbValueLen);
5860 if (ret != ERROR_SUCCESS)
5862 if (HeapFree (hHeap, 0, lpValue) == 0)
5863 WARN ("HeapFree failed with code %i\n", GetLastError ());
5864 if (HeapFree (hHeap, 0, lpValueName) == 0)
5865 WARN ("HeapFree failed with code %i\n", GetLastError ());
5866 r = RegCloseKey (hkSubKey);
5867 if (r != ERROR_SUCCESS)
5868 WARN ("RegCloseKey returned %i\n", r);
5869 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5870 return ret;
5873 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5874 debugstr_w (lpValueName), dwIndex,
5875 cbValueNameLen + 1, cbValueLen);
5877 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5878 cbBufSize += cbValueLen;
5881 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5883 *pcbEnumValues = cbBufSize;
5884 *pnEnumValues = cValues;
5886 if (cbEnumValues < cbBufSize) /* buffer too small */
5888 if (HeapFree (hHeap, 0, lpValue) == 0)
5889 WARN ("HeapFree failed with code %i\n", GetLastError ());
5890 if (HeapFree (hHeap, 0, lpValueName) == 0)
5891 WARN ("HeapFree failed with code %i\n", GetLastError ());
5892 r = RegCloseKey (hkSubKey);
5893 if (r != ERROR_SUCCESS)
5894 WARN ("RegCloseKey returned %i\n", r);
5895 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5896 return ERROR_MORE_DATA;
5899 TRACE ("pass 2: copying all names and values to buffer\n");
5901 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5902 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5904 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5906 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5907 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5908 NULL, &dwType, lpValue, &cbValueLen);
5909 if (ret != ERROR_SUCCESS)
5911 if (HeapFree (hHeap, 0, lpValue) == 0)
5912 WARN ("HeapFree failed with code %i\n", GetLastError ());
5913 if (HeapFree (hHeap, 0, lpValueName) == 0)
5914 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 r = RegCloseKey (hkSubKey);
5916 if (r != ERROR_SUCCESS)
5917 WARN ("RegCloseKey returned %i\n", r);
5918 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5919 return ret;
5922 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5923 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5924 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5925 pEnumValues += cbValueNameLen;
5927 /* return # of *bytes* (including trailing \0), not # of chars */
5928 ppev[dwIndex].cbValueName = cbValueNameLen;
5930 ppev[dwIndex].dwType = dwType;
5932 memcpy (pEnumValues, lpValue, cbValueLen);
5933 ppev[dwIndex].pData = pEnumValues;
5934 pEnumValues += cbValueLen;
5936 ppev[dwIndex].cbData = cbValueLen;
5938 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5939 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5942 if (HeapFree (hHeap, 0, lpValue) == 0)
5944 ret = GetLastError ();
5945 ERR ("HeapFree failed with code %i\n", ret);
5946 if (HeapFree (hHeap, 0, lpValueName) == 0)
5947 WARN ("HeapFree failed with code %i\n", GetLastError ());
5948 r = RegCloseKey (hkSubKey);
5949 if (r != ERROR_SUCCESS)
5950 WARN ("RegCloseKey returned %i\n", r);
5951 return ret;
5954 if (HeapFree (hHeap, 0, lpValueName) == 0)
5956 ret = GetLastError ();
5957 ERR ("HeapFree failed with code %i\n", ret);
5958 r = RegCloseKey (hkSubKey);
5959 if (r != ERROR_SUCCESS)
5960 WARN ("RegCloseKey returned %i\n", r);
5961 return ret;
5964 ret = RegCloseKey (hkSubKey);
5965 if (ret != ERROR_SUCCESS)
5967 ERR ("RegCloseKey returned %i\n", ret);
5968 return ret;
5971 return ERROR_SUCCESS;
5974 /*******************************************************************************
5975 * EnumPrinterDataExA [WINSPOOL.@]
5977 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5978 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5979 * what Windows 2000 SP1 does.
5982 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5983 LPBYTE pEnumValues, DWORD cbEnumValues,
5984 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5986 INT len;
5987 LPWSTR pKeyNameW;
5988 DWORD ret, dwIndex, dwBufSize;
5989 HANDLE hHeap;
5990 LPSTR pBuffer;
5992 TRACE ("%p %s\n", hPrinter, pKeyName);
5994 if (pKeyName == NULL || *pKeyName == 0)
5995 return ERROR_INVALID_PARAMETER;
5997 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5998 if (len == 0)
6000 ret = GetLastError ();
6001 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6002 return ret;
6005 hHeap = GetProcessHeap ();
6006 if (hHeap == NULL)
6008 ERR ("GetProcessHeap failed\n");
6009 return ERROR_OUTOFMEMORY;
6012 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6013 if (pKeyNameW == NULL)
6015 ERR ("Failed to allocate %i bytes from process heap\n",
6016 (LONG)(len * sizeof (WCHAR)));
6017 return ERROR_OUTOFMEMORY;
6020 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6022 ret = GetLastError ();
6023 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6024 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6025 WARN ("HeapFree failed with code %i\n", GetLastError ());
6026 return ret;
6029 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6030 pcbEnumValues, pnEnumValues);
6031 if (ret != ERROR_SUCCESS)
6033 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6034 WARN ("HeapFree failed with code %i\n", GetLastError ());
6035 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6036 return ret;
6039 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6041 ret = GetLastError ();
6042 ERR ("HeapFree failed with code %i\n", ret);
6043 return ret;
6046 if (*pnEnumValues == 0) /* empty key */
6047 return ERROR_SUCCESS;
6049 dwBufSize = 0;
6050 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6052 PPRINTER_ENUM_VALUESW ppev =
6053 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6055 if (dwBufSize < ppev->cbValueName)
6056 dwBufSize = ppev->cbValueName;
6058 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6059 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6060 dwBufSize = ppev->cbData;
6063 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6065 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6066 if (pBuffer == NULL)
6068 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6069 return ERROR_OUTOFMEMORY;
6072 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6074 PPRINTER_ENUM_VALUESW ppev =
6075 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6077 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6078 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6079 NULL);
6080 if (len == 0)
6082 ret = GetLastError ();
6083 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6084 if (HeapFree (hHeap, 0, pBuffer) == 0)
6085 WARN ("HeapFree failed with code %i\n", GetLastError ());
6086 return ret;
6089 memcpy (ppev->pValueName, pBuffer, len);
6091 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6093 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6094 ppev->dwType != REG_MULTI_SZ)
6095 continue;
6097 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6098 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6099 if (len == 0)
6101 ret = GetLastError ();
6102 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6103 if (HeapFree (hHeap, 0, pBuffer) == 0)
6104 WARN ("HeapFree failed with code %i\n", GetLastError ());
6105 return ret;
6108 memcpy (ppev->pData, pBuffer, len);
6110 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6111 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6114 if (HeapFree (hHeap, 0, pBuffer) == 0)
6116 ret = GetLastError ();
6117 ERR ("HeapFree failed with code %i\n", ret);
6118 return ret;
6121 return ERROR_SUCCESS;
6124 /******************************************************************************
6125 * AbortPrinter (WINSPOOL.@)
6127 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6129 FIXME("(%p), stub!\n", hPrinter);
6130 return TRUE;
6133 /******************************************************************************
6134 * AddPortA (WINSPOOL.@)
6136 * See AddPortW.
6139 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6141 LPWSTR nameW = NULL;
6142 LPWSTR monitorW = NULL;
6143 DWORD len;
6144 BOOL res;
6146 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6148 if (pName) {
6149 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6150 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6151 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6154 if (pMonitorName) {
6155 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6156 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6157 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6159 res = AddPortW(nameW, hWnd, monitorW);
6160 HeapFree(GetProcessHeap(), 0, nameW);
6161 HeapFree(GetProcessHeap(), 0, monitorW);
6162 return res;
6165 /******************************************************************************
6166 * AddPortW (WINSPOOL.@)
6168 * Add a Port for a specific Monitor
6170 * PARAMS
6171 * pName [I] Servername or NULL (local Computer)
6172 * hWnd [I] Handle to parent Window for the Dialog-Box
6173 * pMonitorName [I] Name of the Monitor that manage the Port
6175 * RETURNS
6176 * Success: TRUE
6177 * Failure: FALSE
6180 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6182 monitor_t * pm;
6183 monitor_t * pui;
6184 DWORD res;
6186 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6188 if (pName && pName[0]) {
6189 SetLastError(ERROR_INVALID_PARAMETER);
6190 return FALSE;
6193 if (!pMonitorName) {
6194 SetLastError(RPC_X_NULL_REF_POINTER);
6195 return FALSE;
6198 /* an empty Monitorname is Invalid */
6199 if (!pMonitorName[0]) {
6200 SetLastError(ERROR_NOT_SUPPORTED);
6201 return FALSE;
6204 pm = monitor_load(pMonitorName, NULL);
6205 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6206 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6207 TRACE("got %d with %u\n", res, GetLastError());
6208 res = TRUE;
6210 else
6212 pui = monitor_loadui(pm);
6213 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6214 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6215 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6216 TRACE("got %d with %u\n", res, GetLastError());
6217 res = TRUE;
6219 else
6221 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6222 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6224 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6225 SetLastError(ERROR_NOT_SUPPORTED);
6226 res = FALSE;
6228 monitor_unload(pui);
6230 monitor_unload(pm);
6231 TRACE("returning %d with %u\n", res, GetLastError());
6232 return res;
6235 /******************************************************************************
6236 * AddPortExA (WINSPOOL.@)
6238 * See AddPortExW.
6241 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6243 PORT_INFO_2W pi2W;
6244 PORT_INFO_2A * pi2A;
6245 LPWSTR nameW = NULL;
6246 LPWSTR monitorW = NULL;
6247 DWORD len;
6248 BOOL res;
6250 pi2A = (PORT_INFO_2A *) pBuffer;
6252 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6253 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6255 if ((level < 1) || (level > 2)) {
6256 SetLastError(ERROR_INVALID_LEVEL);
6257 return FALSE;
6260 if (!pi2A) {
6261 SetLastError(ERROR_INVALID_PARAMETER);
6262 return FALSE;
6265 if (pName) {
6266 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6267 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6268 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6271 if (pMonitorName) {
6272 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6273 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6274 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6277 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6279 if (pi2A->pPortName) {
6280 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6281 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6282 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6285 if (level > 1) {
6286 if (pi2A->pMonitorName) {
6287 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6288 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6289 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6292 if (pi2A->pDescription) {
6293 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6294 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6295 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6297 pi2W.fPortType = pi2A->fPortType;
6298 pi2W.Reserved = pi2A->Reserved;
6301 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6303 HeapFree(GetProcessHeap(), 0, nameW);
6304 HeapFree(GetProcessHeap(), 0, monitorW);
6305 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6306 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6307 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6308 return res;
6312 /******************************************************************************
6313 * AddPortExW (WINSPOOL.@)
6315 * Add a Port for a specific Monitor, without presenting a user interface
6317 * PARAMS
6318 * pName [I] Servername or NULL (local Computer)
6319 * level [I] Structure-Level (1 or 2) for pBuffer
6320 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6321 * pMonitorName [I] Name of the Monitor that manage the Port
6323 * RETURNS
6324 * Success: TRUE
6325 * Failure: FALSE
6328 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6330 PORT_INFO_2W * pi2;
6331 monitor_t * pm;
6332 DWORD res = FALSE;
6334 pi2 = (PORT_INFO_2W *) pBuffer;
6336 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6337 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6338 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6339 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6342 if ((level < 1) || (level > 2)) {
6343 SetLastError(ERROR_INVALID_LEVEL);
6344 return FALSE;
6347 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6348 SetLastError(ERROR_INVALID_PARAMETER);
6349 return FALSE;
6352 /* load the Monitor */
6353 pm = monitor_load(pMonitorName, NULL);
6354 if (!pm) {
6355 SetLastError(ERROR_INVALID_PARAMETER);
6356 return FALSE;
6359 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6360 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6361 TRACE("got %u with %u\n", res, GetLastError());
6363 else
6365 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6367 monitor_unload(pm);
6368 return res;
6371 /******************************************************************************
6372 * AddPrinterConnectionA (WINSPOOL.@)
6374 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6376 FIXME("%s\n", debugstr_a(pName));
6377 return FALSE;
6380 /******************************************************************************
6381 * AddPrinterConnectionW (WINSPOOL.@)
6383 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6385 FIXME("%s\n", debugstr_w(pName));
6386 return FALSE;
6389 /******************************************************************************
6390 * AddPrinterDriverExW (WINSPOOL.@)
6392 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6394 * PARAMS
6395 * pName [I] Servername or NULL (local Computer)
6396 * level [I] Level for the supplied DRIVER_INFO_*W struct
6397 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6398 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6400 * RESULTS
6401 * Success: TRUE
6402 * Failure: FALSE
6405 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6407 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6409 if ((backend == NULL) && !load_backend()) return FALSE;
6411 if (level < 2 || level == 5 || level == 7 || level > 8) {
6412 SetLastError(ERROR_INVALID_LEVEL);
6413 return FALSE;
6416 if (!pDriverInfo) {
6417 SetLastError(ERROR_INVALID_PARAMETER);
6418 return FALSE;
6421 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6424 /******************************************************************************
6425 * AddPrinterDriverExA (WINSPOOL.@)
6427 * See AddPrinterDriverExW.
6430 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6432 DRIVER_INFO_8A *diA;
6433 DRIVER_INFO_8W diW;
6434 LPWSTR nameW = NULL;
6435 DWORD lenA;
6436 DWORD len;
6437 DWORD res = FALSE;
6439 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6441 diA = (DRIVER_INFO_8A *) pDriverInfo;
6442 ZeroMemory(&diW, sizeof(diW));
6444 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6445 SetLastError(ERROR_INVALID_LEVEL);
6446 return FALSE;
6449 if (diA == NULL) {
6450 SetLastError(ERROR_INVALID_PARAMETER);
6451 return FALSE;
6454 /* convert servername to unicode */
6455 if (pName) {
6456 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6457 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6458 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6461 /* common fields */
6462 diW.cVersion = diA->cVersion;
6464 if (diA->pName) {
6465 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6466 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6467 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6470 if (diA->pEnvironment) {
6471 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6472 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6473 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6476 if (diA->pDriverPath) {
6477 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6478 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6479 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6482 if (diA->pDataFile) {
6483 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6484 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6485 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6488 if (diA->pConfigFile) {
6489 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6490 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6491 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6494 if ((Level > 2) && diA->pDependentFiles) {
6495 lenA = multi_sz_lenA(diA->pDependentFiles);
6496 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6497 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6498 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6501 if ((Level > 2) && diA->pMonitorName) {
6502 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6503 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6504 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6507 if ((Level > 3) && diA->pDefaultDataType) {
6508 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6509 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6510 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6513 if ((Level > 3) && diA->pszzPreviousNames) {
6514 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6515 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6516 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6517 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6520 if ((Level > 5) && diA->pszMfgName) {
6521 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6522 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6523 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6526 if ((Level > 5) && diA->pszOEMUrl) {
6527 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6528 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6529 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6532 if ((Level > 5) && diA->pszHardwareID) {
6533 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6534 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6535 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6538 if ((Level > 5) && diA->pszProvider) {
6539 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6540 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6541 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6544 if (Level > 7) {
6545 FIXME("level %u is incomplete\n", Level);
6548 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6549 TRACE("got %u with %u\n", res, GetLastError());
6550 HeapFree(GetProcessHeap(), 0, nameW);
6551 HeapFree(GetProcessHeap(), 0, diW.pName);
6552 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6553 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6554 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6555 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6556 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6557 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6558 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6559 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6560 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6561 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6562 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6563 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6565 TRACE("=> %u with %u\n", res, GetLastError());
6566 return res;
6569 /******************************************************************************
6570 * ConfigurePortA (WINSPOOL.@)
6572 * See ConfigurePortW.
6575 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6577 LPWSTR nameW = NULL;
6578 LPWSTR portW = NULL;
6579 INT len;
6580 DWORD res;
6582 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6584 /* convert servername to unicode */
6585 if (pName) {
6586 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6587 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6588 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6591 /* convert portname to unicode */
6592 if (pPortName) {
6593 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6594 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6595 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6598 res = ConfigurePortW(nameW, hWnd, portW);
6599 HeapFree(GetProcessHeap(), 0, nameW);
6600 HeapFree(GetProcessHeap(), 0, portW);
6601 return res;
6604 /******************************************************************************
6605 * ConfigurePortW (WINSPOOL.@)
6607 * Display the Configuration-Dialog for a specific Port
6609 * PARAMS
6610 * pName [I] Servername or NULL (local Computer)
6611 * hWnd [I] Handle to parent Window for the Dialog-Box
6612 * pPortName [I] Name of the Port, that should be configured
6614 * RETURNS
6615 * Success: TRUE
6616 * Failure: FALSE
6619 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6621 monitor_t * pm;
6622 monitor_t * pui;
6623 DWORD res;
6625 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6627 if (pName && pName[0]) {
6628 SetLastError(ERROR_INVALID_PARAMETER);
6629 return FALSE;
6632 if (!pPortName) {
6633 SetLastError(RPC_X_NULL_REF_POINTER);
6634 return FALSE;
6637 /* an empty Portname is Invalid, but can popup a Dialog */
6638 if (!pPortName[0]) {
6639 SetLastError(ERROR_NOT_SUPPORTED);
6640 return FALSE;
6643 pm = monitor_load_by_port(pPortName);
6644 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6645 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6646 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6647 TRACE("got %d with %u\n", res, GetLastError());
6649 else
6651 pui = monitor_loadui(pm);
6652 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6653 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6654 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6655 TRACE("got %d with %u\n", res, GetLastError());
6657 else
6659 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6660 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6662 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6663 SetLastError(ERROR_NOT_SUPPORTED);
6664 res = FALSE;
6666 monitor_unload(pui);
6668 monitor_unload(pm);
6670 TRACE("returning %d with %u\n", res, GetLastError());
6671 return res;
6674 /******************************************************************************
6675 * ConnectToPrinterDlg (WINSPOOL.@)
6677 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6679 FIXME("%p %x\n", hWnd, Flags);
6680 return NULL;
6683 /******************************************************************************
6684 * DeletePrinterConnectionA (WINSPOOL.@)
6686 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6688 FIXME("%s\n", debugstr_a(pName));
6689 return TRUE;
6692 /******************************************************************************
6693 * DeletePrinterConnectionW (WINSPOOL.@)
6695 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6697 FIXME("%s\n", debugstr_w(pName));
6698 return TRUE;
6701 /******************************************************************************
6702 * DeletePrinterDriverExW (WINSPOOL.@)
6704 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6705 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6707 HKEY hkey_drivers;
6708 BOOL ret = FALSE;
6710 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6711 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6713 if(pName && pName[0])
6715 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6716 SetLastError(ERROR_INVALID_PARAMETER);
6717 return FALSE;
6720 if(dwDeleteFlag)
6722 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6723 SetLastError(ERROR_INVALID_PARAMETER);
6724 return FALSE;
6727 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6729 if(!hkey_drivers)
6731 ERR("Can't open drivers key\n");
6732 return FALSE;
6735 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6736 ret = TRUE;
6738 RegCloseKey(hkey_drivers);
6740 return ret;
6743 /******************************************************************************
6744 * DeletePrinterDriverExA (WINSPOOL.@)
6746 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6747 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6749 UNICODE_STRING NameW, EnvW, DriverW;
6750 BOOL ret;
6752 asciitounicode(&NameW, pName);
6753 asciitounicode(&EnvW, pEnvironment);
6754 asciitounicode(&DriverW, pDriverName);
6756 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6758 RtlFreeUnicodeString(&DriverW);
6759 RtlFreeUnicodeString(&EnvW);
6760 RtlFreeUnicodeString(&NameW);
6762 return ret;
6765 /******************************************************************************
6766 * DeletePrinterDataExW (WINSPOOL.@)
6768 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6769 LPCWSTR pValueName)
6771 FIXME("%p %s %s\n", hPrinter,
6772 debugstr_w(pKeyName), debugstr_w(pValueName));
6773 return ERROR_INVALID_PARAMETER;
6776 /******************************************************************************
6777 * DeletePrinterDataExA (WINSPOOL.@)
6779 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6780 LPCSTR pValueName)
6782 FIXME("%p %s %s\n", hPrinter,
6783 debugstr_a(pKeyName), debugstr_a(pValueName));
6784 return ERROR_INVALID_PARAMETER;
6787 /******************************************************************************
6788 * DeletePrintProcessorA (WINSPOOL.@)
6790 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6792 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6793 debugstr_a(pPrintProcessorName));
6794 return TRUE;
6797 /******************************************************************************
6798 * DeletePrintProcessorW (WINSPOOL.@)
6800 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6802 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6803 debugstr_w(pPrintProcessorName));
6804 return TRUE;
6807 /******************************************************************************
6808 * DeletePrintProvidorA (WINSPOOL.@)
6810 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6812 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6813 debugstr_a(pPrintProviderName));
6814 return TRUE;
6817 /******************************************************************************
6818 * DeletePrintProvidorW (WINSPOOL.@)
6820 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6822 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6823 debugstr_w(pPrintProviderName));
6824 return TRUE;
6827 /******************************************************************************
6828 * EnumFormsA (WINSPOOL.@)
6830 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6831 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6833 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6834 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6835 return FALSE;
6838 /******************************************************************************
6839 * EnumFormsW (WINSPOOL.@)
6841 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6842 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6844 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6845 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6846 return FALSE;
6849 /*****************************************************************************
6850 * EnumMonitorsA [WINSPOOL.@]
6852 * See EnumMonitorsW.
6855 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6856 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6858 BOOL res;
6859 LPBYTE bufferW = NULL;
6860 LPWSTR nameW = NULL;
6861 DWORD needed = 0;
6862 DWORD numentries = 0;
6863 INT len;
6865 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6866 cbBuf, pcbNeeded, pcReturned);
6868 /* convert servername to unicode */
6869 if (pName) {
6870 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6871 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6872 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6874 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6875 needed = cbBuf * sizeof(WCHAR);
6876 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6877 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6879 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6880 if (pcbNeeded) needed = *pcbNeeded;
6881 /* HeapReAlloc return NULL, when bufferW was NULL */
6882 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6883 HeapAlloc(GetProcessHeap(), 0, needed);
6885 /* Try again with the large Buffer */
6886 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6888 numentries = pcReturned ? *pcReturned : 0;
6889 needed = 0;
6891 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6892 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6894 if (res) {
6895 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6896 DWORD entrysize = 0;
6897 DWORD index;
6898 LPSTR ptr;
6899 LPMONITOR_INFO_2W mi2w;
6900 LPMONITOR_INFO_2A mi2a;
6902 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6903 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6905 /* First pass: calculate the size for all Entries */
6906 mi2w = (LPMONITOR_INFO_2W) bufferW;
6907 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6908 index = 0;
6909 while (index < numentries) {
6910 index++;
6911 needed += entrysize; /* MONITOR_INFO_?A */
6912 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6914 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6915 NULL, 0, NULL, NULL);
6916 if (Level > 1) {
6917 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6918 NULL, 0, NULL, NULL);
6919 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6920 NULL, 0, NULL, NULL);
6922 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6923 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6924 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6927 /* check for errors and quit on failure */
6928 if (cbBuf < needed) {
6929 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6930 res = FALSE;
6931 goto emA_cleanup;
6933 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6934 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6935 cbBuf -= len ; /* free Bytes in the user-Buffer */
6936 mi2w = (LPMONITOR_INFO_2W) bufferW;
6937 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6938 index = 0;
6939 /* Second Pass: Fill the User Buffer (if we have one) */
6940 while ((index < numentries) && pMonitors) {
6941 index++;
6942 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6943 mi2a->pName = ptr;
6944 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6945 ptr, cbBuf , NULL, NULL);
6946 ptr += len;
6947 cbBuf -= len;
6948 if (Level > 1) {
6949 mi2a->pEnvironment = ptr;
6950 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6951 ptr, cbBuf, NULL, NULL);
6952 ptr += len;
6953 cbBuf -= len;
6955 mi2a->pDLLName = ptr;
6956 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6957 ptr, cbBuf, NULL, NULL);
6958 ptr += len;
6959 cbBuf -= len;
6961 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6962 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6963 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6966 emA_cleanup:
6967 if (pcbNeeded) *pcbNeeded = needed;
6968 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6970 HeapFree(GetProcessHeap(), 0, nameW);
6971 HeapFree(GetProcessHeap(), 0, bufferW);
6973 TRACE("returning %d with %d (%d byte for %d entries)\n",
6974 (res), GetLastError(), needed, numentries);
6976 return (res);
6980 /*****************************************************************************
6981 * EnumMonitorsW [WINSPOOL.@]
6983 * Enumerate available Port-Monitors
6985 * PARAMS
6986 * pName [I] Servername or NULL (local Computer)
6987 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6988 * pMonitors [O] PTR to Buffer that receives the Result
6989 * cbBuf [I] Size of Buffer at pMonitors
6990 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6991 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6993 * RETURNS
6994 * Success: TRUE
6995 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6998 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6999 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7002 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7003 cbBuf, pcbNeeded, pcReturned);
7005 if ((backend == NULL) && !load_backend()) return FALSE;
7007 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7008 SetLastError(RPC_X_NULL_REF_POINTER);
7009 return FALSE;
7012 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7015 /******************************************************************************
7016 * SpoolerInit (WINSPOOL.@)
7018 * Initialize the Spooler
7020 * RETURNS
7021 * Success: TRUE
7022 * Failure: FALSE
7024 * NOTES
7025 * The function fails on windows, when the spooler service is not running
7028 BOOL WINAPI SpoolerInit(void)
7031 if ((backend == NULL) && !load_backend()) return FALSE;
7032 return TRUE;
7035 /******************************************************************************
7036 * XcvDataW (WINSPOOL.@)
7038 * Execute commands in the Printmonitor DLL
7040 * PARAMS
7041 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7042 * pszDataName [i] Name of the command to execute
7043 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7044 * cbInputData [i] Size in Bytes of Buffer at pInputData
7045 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7046 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7047 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7048 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7050 * RETURNS
7051 * Success: TRUE
7052 * Failure: FALSE
7054 * NOTES
7055 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7056 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7058 * Minimal List of commands, that a Printmonitor DLL should support:
7060 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7061 *| "AddPort" : Add a Port
7062 *| "DeletePort": Delete a Port
7064 * Many Printmonitors support additional commands. Examples for localspl.dll:
7065 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7066 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7069 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7070 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7071 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7073 opened_printer_t *printer;
7075 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7076 pInputData, cbInputData, pOutputData,
7077 cbOutputData, pcbOutputNeeded, pdwStatus);
7079 printer = get_opened_printer(hXcv);
7080 if (!printer || (!printer->hXcv)) {
7081 SetLastError(ERROR_INVALID_HANDLE);
7082 return FALSE;
7085 if (!pcbOutputNeeded) {
7086 SetLastError(ERROR_INVALID_PARAMETER);
7087 return FALSE;
7090 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7091 SetLastError(RPC_X_NULL_REF_POINTER);
7092 return FALSE;
7095 *pcbOutputNeeded = 0;
7097 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7098 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7100 return TRUE;
7103 /*****************************************************************************
7104 * EnumPrinterDataA [WINSPOOL.@]
7107 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7108 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7109 DWORD cbData, LPDWORD pcbData )
7111 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7112 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7113 return ERROR_NO_MORE_ITEMS;
7116 /*****************************************************************************
7117 * EnumPrinterDataW [WINSPOOL.@]
7120 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7121 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7122 DWORD cbData, LPDWORD pcbData )
7124 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7125 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7126 return ERROR_NO_MORE_ITEMS;
7129 /*****************************************************************************
7130 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7133 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7134 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7135 LPDWORD pcbNeeded, LPDWORD pcReturned)
7137 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7138 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7139 pcbNeeded, pcReturned);
7140 return FALSE;
7143 /*****************************************************************************
7144 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7147 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7148 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7149 LPDWORD pcbNeeded, LPDWORD pcReturned)
7151 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7152 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7153 pcbNeeded, pcReturned);
7154 return FALSE;
7157 /*****************************************************************************
7158 * EnumPrintProcessorsA [WINSPOOL.@]
7161 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7162 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7164 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7165 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7166 return FALSE;
7169 /*****************************************************************************
7170 * EnumPrintProcessorsW [WINSPOOL.@]
7173 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7174 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7176 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7177 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7178 cbBuf, pcbNeeded, pcbReturned);
7179 return FALSE;
7182 /*****************************************************************************
7183 * ExtDeviceMode [WINSPOOL.@]
7186 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7187 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7188 DWORD fMode)
7190 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7191 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7192 debugstr_a(pProfile), fMode);
7193 return -1;
7196 /*****************************************************************************
7197 * FindClosePrinterChangeNotification [WINSPOOL.@]
7200 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7202 FIXME("Stub: %p\n", hChange);
7203 return TRUE;
7206 /*****************************************************************************
7207 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7210 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7211 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7213 FIXME("Stub: %p %x %x %p\n",
7214 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7215 return INVALID_HANDLE_VALUE;
7218 /*****************************************************************************
7219 * FindNextPrinterChangeNotification [WINSPOOL.@]
7222 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7223 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7225 FIXME("Stub: %p %p %p %p\n",
7226 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7227 return FALSE;
7230 /*****************************************************************************
7231 * FreePrinterNotifyInfo [WINSPOOL.@]
7234 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7236 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7237 return TRUE;
7240 /*****************************************************************************
7241 * string_to_buf
7243 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7244 * ansi depending on the unicode parameter.
7246 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7248 if(!str)
7250 *size = 0;
7251 return TRUE;
7254 if(unicode)
7256 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7257 if(*size <= cb)
7259 memcpy(ptr, str, *size);
7260 return TRUE;
7262 return FALSE;
7264 else
7266 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7267 if(*size <= cb)
7269 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7270 return TRUE;
7272 return FALSE;
7276 /*****************************************************************************
7277 * get_job_info_1
7279 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7280 LPDWORD pcbNeeded, BOOL unicode)
7282 DWORD size, left = cbBuf;
7283 BOOL space = (cbBuf > 0);
7284 LPBYTE ptr = buf;
7286 *pcbNeeded = 0;
7288 if(space)
7290 ji1->JobId = job->job_id;
7293 string_to_buf(job->document_title, ptr, left, &size, unicode);
7294 if(space && size <= left)
7296 ji1->pDocument = (LPWSTR)ptr;
7297 ptr += size;
7298 left -= size;
7300 else
7301 space = FALSE;
7302 *pcbNeeded += size;
7304 return space;
7307 /*****************************************************************************
7308 * get_job_info_2
7310 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7311 LPDWORD pcbNeeded, BOOL unicode)
7313 DWORD size, left = cbBuf;
7314 BOOL space = (cbBuf > 0);
7315 LPBYTE ptr = buf;
7317 *pcbNeeded = 0;
7319 if(space)
7321 ji2->JobId = job->job_id;
7324 string_to_buf(job->document_title, ptr, left, &size, unicode);
7325 if(space && size <= left)
7327 ji2->pDocument = (LPWSTR)ptr;
7328 ptr += size;
7329 left -= size;
7331 else
7332 space = FALSE;
7333 *pcbNeeded += size;
7335 return space;
7338 /*****************************************************************************
7339 * get_job_info
7341 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7342 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7344 BOOL ret = FALSE;
7345 DWORD needed = 0, size;
7346 job_t *job;
7347 LPBYTE ptr = pJob;
7349 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7351 EnterCriticalSection(&printer_handles_cs);
7352 job = get_job(hPrinter, JobId);
7353 if(!job)
7354 goto end;
7356 switch(Level)
7358 case 1:
7359 size = sizeof(JOB_INFO_1W);
7360 if(cbBuf >= size)
7362 cbBuf -= size;
7363 ptr += size;
7364 memset(pJob, 0, size);
7366 else
7367 cbBuf = 0;
7368 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7369 needed += size;
7370 break;
7372 case 2:
7373 size = sizeof(JOB_INFO_2W);
7374 if(cbBuf >= size)
7376 cbBuf -= size;
7377 ptr += size;
7378 memset(pJob, 0, size);
7380 else
7381 cbBuf = 0;
7382 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7383 needed += size;
7384 break;
7386 case 3:
7387 size = sizeof(JOB_INFO_3);
7388 if(cbBuf >= size)
7390 cbBuf -= size;
7391 memset(pJob, 0, size);
7392 ret = TRUE;
7394 else
7395 cbBuf = 0;
7396 needed = size;
7397 break;
7399 default:
7400 SetLastError(ERROR_INVALID_LEVEL);
7401 goto end;
7403 if(pcbNeeded)
7404 *pcbNeeded = needed;
7405 end:
7406 LeaveCriticalSection(&printer_handles_cs);
7407 return ret;
7410 /*****************************************************************************
7411 * GetJobA [WINSPOOL.@]
7414 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7415 DWORD cbBuf, LPDWORD pcbNeeded)
7417 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7420 /*****************************************************************************
7421 * GetJobW [WINSPOOL.@]
7424 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7425 DWORD cbBuf, LPDWORD pcbNeeded)
7427 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7430 /*****************************************************************************
7431 * schedule_lpr
7433 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7435 char *unixname, *queue, *cmd;
7436 char fmt[] = "lpr -P%s %s";
7437 DWORD len;
7438 int r;
7440 if(!(unixname = wine_get_unix_file_name(filename)))
7441 return FALSE;
7443 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7444 queue = HeapAlloc(GetProcessHeap(), 0, len);
7445 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7447 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7448 sprintf(cmd, fmt, queue, unixname);
7450 TRACE("printing with: %s\n", cmd);
7451 r = system(cmd);
7453 HeapFree(GetProcessHeap(), 0, cmd);
7454 HeapFree(GetProcessHeap(), 0, queue);
7455 HeapFree(GetProcessHeap(), 0, unixname);
7456 return (r == 0);
7459 /*****************************************************************************
7460 * schedule_cups
7462 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7464 #ifdef SONAME_LIBCUPS
7465 if(pcupsPrintFile)
7467 char *unixname, *queue, *unix_doc_title;
7468 DWORD len;
7469 BOOL ret;
7471 if(!(unixname = wine_get_unix_file_name(filename)))
7472 return FALSE;
7474 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7475 queue = HeapAlloc(GetProcessHeap(), 0, len);
7476 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7478 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7479 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7480 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7482 TRACE("printing via cups\n");
7483 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7484 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7485 HeapFree(GetProcessHeap(), 0, queue);
7486 HeapFree(GetProcessHeap(), 0, unixname);
7487 return ret;
7489 else
7490 #endif
7492 return schedule_lpr(printer_name, filename);
7496 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7498 LPWSTR filename;
7500 switch(msg)
7502 case WM_INITDIALOG:
7503 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7504 return TRUE;
7506 case WM_COMMAND:
7507 if(HIWORD(wparam) == BN_CLICKED)
7509 if(LOWORD(wparam) == IDOK)
7511 HANDLE hf;
7512 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7513 LPWSTR *output;
7515 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7516 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7518 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7520 WCHAR caption[200], message[200];
7521 int mb_ret;
7523 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7524 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7525 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7526 if(mb_ret == IDCANCEL)
7528 HeapFree(GetProcessHeap(), 0, filename);
7529 return TRUE;
7532 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7533 if(hf == INVALID_HANDLE_VALUE)
7535 WCHAR caption[200], message[200];
7537 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7538 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7539 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7540 HeapFree(GetProcessHeap(), 0, filename);
7541 return TRUE;
7543 CloseHandle(hf);
7544 DeleteFileW(filename);
7545 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7546 *output = filename;
7547 EndDialog(hwnd, IDOK);
7548 return TRUE;
7550 if(LOWORD(wparam) == IDCANCEL)
7552 EndDialog(hwnd, IDCANCEL);
7553 return TRUE;
7556 return FALSE;
7558 return FALSE;
7561 /*****************************************************************************
7562 * get_filename
7564 static BOOL get_filename(LPWSTR *filename)
7566 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7567 file_dlg_proc, (LPARAM)filename) == IDOK;
7570 /*****************************************************************************
7571 * schedule_file
7573 static BOOL schedule_file(LPCWSTR filename)
7575 LPWSTR output = NULL;
7577 if(get_filename(&output))
7579 BOOL r;
7580 TRACE("copy to %s\n", debugstr_w(output));
7581 r = CopyFileW(filename, output, FALSE);
7582 HeapFree(GetProcessHeap(), 0, output);
7583 return r;
7585 return FALSE;
7588 /*****************************************************************************
7589 * schedule_pipe
7591 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7593 #ifdef HAVE_FORK
7594 char *unixname, *cmdA;
7595 DWORD len;
7596 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7597 BOOL ret = FALSE;
7598 char buf[1024];
7600 if(!(unixname = wine_get_unix_file_name(filename)))
7601 return FALSE;
7603 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7604 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7605 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7607 TRACE("printing with: %s\n", cmdA);
7609 if((file_fd = open(unixname, O_RDONLY)) == -1)
7610 goto end;
7612 if (pipe(fds))
7614 ERR("pipe() failed!\n");
7615 goto end;
7618 if (fork() == 0)
7620 close(0);
7621 dup2(fds[0], 0);
7622 close(fds[1]);
7624 /* reset signals that we previously set to SIG_IGN */
7625 signal(SIGPIPE, SIG_DFL);
7626 signal(SIGCHLD, SIG_DFL);
7628 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7629 _exit(1);
7632 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7633 write(fds[1], buf, no_read);
7635 ret = TRUE;
7637 end:
7638 if(file_fd != -1) close(file_fd);
7639 if(fds[0] != -1) close(fds[0]);
7640 if(fds[1] != -1) close(fds[1]);
7642 HeapFree(GetProcessHeap(), 0, cmdA);
7643 HeapFree(GetProcessHeap(), 0, unixname);
7644 return ret;
7645 #else
7646 return FALSE;
7647 #endif
7650 /*****************************************************************************
7651 * schedule_unixfile
7653 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7655 int in_fd, out_fd, no_read;
7656 char buf[1024];
7657 BOOL ret = FALSE;
7658 char *unixname, *outputA;
7659 DWORD len;
7661 if(!(unixname = wine_get_unix_file_name(filename)))
7662 return FALSE;
7664 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7665 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7666 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7668 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7669 in_fd = open(unixname, O_RDONLY);
7670 if(out_fd == -1 || in_fd == -1)
7671 goto end;
7673 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7674 write(out_fd, buf, no_read);
7676 ret = TRUE;
7677 end:
7678 if(in_fd != -1) close(in_fd);
7679 if(out_fd != -1) close(out_fd);
7680 HeapFree(GetProcessHeap(), 0, outputA);
7681 HeapFree(GetProcessHeap(), 0, unixname);
7682 return ret;
7685 /*****************************************************************************
7686 * ScheduleJob [WINSPOOL.@]
7689 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7691 opened_printer_t *printer;
7692 BOOL ret = FALSE;
7693 struct list *cursor, *cursor2;
7695 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7696 EnterCriticalSection(&printer_handles_cs);
7697 printer = get_opened_printer(hPrinter);
7698 if(!printer)
7699 goto end;
7701 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7703 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7704 HANDLE hf;
7706 if(job->job_id != dwJobID) continue;
7708 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7709 if(hf != INVALID_HANDLE_VALUE)
7711 PRINTER_INFO_5W *pi5;
7712 DWORD needed;
7713 HKEY hkey;
7714 WCHAR output[1024];
7715 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7716 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7718 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7719 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7720 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7721 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7722 debugstr_w(pi5->pPortName));
7724 output[0] = 0;
7726 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7727 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7729 DWORD type, count = sizeof(output);
7730 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7731 RegCloseKey(hkey);
7733 if(output[0] == '|')
7735 ret = schedule_pipe(output + 1, job->filename);
7737 else if(output[0])
7739 ret = schedule_unixfile(output, job->filename);
7741 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7743 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7745 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7747 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7749 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7751 ret = schedule_file(job->filename);
7753 else
7755 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7757 HeapFree(GetProcessHeap(), 0, pi5);
7758 CloseHandle(hf);
7759 DeleteFileW(job->filename);
7761 list_remove(cursor);
7762 HeapFree(GetProcessHeap(), 0, job->document_title);
7763 HeapFree(GetProcessHeap(), 0, job->filename);
7764 HeapFree(GetProcessHeap(), 0, job);
7765 break;
7767 end:
7768 LeaveCriticalSection(&printer_handles_cs);
7769 return ret;
7772 /*****************************************************************************
7773 * StartDocDlgA [WINSPOOL.@]
7775 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7777 UNICODE_STRING usBuffer;
7778 DOCINFOW docW;
7779 LPWSTR retW;
7780 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7781 LPSTR ret = NULL;
7783 docW.cbSize = sizeof(docW);
7784 if (doc->lpszDocName)
7786 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7787 if (!(docW.lpszDocName = docnameW)) return NULL;
7789 if (doc->lpszOutput)
7791 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7792 if (!(docW.lpszOutput = outputW)) return NULL;
7794 if (doc->lpszDatatype)
7796 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7797 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7799 docW.fwType = doc->fwType;
7801 retW = StartDocDlgW(hPrinter, &docW);
7803 if(retW)
7805 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7806 ret = HeapAlloc(GetProcessHeap(), 0, len);
7807 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7808 HeapFree(GetProcessHeap(), 0, retW);
7811 HeapFree(GetProcessHeap(), 0, datatypeW);
7812 HeapFree(GetProcessHeap(), 0, outputW);
7813 HeapFree(GetProcessHeap(), 0, docnameW);
7815 return ret;
7818 /*****************************************************************************
7819 * StartDocDlgW [WINSPOOL.@]
7821 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7822 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7823 * port is "FILE:". Also returns the full path if passed a relative path.
7825 * The caller should free the returned string from the process heap.
7827 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7829 LPWSTR ret = NULL;
7830 DWORD len, attr;
7832 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7834 PRINTER_INFO_5W *pi5;
7835 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7836 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7837 return NULL;
7838 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7839 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7840 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7842 HeapFree(GetProcessHeap(), 0, pi5);
7843 return NULL;
7845 HeapFree(GetProcessHeap(), 0, pi5);
7848 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7850 LPWSTR name;
7852 if (get_filename(&name))
7854 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7856 HeapFree(GetProcessHeap(), 0, name);
7857 return NULL;
7859 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7860 GetFullPathNameW(name, len, ret, NULL);
7861 HeapFree(GetProcessHeap(), 0, name);
7863 return ret;
7866 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7867 return NULL;
7869 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7870 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7872 attr = GetFileAttributesW(ret);
7873 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7875 HeapFree(GetProcessHeap(), 0, ret);
7876 ret = NULL;
7878 return ret;