winspool: Use the backend for AddMonitor.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob4737e986393b150c5f7bd4ecd7ca8a793783c8f4
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2008 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
201 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
202 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
203 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
204 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
206 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
207 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
209 static const WCHAR backslashW[] = {'\\',0};
210 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
211 'i','o','n',' ','F','i','l','e',0};
212 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
213 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
214 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
215 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
216 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
218 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
219 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
220 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
221 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
222 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
223 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
224 static const WCHAR NameW[] = {'N','a','m','e',0};
225 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
226 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
227 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
228 static const WCHAR PortW[] = {'P','o','r','t',0};
229 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
230 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
234 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
235 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW[] = {0};
244 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
257 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
258 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
259 0, sizeof(DRIVER_INFO_8W)};
262 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
263 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
264 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
265 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
266 sizeof(PRINTER_INFO_9W)};
268 /******************************************************************
269 * validate the user-supplied printing-environment [internal]
271 * PARAMS
272 * env [I] PTR to Environment-String or NULL
274 * RETURNS
275 * Failure: NULL
276 * Success: PTR to printenv_t
278 * NOTES
279 * An empty string is handled the same way as NULL.
280 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
284 static const printenv_t * validate_envW(LPCWSTR env)
286 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
287 3, Version3_RegPathW, Version3_SubdirW};
288 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
289 0, Version0_RegPathW, Version0_SubdirW};
291 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
293 const printenv_t *result = NULL;
294 unsigned int i;
296 TRACE("testing %s\n", debugstr_w(env));
297 if (env && env[0])
299 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
301 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
303 result = all_printenv[i];
304 break;
308 if (result == NULL) {
309 FIXME("unsupported Environment: %s\n", debugstr_w(env));
310 SetLastError(ERROR_INVALID_ENVIRONMENT);
312 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
314 else
316 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
318 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
320 return result;
324 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
325 if passed a NULL string. This returns NULLs to the result.
327 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
329 if ( (src) )
331 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
332 return usBufferPtr->Buffer;
334 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
335 return NULL;
338 static LPWSTR strdupW(LPCWSTR p)
340 LPWSTR ret;
341 DWORD len;
343 if(!p) return NULL;
344 len = (strlenW(p) + 1) * sizeof(WCHAR);
345 ret = HeapAlloc(GetProcessHeap(), 0, len);
346 memcpy(ret, p, len);
347 return ret;
350 static LPSTR strdupWtoA( LPCWSTR str )
352 LPSTR ret;
353 INT len;
355 if (!str) return NULL;
356 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
357 ret = HeapAlloc( GetProcessHeap(), 0, len );
358 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
359 return ret;
362 /******************************************************************
363 * Return the number of bytes for an multi_sz string.
364 * The result includes all \0s
365 * (specifically the extra \0, that is needed as multi_sz terminator).
367 #if 0
368 static int multi_sz_lenW(const WCHAR *str)
370 const WCHAR *ptr = str;
371 if(!str) return 0;
374 ptr += lstrlenW(ptr) + 1;
375 } while(*ptr);
377 return (ptr - str + 1) * sizeof(WCHAR);
379 #endif
380 /* ################################ */
382 static int multi_sz_lenA(const char *str)
384 const char *ptr = str;
385 if(!str) return 0;
388 ptr += lstrlenA(ptr) + 1;
389 } while(*ptr);
391 return ptr - str + 1;
394 static void
395 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
396 char qbuf[200];
398 /* If forcing, or no profile string entry for device yet, set the entry
400 * The always change entry if not WINEPS yet is discussable.
402 if (force ||
403 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
404 !strcmp(qbuf,"*") ||
405 !strstr(qbuf,"WINEPS.DRV")
407 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
408 HKEY hkey;
410 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
411 WriteProfileStringA("windows","device",buf);
412 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
413 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
414 RegCloseKey(hkey);
416 HeapFree(GetProcessHeap(),0,buf);
420 static BOOL add_printer_driver(const char *name)
422 DRIVER_INFO_3A di3a;
424 static char driver_9x[] = "wineps16.drv",
425 driver_nt[] = "wineps.drv",
426 env_9x[] = "Windows 4.0",
427 env_nt[] = "Windows NT x86",
428 data_file[] = "generic.ppd",
429 default_data_type[] = "RAW";
431 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
432 di3a.cVersion = 3;
433 di3a.pName = (char *)name;
434 di3a.pEnvironment = env_nt;
435 di3a.pDriverPath = driver_nt;
436 di3a.pDataFile = data_file;
437 di3a.pConfigFile = driver_nt;
438 di3a.pDefaultDataType = default_data_type;
440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
443 di3a.cVersion = 0;
444 di3a.pEnvironment = env_9x;
445 di3a.pDriverPath = driver_9x;
446 di3a.pConfigFile = driver_9x;
447 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
448 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
450 return TRUE;
453 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
454 debugstr_a(di3a.pEnvironment), GetLastError());
455 return FALSE;
458 #ifdef SONAME_LIBCUPS
459 static typeof(cupsGetDests) *pcupsGetDests;
460 static typeof(cupsGetPPD) *pcupsGetPPD;
461 static typeof(cupsPrintFile) *pcupsPrintFile;
462 static void *cupshandle;
464 static BOOL CUPS_LoadPrinters(void)
466 int i, nrofdests;
467 BOOL hadprinter = FALSE, haddefault = FALSE;
468 cups_dest_t *dests;
469 PRINTER_INFO_2A pinfo2a;
470 char *port,*devline;
471 HKEY hkeyPrinter, hkeyPrinters, hkey;
472 char loaderror[256];
474 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
475 if (!cupshandle) {
476 TRACE("%s\n", loaderror);
477 return FALSE;
479 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
481 #define DYNCUPS(x) \
482 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
483 if (!p##x) return FALSE;
485 DYNCUPS(cupsGetPPD);
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
488 #undef DYNCUPS
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491 ERROR_SUCCESS) {
492 ERR("Can't create Printers key\n");
493 return FALSE;
496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498 for (i=0;i<nrofdests;i++) {
499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501 sprintf(port,"LPR:%s", dests[i].name);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504 sprintf(devline, "WINEPS.DRV,%s", port);
505 WriteProfileStringA("devices", dests[i].name, devline);
506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
508 RegCloseKey(hkey);
511 lstrcatA(devline, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 RegCloseKey(hkey);
518 HeapFree(GetProcessHeap(), 0, devline);
520 TRACE("Printer %d: %s\n", i, dests[i].name);
521 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
523 and continue */
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526 RegCloseKey(hkeyPrinter);
527 } else {
528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
530 comment[] = "WINEPS Printer using CUPS",
531 location[] = "<physical location of printer>",
532 params[] = "<parameters?>",
533 share_name[] = "<share name?>",
534 sep_file[] = "<sep file?>";
536 add_printer_driver(dests[i].name);
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = dests[i].name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = location;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
555 HeapFree(GetProcessHeap(),0,port);
557 hadprinter = TRUE;
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
560 haddefault = TRUE;
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 RegCloseKey(hkeyPrinters);
566 return hadprinter;
568 #endif
570 static BOOL
571 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
572 PRINTER_INFO_2A pinfo2a;
573 char *e,*s,*name,*prettyname,*devname;
574 BOOL ret = FALSE, set_default = FALSE;
575 char *port = NULL, *devline,*env_default;
576 HKEY hkeyPrinter, hkeyPrinters, hkey;
578 while (isspace(*pent)) pent++;
579 s = strchr(pent,':');
580 if(s) *s='\0';
581 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
582 strcpy(name,pent);
583 if(s) {
584 *s=':';
585 pent = s;
586 } else
587 pent = "";
589 TRACE("name=%s entry=%s\n",name, pent);
591 if(ispunct(*name)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
593 goto end;
596 if(strstr(pent,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
598 goto end;
601 /* Determine whether this is a postscript printer. */
603 ret = TRUE;
604 env_default = getenv("PRINTER");
605 prettyname = name;
606 /* Get longest name, usually the one at the right for later display. */
607 while((s=strchr(prettyname,'|'))) {
608 *s = '\0';
609 e = s;
610 while(isspace(*--e)) *e = '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname));
612 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
613 for(prettyname = s+1; isspace(*prettyname); prettyname++)
616 e = prettyname + strlen(prettyname);
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname = prettyname;
624 if (strlen(devname)>=CCHDEVICENAME-1)
625 devname = name;
626 if (strlen(devname)>=CCHDEVICENAME-1) {
627 ret = FALSE;
628 goto end;
631 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
632 sprintf(port,"LPR:%s",name);
634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
636 sprintf(devline, "WINEPS.DRV,%s", port);
637 WriteProfileStringA("devices", devname, devline);
638 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
639 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
640 RegCloseKey(hkey);
643 lstrcatA(devline, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
647 RegCloseKey(hkey);
650 HeapFree(GetProcessHeap(),0,devline);
652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
653 ERROR_SUCCESS) {
654 ERR("Can't create Printers key\n");
655 ret = FALSE;
656 goto end;
658 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
660 and continue */
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
663 RegCloseKey(hkeyPrinter);
664 } else {
665 static CHAR data_type[] = "RAW",
666 print_proc[] = "WinPrint",
667 comment[] = "WINEPS Printer using LPR",
668 params[] = "<parameters?>",
669 share_name[] = "<share name?>",
670 sep_file[] = "<sep file?>";
672 add_printer_driver(devname);
674 memset(&pinfo2a,0,sizeof(pinfo2a));
675 pinfo2a.pPrinterName = devname;
676 pinfo2a.pDatatype = data_type;
677 pinfo2a.pPrintProcessor = print_proc;
678 pinfo2a.pDriverName = devname;
679 pinfo2a.pComment = comment;
680 pinfo2a.pLocation = prettyname;
681 pinfo2a.pPortName = port;
682 pinfo2a.pParameters = params;
683 pinfo2a.pShareName = share_name;
684 pinfo2a.pSepFile = sep_file;
686 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
688 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
691 RegCloseKey(hkeyPrinters);
693 if (isfirst || set_default)
694 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
696 end:
697 HeapFree(GetProcessHeap(), 0, port);
698 HeapFree(GetProcessHeap(), 0, name);
699 return ret;
702 static BOOL
703 PRINTCAP_LoadPrinters(void) {
704 BOOL hadprinter = FALSE;
705 char buf[200];
706 FILE *f;
707 char *pent = NULL;
708 BOOL had_bash = FALSE;
710 f = fopen("/etc/printcap","r");
711 if (!f)
712 return FALSE;
714 while(fgets(buf,sizeof(buf),f)) {
715 char *start, *end;
717 end=strchr(buf,'\n');
718 if (end) *end='\0';
720 start = buf;
721 while(isspace(*start)) start++;
722 if(*start == '#' || *start == '\0')
723 continue;
725 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
726 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
727 HeapFree(GetProcessHeap(),0,pent);
728 pent = NULL;
731 if (end && *--end == '\\') {
732 *end = '\0';
733 had_bash = TRUE;
734 } else
735 had_bash = FALSE;
737 if (pent) {
738 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
739 strcat(pent,start);
740 } else {
741 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
742 strcpy(pent,start);
746 if(pent) {
747 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
748 HeapFree(GetProcessHeap(),0,pent);
750 fclose(f);
751 return hadprinter;
754 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
756 if (value)
757 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
758 (lstrlenW(value) + 1) * sizeof(WCHAR));
759 else
760 return ERROR_FILE_NOT_FOUND;
763 /******************************************************************
764 * monitor_unload [internal]
766 * release a printmonitor and unload it from memory, when needed
769 static void monitor_unload(monitor_t * pm)
771 if (pm == NULL) return;
772 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
774 EnterCriticalSection(&monitor_handles_cs);
776 if (pm->refcount) pm->refcount--;
778 if (pm->refcount == 0) {
779 list_remove(&pm->entry);
780 FreeLibrary(pm->hdll);
781 HeapFree(GetProcessHeap(), 0, pm->name);
782 HeapFree(GetProcessHeap(), 0, pm->dllname);
783 HeapFree(GetProcessHeap(), 0, pm);
785 LeaveCriticalSection(&monitor_handles_cs);
788 /******************************************************************
789 * monitor_unloadall [internal]
791 * release all printmonitors and unload them from memory, when needed
794 static void monitor_unloadall(void)
796 monitor_t * pm;
797 monitor_t * next;
799 EnterCriticalSection(&monitor_handles_cs);
800 /* iterate through the list, with safety against removal */
801 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
803 monitor_unload(pm);
805 LeaveCriticalSection(&monitor_handles_cs);
808 /******************************************************************
809 * monitor_load [internal]
811 * load a printmonitor, get the dllname from the registry, when needed
812 * initialize the monitor and dump found function-pointers
814 * On failure, SetLastError() is called and NULL is returned
817 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
819 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
820 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
821 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
822 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
823 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
825 monitor_t * pm = NULL;
826 monitor_t * cursor;
827 LPWSTR regroot = NULL;
828 LPWSTR driver = dllname;
830 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
831 /* Is the Monitor already loaded? */
832 EnterCriticalSection(&monitor_handles_cs);
834 if (name) {
835 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
837 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
838 pm = cursor;
839 break;
844 if (pm == NULL) {
845 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
846 if (pm == NULL) goto cleanup;
847 list_add_tail(&monitor_handles, &pm->entry);
849 pm->refcount++;
851 if (pm->name == NULL) {
852 /* Load the monitor */
853 LPMONITOREX pmonitorEx;
854 DWORD len;
856 if (name) {
857 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
858 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
861 if (regroot) {
862 lstrcpyW(regroot, MonitorsW);
863 lstrcatW(regroot, name);
864 /* Get the Driver from the Registry */
865 if (driver == NULL) {
866 HKEY hroot;
867 DWORD namesize;
868 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
869 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
870 &namesize) == ERROR_SUCCESS) {
871 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
872 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
874 RegCloseKey(hroot);
879 pm->name = strdupW(name);
880 pm->dllname = strdupW(driver);
882 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
883 monitor_unload(pm);
884 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
885 pm = NULL;
886 goto cleanup;
889 pm->hdll = LoadLibraryW(driver);
890 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
892 if (pm->hdll == NULL) {
893 monitor_unload(pm);
894 SetLastError(ERROR_MOD_NOT_FOUND);
895 pm = NULL;
896 goto cleanup;
899 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
900 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
901 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
902 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
903 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
906 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
907 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
908 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
909 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
910 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
912 if (pInitializePrintMonitorUI != NULL) {
913 pm->monitorUI = pInitializePrintMonitorUI();
914 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
915 if (pm->monitorUI) {
916 TRACE( "0x%08x: dwMonitorSize (%d)\n",
917 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
922 if (pInitializePrintMonitor && regroot) {
923 pmonitorEx = pInitializePrintMonitor(regroot);
924 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
925 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
927 if (pmonitorEx) {
928 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
929 pm->monitor = &(pmonitorEx->Monitor);
933 if (pm->monitor) {
934 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
938 if (!pm->monitor && regroot) {
939 if (pInitializePrintMonitor2 != NULL) {
940 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
942 if (pInitializeMonitorEx != NULL) {
943 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
945 if (pInitializeMonitor != NULL) {
946 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
949 if (!pm->monitor && !pm->monitorUI) {
950 monitor_unload(pm);
951 SetLastError(ERROR_PROC_NOT_FOUND);
952 pm = NULL;
955 cleanup:
956 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
957 pm->refcount++;
958 pm_localport = pm;
960 LeaveCriticalSection(&monitor_handles_cs);
961 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
962 HeapFree(GetProcessHeap(), 0, regroot);
963 TRACE("=> %p\n", pm);
964 return pm;
967 /******************************************************************
968 * monitor_loadall [internal]
970 * Load all registered monitors
973 static DWORD monitor_loadall(void)
975 monitor_t * pm;
976 DWORD registered = 0;
977 DWORD loaded = 0;
978 HKEY hmonitors;
979 WCHAR buffer[MAX_PATH];
980 DWORD id = 0;
982 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
983 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
984 NULL, NULL, NULL, NULL, NULL);
986 TRACE("%d monitors registered\n", registered);
988 EnterCriticalSection(&monitor_handles_cs);
989 while (id < registered) {
990 buffer[0] = '\0';
991 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
992 pm = monitor_load(buffer, NULL);
993 if (pm) loaded++;
994 id++;
996 LeaveCriticalSection(&monitor_handles_cs);
997 RegCloseKey(hmonitors);
999 TRACE("%d monitors loaded\n", loaded);
1000 return loaded;
1003 /******************************************************************
1004 * monitor_loadui [internal]
1006 * load the userinterface-dll for a given portmonitor
1008 * On failure, NULL is returned
1011 static monitor_t * monitor_loadui(monitor_t * pm)
1013 monitor_t * pui = NULL;
1014 LPWSTR buffer[MAX_PATH];
1015 HANDLE hXcv;
1016 DWORD len;
1017 DWORD res;
1019 if (pm == NULL) return NULL;
1020 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1022 /* Try the Portmonitor first; works for many monitors */
1023 if (pm->monitorUI) {
1024 EnterCriticalSection(&monitor_handles_cs);
1025 pm->refcount++;
1026 LeaveCriticalSection(&monitor_handles_cs);
1027 return pm;
1030 /* query the userinterface-dllname from the Portmonitor */
1031 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1032 /* building (",XcvMonitor %s",pm->name) not needed yet */
1033 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1034 TRACE("got %u with %p\n", res, hXcv);
1035 if (res) {
1036 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1037 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1038 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1039 pm->monitor->pfnXcvClosePort(hXcv);
1042 return pui;
1046 /******************************************************************
1047 * monitor_load_by_port [internal]
1049 * load a printmonitor for a given port
1051 * On failure, NULL is returned
1054 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1056 HKEY hroot;
1057 HKEY hport;
1058 LPWSTR buffer;
1059 monitor_t * pm = NULL;
1060 DWORD registered = 0;
1061 DWORD id = 0;
1062 DWORD len;
1064 TRACE("(%s)\n", debugstr_w(portname));
1066 /* Try the Local Monitor first */
1067 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1068 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1069 /* found the portname */
1070 RegCloseKey(hroot);
1071 return monitor_load(LocalPortW, NULL);
1073 RegCloseKey(hroot);
1076 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1077 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1078 if (buffer == NULL) return NULL;
1080 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1081 EnterCriticalSection(&monitor_handles_cs);
1082 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1084 while ((pm == NULL) && (id < registered)) {
1085 buffer[0] = '\0';
1086 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1087 TRACE("testing %s\n", debugstr_w(buffer));
1088 len = lstrlenW(buffer);
1089 lstrcatW(buffer, bs_Ports_bsW);
1090 lstrcatW(buffer, portname);
1091 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1092 RegCloseKey(hport);
1093 buffer[len] = '\0'; /* use only the Monitor-Name */
1094 pm = monitor_load(buffer, NULL);
1096 id++;
1098 LeaveCriticalSection(&monitor_handles_cs);
1099 RegCloseKey(hroot);
1101 HeapFree(GetProcessHeap(), 0, buffer);
1102 return pm;
1105 /******************************************************************
1106 * enumerate the local Ports from all loaded monitors (internal)
1108 * returns the needed size (in bytes) for pPorts
1109 * and *lpreturned is set to number of entries returned in pPorts
1112 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1114 monitor_t * pm;
1115 LPWSTR ptr;
1116 LPPORT_INFO_2W cache;
1117 LPPORT_INFO_2W out;
1118 LPBYTE pi_buffer = NULL;
1119 DWORD pi_allocated = 0;
1120 DWORD pi_needed;
1121 DWORD pi_index;
1122 DWORD pi_returned;
1123 DWORD res;
1124 DWORD outindex = 0;
1125 DWORD needed;
1126 DWORD numentries;
1127 DWORD entrysize;
1130 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1131 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1133 numentries = *lpreturned; /* this is 0, when we scan the registry */
1134 needed = entrysize * numentries;
1135 ptr = (LPWSTR) &pPorts[needed];
1137 numentries = 0;
1138 needed = 0;
1140 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1142 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1143 pi_needed = 0;
1144 pi_returned = 0;
1145 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1146 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1147 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1148 HeapFree(GetProcessHeap(), 0, pi_buffer);
1149 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1150 pi_allocated = (pi_buffer) ? pi_needed : 0;
1151 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1153 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1154 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1156 numentries += pi_returned;
1157 needed += pi_needed;
1159 /* fill the output-buffer (pPorts), if we have one */
1160 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1161 pi_index = 0;
1162 while (pi_returned > pi_index) {
1163 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1164 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1165 out->pPortName = ptr;
1166 lstrcpyW(ptr, cache->pPortName);
1167 ptr += (lstrlenW(ptr)+1);
1168 if (level > 1) {
1169 out->pMonitorName = ptr;
1170 lstrcpyW(ptr, cache->pMonitorName);
1171 ptr += (lstrlenW(ptr)+1);
1173 out->pDescription = ptr;
1174 lstrcpyW(ptr, cache->pDescription);
1175 ptr += (lstrlenW(ptr)+1);
1176 out->fPortType = cache->fPortType;
1177 out->Reserved = cache->Reserved;
1179 pi_index++;
1180 outindex++;
1185 /* the temporary portinfo-buffer is no longer needed */
1186 HeapFree(GetProcessHeap(), 0, pi_buffer);
1188 *lpreturned = numentries;
1189 TRACE("need %d byte for %d entries\n", needed, numentries);
1190 return needed;
1193 /******************************************************************
1194 * get_servername_from_name (internal)
1196 * for an external server, a copy of the serverpart from the full name is returned
1199 static LPWSTR get_servername_from_name(LPCWSTR name)
1201 LPWSTR server;
1202 LPWSTR ptr;
1203 WCHAR buffer[MAX_PATH];
1204 DWORD len;
1206 if (name == NULL) return NULL;
1207 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1209 server = strdupW(&name[2]); /* skip over both backslash */
1210 if (server == NULL) return NULL;
1212 /* strip '\' and the printername */
1213 ptr = strchrW(server, '\\');
1214 if (ptr) ptr[0] = '\0';
1216 TRACE("found %s\n", debugstr_w(server));
1218 len = sizeof(buffer)/sizeof(buffer[0]);
1219 if (GetComputerNameW(buffer, &len)) {
1220 if (lstrcmpW(buffer, server) == 0) {
1221 /* The requested Servername is our computername */
1222 HeapFree(GetProcessHeap(), 0, server);
1223 return NULL;
1226 return server;
1229 /******************************************************************
1230 * get_basename_from_name (internal)
1232 * skip over the serverpart from the full name
1235 static LPCWSTR get_basename_from_name(LPCWSTR name)
1237 if (name == NULL) return NULL;
1238 if ((name[0] == '\\') && (name[1] == '\\')) {
1239 /* skip over the servername and search for the following '\' */
1240 name = strchrW(&name[2], '\\');
1241 if ((name) && (name[1])) {
1242 /* found a separator ('\') followed by a name:
1243 skip over the separator and return the rest */
1244 name++;
1246 else
1248 /* no basename present (we found only a servername) */
1249 return NULL;
1252 return name;
1255 /******************************************************************
1256 * get_opened_printer_entry
1257 * Get the first place empty in the opened printer table
1259 * ToDo:
1260 * - pDefault is ignored
1262 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1264 UINT_PTR handle = nb_printer_handles, i;
1265 jobqueue_t *queue = NULL;
1266 opened_printer_t *printer = NULL;
1267 LPWSTR servername;
1268 LPCWSTR printername;
1269 HKEY hkeyPrinters;
1270 HKEY hkeyPrinter;
1271 DWORD len;
1273 servername = get_servername_from_name(name);
1274 if (servername) {
1275 FIXME("server %s not supported\n", debugstr_w(servername));
1276 HeapFree(GetProcessHeap(), 0, servername);
1277 SetLastError(ERROR_INVALID_PRINTER_NAME);
1278 return NULL;
1281 printername = get_basename_from_name(name);
1282 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1284 /* an empty printername is invalid */
1285 if (printername && (!printername[0])) {
1286 SetLastError(ERROR_INVALID_PARAMETER);
1287 return NULL;
1290 EnterCriticalSection(&printer_handles_cs);
1292 for (i = 0; i < nb_printer_handles; i++)
1294 if (!printer_handles[i])
1296 if(handle == nb_printer_handles)
1297 handle = i;
1299 else
1301 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1302 queue = printer_handles[i]->queue;
1306 if (handle >= nb_printer_handles)
1308 opened_printer_t **new_array;
1309 if (printer_handles)
1310 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1311 (nb_printer_handles + 16) * sizeof(*new_array) );
1312 else
1313 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1314 (nb_printer_handles + 16) * sizeof(*new_array) );
1316 if (!new_array)
1318 handle = 0;
1319 goto end;
1321 printer_handles = new_array;
1322 nb_printer_handles += 16;
1325 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1327 handle = 0;
1328 goto end;
1332 /* clone the base name. This is NULL for the printserver */
1333 printer->printername = strdupW(printername);
1335 /* clone the full name */
1336 printer->name = strdupW(name);
1337 if (name && (!printer->name)) {
1338 handle = 0;
1339 goto end;
1342 if (printername) {
1343 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1344 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1345 /* OpenPrinter(",XcvMonitor " detected */
1346 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1347 printer->pm = monitor_load(&printername[len], NULL);
1348 if (printer->pm == NULL) {
1349 SetLastError(ERROR_UNKNOWN_PORT);
1350 handle = 0;
1351 goto end;
1354 else
1356 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1357 if (strncmpW( printername, XcvPortW, len) == 0) {
1358 /* OpenPrinter(",XcvPort " detected */
1359 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1360 printer->pm = monitor_load_by_port(&printername[len]);
1361 if (printer->pm == NULL) {
1362 SetLastError(ERROR_UNKNOWN_PORT);
1363 handle = 0;
1364 goto end;
1369 if (printer->pm) {
1370 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1371 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1372 pDefault ? pDefault->DesiredAccess : 0,
1373 &printer->hXcv);
1375 if (printer->hXcv == NULL) {
1376 SetLastError(ERROR_INVALID_PARAMETER);
1377 handle = 0;
1378 goto end;
1381 else
1383 /* Does the Printer exist? */
1384 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1385 ERR("Can't create Printers key\n");
1386 handle = 0;
1387 goto end;
1389 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1390 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1391 RegCloseKey(hkeyPrinters);
1392 SetLastError(ERROR_INVALID_PRINTER_NAME);
1393 handle = 0;
1394 goto end;
1396 RegCloseKey(hkeyPrinter);
1397 RegCloseKey(hkeyPrinters);
1400 else
1402 TRACE("using the local printserver\n");
1405 if(queue)
1406 printer->queue = queue;
1407 else
1409 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1410 if (!printer->queue) {
1411 handle = 0;
1412 goto end;
1414 list_init(&printer->queue->jobs);
1415 printer->queue->ref = 0;
1417 InterlockedIncrement(&printer->queue->ref);
1419 printer_handles[handle] = printer;
1420 handle++;
1421 end:
1422 LeaveCriticalSection(&printer_handles_cs);
1423 if (!handle && printer) {
1424 /* Something failed: Free all resources */
1425 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1426 monitor_unload(printer->pm);
1427 HeapFree(GetProcessHeap(), 0, printer->printername);
1428 HeapFree(GetProcessHeap(), 0, printer->name);
1429 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1430 HeapFree(GetProcessHeap(), 0, printer);
1433 return (HANDLE)handle;
1436 /******************************************************************
1437 * get_opened_printer
1438 * Get the pointer to the opened printer referred by the handle
1440 static opened_printer_t *get_opened_printer(HANDLE hprn)
1442 UINT_PTR idx = (UINT_PTR)hprn;
1443 opened_printer_t *ret = NULL;
1445 EnterCriticalSection(&printer_handles_cs);
1447 if ((idx > 0) && (idx <= nb_printer_handles)) {
1448 ret = printer_handles[idx - 1];
1450 LeaveCriticalSection(&printer_handles_cs);
1451 return ret;
1454 /******************************************************************
1455 * get_opened_printer_name
1456 * Get the pointer to the opened printer name referred by the handle
1458 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1460 opened_printer_t *printer = get_opened_printer(hprn);
1461 if(!printer) return NULL;
1462 return printer->name;
1465 /******************************************************************
1466 * WINSPOOL_GetOpenedPrinterRegKey
1469 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1471 LPCWSTR name = get_opened_printer_name(hPrinter);
1472 DWORD ret;
1473 HKEY hkeyPrinters;
1475 if(!name) return ERROR_INVALID_HANDLE;
1477 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1478 ERROR_SUCCESS)
1479 return ret;
1481 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1483 ERR("Can't find opened printer %s in registry\n",
1484 debugstr_w(name));
1485 RegCloseKey(hkeyPrinters);
1486 return ERROR_INVALID_PRINTER_NAME; /* ? */
1488 RegCloseKey(hkeyPrinters);
1489 return ERROR_SUCCESS;
1492 void WINSPOOL_LoadSystemPrinters(void)
1494 HKEY hkey, hkeyPrinters;
1495 HANDLE hprn;
1496 DWORD needed, num, i;
1497 WCHAR PrinterName[256];
1498 BOOL done = FALSE;
1500 /* This ensures that all printer entries have a valid Name value. If causes
1501 problems later if they don't. If one is found to be missed we create one
1502 and set it equal to the name of the key */
1503 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1504 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1505 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1506 for(i = 0; i < num; i++) {
1507 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1508 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1509 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1510 set_reg_szW(hkey, NameW, PrinterName);
1512 RegCloseKey(hkey);
1517 RegCloseKey(hkeyPrinters);
1520 /* We want to avoid calling AddPrinter on printers as much as
1521 possible, because on cups printers this will (eventually) lead
1522 to a call to cupsGetPPD which takes forever, even with non-cups
1523 printers AddPrinter takes a while. So we'll tag all printers that
1524 were automatically added last time around, if they still exist
1525 we'll leave them be otherwise we'll delete them. */
1526 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1527 if(needed) {
1528 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1529 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1530 for(i = 0; i < num; i++) {
1531 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1532 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1533 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1534 DWORD dw = 1;
1535 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1536 RegCloseKey(hkey);
1538 ClosePrinter(hprn);
1543 HeapFree(GetProcessHeap(), 0, pi);
1547 #ifdef SONAME_LIBCUPS
1548 done = CUPS_LoadPrinters();
1549 #endif
1551 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1552 PRINTCAP_LoadPrinters();
1554 /* Now enumerate the list again and delete any printers that are still tagged */
1555 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1556 if(needed) {
1557 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1558 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1559 for(i = 0; i < num; i++) {
1560 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1561 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1562 BOOL delete_driver = FALSE;
1563 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1564 DWORD dw, type, size = sizeof(dw);
1565 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1566 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1567 DeletePrinter(hprn);
1568 delete_driver = TRUE;
1570 RegCloseKey(hkey);
1572 ClosePrinter(hprn);
1573 if(delete_driver)
1574 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1579 HeapFree(GetProcessHeap(), 0, pi);
1582 return;
1586 /******************************************************************
1587 * get_job
1589 * Get the pointer to the specified job.
1590 * Should hold the printer_handles_cs before calling.
1592 static job_t *get_job(HANDLE hprn, DWORD JobId)
1594 opened_printer_t *printer = get_opened_printer(hprn);
1595 job_t *job;
1597 if(!printer) return NULL;
1598 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1600 if(job->job_id == JobId)
1601 return job;
1603 return NULL;
1606 /***********************************************************
1607 * DEVMODEcpyAtoW
1609 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1611 BOOL Formname;
1612 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1613 DWORD size;
1615 Formname = (dmA->dmSize > off_formname);
1616 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1617 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1618 dmW->dmDeviceName, CCHDEVICENAME);
1619 if(!Formname) {
1620 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1621 dmA->dmSize - CCHDEVICENAME);
1622 } else {
1623 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1624 off_formname - CCHDEVICENAME);
1625 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1626 dmW->dmFormName, CCHFORMNAME);
1627 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1628 (off_formname + CCHFORMNAME));
1630 dmW->dmSize = size;
1631 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1632 dmA->dmDriverExtra);
1633 return dmW;
1636 /***********************************************************
1637 * DEVMODEdupWtoA
1638 * Creates an ansi copy of supplied devmode
1640 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1642 LPDEVMODEA dmA;
1643 DWORD size;
1645 if (!dmW) return NULL;
1646 size = dmW->dmSize - CCHDEVICENAME -
1647 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1649 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1650 if (!dmA) return NULL;
1652 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1653 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1655 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1656 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1657 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1659 else
1661 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1662 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1663 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1664 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1666 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1669 dmA->dmSize = size;
1670 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1671 return dmA;
1674 /******************************************************************
1675 * convert_printerinfo_W_to_A [internal]
1678 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1679 DWORD level, DWORD outlen, DWORD numentries)
1681 DWORD id = 0;
1682 LPSTR ptr;
1683 INT len;
1685 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1687 len = pi_sizeof[level] * numentries;
1688 ptr = (LPSTR) out + len;
1689 outlen -= len;
1691 /* copy the numbers of all PRINTER_INFO_* first */
1692 memcpy(out, pPrintersW, len);
1694 while (id < numentries) {
1695 switch (level) {
1696 case 1:
1698 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1699 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1701 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1702 if (piW->pDescription) {
1703 piA->pDescription = ptr;
1704 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1705 ptr, outlen, NULL, NULL);
1706 ptr += len;
1707 outlen -= len;
1709 if (piW->pName) {
1710 piA->pName = ptr;
1711 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1712 ptr, outlen, NULL, NULL);
1713 ptr += len;
1714 outlen -= len;
1716 if (piW->pComment) {
1717 piA->pComment = ptr;
1718 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1719 ptr, outlen, NULL, NULL);
1720 ptr += len;
1721 outlen -= len;
1723 break;
1726 case 2:
1728 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1729 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1730 LPDEVMODEA dmA;
1732 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1733 if (piW->pServerName) {
1734 piA->pServerName = ptr;
1735 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1736 ptr, outlen, NULL, NULL);
1737 ptr += len;
1738 outlen -= len;
1740 if (piW->pPrinterName) {
1741 piA->pPrinterName = ptr;
1742 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1743 ptr, outlen, NULL, NULL);
1744 ptr += len;
1745 outlen -= len;
1747 if (piW->pShareName) {
1748 piA->pShareName = ptr;
1749 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1750 ptr, outlen, NULL, NULL);
1751 ptr += len;
1752 outlen -= len;
1754 if (piW->pPortName) {
1755 piA->pPortName = ptr;
1756 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1757 ptr, outlen, NULL, NULL);
1758 ptr += len;
1759 outlen -= len;
1761 if (piW->pDriverName) {
1762 piA->pDriverName = ptr;
1763 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1764 ptr, outlen, NULL, NULL);
1765 ptr += len;
1766 outlen -= len;
1768 if (piW->pComment) {
1769 piA->pComment = ptr;
1770 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1771 ptr, outlen, NULL, NULL);
1772 ptr += len;
1773 outlen -= len;
1775 if (piW->pLocation) {
1776 piA->pLocation = ptr;
1777 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1778 ptr, outlen, NULL, NULL);
1779 ptr += len;
1780 outlen -= len;
1783 dmA = DEVMODEdupWtoA(piW->pDevMode);
1784 if (dmA) {
1785 /* align DEVMODEA to a DWORD boundary */
1786 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1787 ptr += len;
1788 outlen -= len;
1790 piA->pDevMode = (LPDEVMODEA) ptr;
1791 len = dmA->dmSize + dmA->dmDriverExtra;
1792 memcpy(ptr, dmA, len);
1793 HeapFree(GetProcessHeap(), 0, dmA);
1795 ptr += len;
1796 outlen -= len;
1799 if (piW->pSepFile) {
1800 piA->pSepFile = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1802 ptr, outlen, NULL, NULL);
1803 ptr += len;
1804 outlen -= len;
1806 if (piW->pPrintProcessor) {
1807 piA->pPrintProcessor = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1809 ptr, outlen, NULL, NULL);
1810 ptr += len;
1811 outlen -= len;
1813 if (piW->pDatatype) {
1814 piA->pDatatype = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1816 ptr, outlen, NULL, NULL);
1817 ptr += len;
1818 outlen -= len;
1820 if (piW->pParameters) {
1821 piA->pParameters = ptr;
1822 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1823 ptr, outlen, NULL, NULL);
1824 ptr += len;
1825 outlen -= len;
1827 if (piW->pSecurityDescriptor) {
1828 piA->pSecurityDescriptor = NULL;
1829 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1831 break;
1834 case 4:
1836 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1837 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1839 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1841 if (piW->pPrinterName) {
1842 piA->pPrinterName = ptr;
1843 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1844 ptr, outlen, NULL, NULL);
1845 ptr += len;
1846 outlen -= len;
1848 if (piW->pServerName) {
1849 piA->pServerName = ptr;
1850 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1851 ptr, outlen, NULL, NULL);
1852 ptr += len;
1853 outlen -= len;
1855 break;
1858 case 5:
1860 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1861 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1863 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1865 if (piW->pPrinterName) {
1866 piA->pPrinterName = ptr;
1867 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1868 ptr, outlen, NULL, NULL);
1869 ptr += len;
1870 outlen -= len;
1872 if (piW->pPortName) {
1873 piA->pPortName = ptr;
1874 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1875 ptr, outlen, NULL, NULL);
1876 ptr += len;
1877 outlen -= len;
1879 break;
1882 default:
1883 FIXME("for level %u\n", level);
1885 pPrintersW += pi_sizeof[level];
1886 out += pi_sizeof[level];
1887 id++;
1891 /***********************************************************
1892 * PRINTER_INFO_2AtoW
1893 * Creates a unicode copy of PRINTER_INFO_2A on heap
1895 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1897 LPPRINTER_INFO_2W piW;
1898 UNICODE_STRING usBuffer;
1900 if(!piA) return NULL;
1901 piW = HeapAlloc(heap, 0, sizeof(*piW));
1902 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1904 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1905 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1906 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1907 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1908 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1909 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1910 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1911 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1912 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1913 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1914 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1915 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1916 return piW;
1919 /***********************************************************
1920 * FREE_PRINTER_INFO_2W
1921 * Free PRINTER_INFO_2W and all strings
1923 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1925 if(!piW) return;
1927 HeapFree(heap,0,piW->pServerName);
1928 HeapFree(heap,0,piW->pPrinterName);
1929 HeapFree(heap,0,piW->pShareName);
1930 HeapFree(heap,0,piW->pPortName);
1931 HeapFree(heap,0,piW->pDriverName);
1932 HeapFree(heap,0,piW->pComment);
1933 HeapFree(heap,0,piW->pLocation);
1934 HeapFree(heap,0,piW->pDevMode);
1935 HeapFree(heap,0,piW->pSepFile);
1936 HeapFree(heap,0,piW->pPrintProcessor);
1937 HeapFree(heap,0,piW->pDatatype);
1938 HeapFree(heap,0,piW->pParameters);
1939 HeapFree(heap,0,piW);
1940 return;
1943 /******************************************************************
1944 * DeviceCapabilities [WINSPOOL.@]
1945 * DeviceCapabilitiesA [WINSPOOL.@]
1948 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1949 LPSTR pOutput, LPDEVMODEA lpdm)
1951 INT ret;
1953 if (!GDI_CallDeviceCapabilities16)
1955 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1956 (LPCSTR)104 );
1957 if (!GDI_CallDeviceCapabilities16) return -1;
1959 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1961 /* If DC_PAPERSIZE map POINT16s to POINTs */
1962 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1963 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1964 POINT *pt = (POINT *)pOutput;
1965 INT i;
1966 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1967 for(i = 0; i < ret; i++, pt++)
1969 pt->x = tmp[i].x;
1970 pt->y = tmp[i].y;
1972 HeapFree( GetProcessHeap(), 0, tmp );
1974 return ret;
1978 /*****************************************************************************
1979 * DeviceCapabilitiesW [WINSPOOL.@]
1981 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1984 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1985 WORD fwCapability, LPWSTR pOutput,
1986 const DEVMODEW *pDevMode)
1988 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1989 LPSTR pDeviceA = strdupWtoA(pDevice);
1990 LPSTR pPortA = strdupWtoA(pPort);
1991 INT ret;
1993 if(pOutput && (fwCapability == DC_BINNAMES ||
1994 fwCapability == DC_FILEDEPENDENCIES ||
1995 fwCapability == DC_PAPERNAMES)) {
1996 /* These need A -> W translation */
1997 INT size = 0, i;
1998 LPSTR pOutputA;
1999 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2000 dmA);
2001 if(ret == -1)
2002 return ret;
2003 switch(fwCapability) {
2004 case DC_BINNAMES:
2005 size = 24;
2006 break;
2007 case DC_PAPERNAMES:
2008 case DC_FILEDEPENDENCIES:
2009 size = 64;
2010 break;
2012 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2013 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2014 dmA);
2015 for(i = 0; i < ret; i++)
2016 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2017 pOutput + (i * size), size);
2018 HeapFree(GetProcessHeap(), 0, pOutputA);
2019 } else {
2020 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2021 (LPSTR)pOutput, dmA);
2023 HeapFree(GetProcessHeap(),0,pPortA);
2024 HeapFree(GetProcessHeap(),0,pDeviceA);
2025 HeapFree(GetProcessHeap(),0,dmA);
2026 return ret;
2029 /******************************************************************
2030 * DocumentPropertiesA [WINSPOOL.@]
2032 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2034 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2035 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2036 LPDEVMODEA pDevModeInput,DWORD fMode )
2038 LPSTR lpName = pDeviceName;
2039 static CHAR port[] = "LPT1:";
2040 LONG ret;
2042 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2043 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2046 if(!pDeviceName) {
2047 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2048 if(!lpNameW) {
2049 ERR("no name from hPrinter?\n");
2050 SetLastError(ERROR_INVALID_HANDLE);
2051 return -1;
2053 lpName = strdupWtoA(lpNameW);
2056 if (!GDI_CallExtDeviceMode16)
2058 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2059 (LPCSTR)102 );
2060 if (!GDI_CallExtDeviceMode16) {
2061 ERR("No CallExtDeviceMode16?\n");
2062 return -1;
2065 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2066 pDevModeInput, NULL, fMode);
2068 if(!pDeviceName)
2069 HeapFree(GetProcessHeap(),0,lpName);
2070 return ret;
2074 /*****************************************************************************
2075 * DocumentPropertiesW (WINSPOOL.@)
2077 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2079 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2080 LPWSTR pDeviceName,
2081 LPDEVMODEW pDevModeOutput,
2082 LPDEVMODEW pDevModeInput, DWORD fMode)
2085 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2086 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2087 LPDEVMODEA pDevModeOutputA = NULL;
2088 LONG ret;
2090 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2091 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2092 fMode);
2093 if(pDevModeOutput) {
2094 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2095 if(ret < 0) return ret;
2096 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2098 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2099 pDevModeInputA, fMode);
2100 if(pDevModeOutput) {
2101 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2102 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2104 if(fMode == 0 && ret > 0)
2105 ret += (CCHDEVICENAME + CCHFORMNAME);
2106 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2107 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2108 return ret;
2111 /******************************************************************
2112 * OpenPrinterA [WINSPOOL.@]
2114 * See OpenPrinterW.
2117 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2118 LPPRINTER_DEFAULTSA pDefault)
2120 UNICODE_STRING lpPrinterNameW;
2121 UNICODE_STRING usBuffer;
2122 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2123 PWSTR pwstrPrinterNameW;
2124 BOOL ret;
2126 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2128 if(pDefault) {
2129 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2130 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2131 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2132 pDefaultW = &DefaultW;
2134 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2135 if(pDefault) {
2136 RtlFreeUnicodeString(&usBuffer);
2137 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2139 RtlFreeUnicodeString(&lpPrinterNameW);
2140 return ret;
2143 /******************************************************************
2144 * OpenPrinterW [WINSPOOL.@]
2146 * Open a Printer / Printserver or a Printer-Object
2148 * PARAMS
2149 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2150 * phPrinter [O] The resulting Handle is stored here
2151 * pDefault [I] PTR to Default Printer Settings or NULL
2153 * RETURNS
2154 * Success: TRUE
2155 * Failure: FALSE
2157 * NOTES
2158 * lpPrinterName is one of:
2159 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2160 *| Printer: "PrinterName"
2161 *| Printer-Object: "PrinterName,Job xxx"
2162 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2163 *| XcvPort: "Servername,XcvPort PortName"
2165 * BUGS
2166 *| Printer-Object not supported
2167 *| pDefaults is ignored
2170 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2173 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2174 if (pDefault) {
2175 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2176 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2179 if(!phPrinter) {
2180 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2181 SetLastError(ERROR_INVALID_PARAMETER);
2182 return FALSE;
2185 /* Get the unique handle of the printer or Printserver */
2186 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2187 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2188 return (*phPrinter != 0);
2191 /******************************************************************
2192 * AddMonitorA [WINSPOOL.@]
2194 * See AddMonitorW.
2197 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2199 LPWSTR nameW = NULL;
2200 INT len;
2201 BOOL res;
2202 LPMONITOR_INFO_2A mi2a;
2203 MONITOR_INFO_2W mi2w;
2205 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2206 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2207 debugstr_a(mi2a ? mi2a->pName : NULL),
2208 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2209 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2211 if (Level != 2) {
2212 SetLastError(ERROR_INVALID_LEVEL);
2213 return FALSE;
2216 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2217 if (mi2a == NULL) {
2218 return FALSE;
2221 if (pName) {
2222 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2223 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2224 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2227 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2228 if (mi2a->pName) {
2229 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2230 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2231 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2233 if (mi2a->pEnvironment) {
2234 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2235 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2236 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2238 if (mi2a->pDLLName) {
2239 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2240 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2241 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2244 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2246 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2247 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2248 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2250 HeapFree(GetProcessHeap(), 0, nameW);
2251 return (res);
2254 /******************************************************************************
2255 * AddMonitorW [WINSPOOL.@]
2257 * Install a Printmonitor
2259 * PARAMS
2260 * pName [I] Servername or NULL (local Computer)
2261 * Level [I] Structure-Level (Must be 2)
2262 * pMonitors [I] PTR to MONITOR_INFO_2
2264 * RETURNS
2265 * Success: TRUE
2266 * Failure: FALSE
2268 * NOTES
2269 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2272 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2274 LPMONITOR_INFO_2W mi2w;
2276 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2277 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2278 debugstr_w(mi2w ? mi2w->pName : NULL),
2279 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2280 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2282 if ((backend == NULL) && !load_backend()) return FALSE;
2284 if (Level != 2) {
2285 SetLastError(ERROR_INVALID_LEVEL);
2286 return FALSE;
2289 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2290 if (mi2w == NULL) {
2291 return FALSE;
2294 return backend->fpAddMonitor(pName, Level, pMonitors);
2297 /******************************************************************
2298 * DeletePrinterDriverA [WINSPOOL.@]
2301 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2303 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2306 /******************************************************************
2307 * DeletePrinterDriverW [WINSPOOL.@]
2310 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2312 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2315 /******************************************************************
2316 * DeleteMonitorA [WINSPOOL.@]
2318 * See DeleteMonitorW.
2321 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2323 LPWSTR nameW = NULL;
2324 LPWSTR EnvironmentW = NULL;
2325 LPWSTR MonitorNameW = NULL;
2326 BOOL res;
2327 INT len;
2329 if (pName) {
2330 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2331 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2332 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2335 if (pEnvironment) {
2336 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2337 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2338 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2340 if (pMonitorName) {
2341 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2342 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2343 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2346 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2348 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2349 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2350 HeapFree(GetProcessHeap(), 0, nameW);
2351 return (res);
2354 /******************************************************************
2355 * DeleteMonitorW [WINSPOOL.@]
2357 * Delete a specific Printmonitor from a Printing-Environment
2359 * PARAMS
2360 * pName [I] Servername or NULL (local Computer)
2361 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2362 * pMonitorName [I] Name of the Monitor, that should be deleted
2364 * RETURNS
2365 * Success: TRUE
2366 * Failure: FALSE
2368 * NOTES
2369 * pEnvironment is ignored in Windows for the local Computer.
2372 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2375 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2376 debugstr_w(pMonitorName));
2378 if ((backend == NULL) && !load_backend()) return FALSE;
2380 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2384 /******************************************************************
2385 * DeletePortA [WINSPOOL.@]
2387 * See DeletePortW.
2390 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2392 LPWSTR nameW = NULL;
2393 LPWSTR portW = NULL;
2394 INT len;
2395 DWORD res;
2397 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2399 /* convert servername to unicode */
2400 if (pName) {
2401 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2402 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2403 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2406 /* convert portname to unicode */
2407 if (pPortName) {
2408 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2409 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2410 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2413 res = DeletePortW(nameW, hWnd, portW);
2414 HeapFree(GetProcessHeap(), 0, nameW);
2415 HeapFree(GetProcessHeap(), 0, portW);
2416 return res;
2419 /******************************************************************
2420 * DeletePortW [WINSPOOL.@]
2422 * Delete a specific Port
2424 * PARAMS
2425 * pName [I] Servername or NULL (local Computer)
2426 * hWnd [I] Handle to parent Window for the Dialog-Box
2427 * pPortName [I] Name of the Port, that should be deleted
2429 * RETURNS
2430 * Success: TRUE
2431 * Failure: FALSE
2434 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2436 monitor_t * pm;
2437 monitor_t * pui;
2438 DWORD res;
2440 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2442 if (pName && pName[0]) {
2443 SetLastError(ERROR_INVALID_PARAMETER);
2444 return FALSE;
2447 if (!pPortName) {
2448 SetLastError(RPC_X_NULL_REF_POINTER);
2449 return FALSE;
2452 /* an empty Portname is Invalid */
2453 if (!pPortName[0]) {
2454 SetLastError(ERROR_NOT_SUPPORTED);
2455 return FALSE;
2458 pm = monitor_load_by_port(pPortName);
2459 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2460 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2461 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2462 TRACE("got %d with %u\n", res, GetLastError());
2464 else
2466 pui = monitor_loadui(pm);
2467 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2468 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2469 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2470 TRACE("got %d with %u\n", res, GetLastError());
2472 else
2474 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2475 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2477 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2478 SetLastError(ERROR_NOT_SUPPORTED);
2479 res = FALSE;
2481 monitor_unload(pui);
2483 monitor_unload(pm);
2485 TRACE("returning %d with %u\n", res, GetLastError());
2486 return res;
2489 /******************************************************************************
2490 * SetPrinterW [WINSPOOL.@]
2492 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2494 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2495 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2496 return FALSE;
2499 /******************************************************************************
2500 * WritePrinter [WINSPOOL.@]
2502 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2504 opened_printer_t *printer;
2505 BOOL ret = FALSE;
2507 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2509 EnterCriticalSection(&printer_handles_cs);
2510 printer = get_opened_printer(hPrinter);
2511 if(!printer)
2513 SetLastError(ERROR_INVALID_HANDLE);
2514 goto end;
2517 if(!printer->doc)
2519 SetLastError(ERROR_SPL_NO_STARTDOC);
2520 goto end;
2523 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2524 end:
2525 LeaveCriticalSection(&printer_handles_cs);
2526 return ret;
2529 /*****************************************************************************
2530 * AddFormA [WINSPOOL.@]
2532 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2534 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2535 return 1;
2538 /*****************************************************************************
2539 * AddFormW [WINSPOOL.@]
2541 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2543 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2544 return 1;
2547 /*****************************************************************************
2548 * AddJobA [WINSPOOL.@]
2550 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2552 BOOL ret;
2553 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2554 DWORD needed;
2556 if(Level != 1) {
2557 SetLastError(ERROR_INVALID_LEVEL);
2558 return FALSE;
2561 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2563 if(ret) {
2564 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2565 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2566 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2567 if(*pcbNeeded > cbBuf) {
2568 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2569 ret = FALSE;
2570 } else {
2571 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2572 addjobA->JobId = addjobW->JobId;
2573 addjobA->Path = (char *)(addjobA + 1);
2574 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2577 return ret;
2580 /*****************************************************************************
2581 * AddJobW [WINSPOOL.@]
2583 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2585 opened_printer_t *printer;
2586 job_t *job;
2587 BOOL ret = FALSE;
2588 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2589 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2590 WCHAR path[MAX_PATH], filename[MAX_PATH];
2591 DWORD len;
2592 ADDJOB_INFO_1W *addjob;
2594 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2596 EnterCriticalSection(&printer_handles_cs);
2598 printer = get_opened_printer(hPrinter);
2600 if(!printer) {
2601 SetLastError(ERROR_INVALID_HANDLE);
2602 goto end;
2605 if(Level != 1) {
2606 SetLastError(ERROR_INVALID_LEVEL);
2607 goto end;
2610 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2611 if(!job)
2612 goto end;
2614 job->job_id = InterlockedIncrement(&next_job_id);
2616 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2617 if(path[len - 1] != '\\')
2618 path[len++] = '\\';
2619 memcpy(path + len, spool_path, sizeof(spool_path));
2620 sprintfW(filename, fmtW, path, job->job_id);
2622 len = strlenW(filename);
2623 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2624 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2625 job->document_title = strdupW(default_doc_title);
2626 list_add_tail(&printer->queue->jobs, &job->entry);
2628 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2629 if(*pcbNeeded <= cbBuf) {
2630 addjob = (ADDJOB_INFO_1W*)pData;
2631 addjob->JobId = job->job_id;
2632 addjob->Path = (WCHAR *)(addjob + 1);
2633 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2634 ret = TRUE;
2635 } else
2636 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2638 end:
2639 LeaveCriticalSection(&printer_handles_cs);
2640 return ret;
2643 /*****************************************************************************
2644 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2646 * Return the PATH for the Print-Processors
2648 * See GetPrintProcessorDirectoryW.
2652 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2653 DWORD level, LPBYTE Info,
2654 DWORD cbBuf, LPDWORD pcbNeeded)
2656 LPWSTR serverW = NULL;
2657 LPWSTR envW = NULL;
2658 BOOL ret;
2659 INT len;
2661 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2662 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2665 if (server) {
2666 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2667 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2671 if (env) {
2672 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2673 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2674 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2677 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2678 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2680 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2681 cbBuf, pcbNeeded);
2683 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2684 cbBuf, NULL, NULL) > 0;
2687 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2688 HeapFree(GetProcessHeap(), 0, envW);
2689 HeapFree(GetProcessHeap(), 0, serverW);
2690 return ret;
2693 /*****************************************************************************
2694 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2696 * Return the PATH for the Print-Processors
2698 * PARAMS
2699 * server [I] Servername (NT only) or NULL (local Computer)
2700 * env [I] Printing-Environment (see below) or NULL (Default)
2701 * level [I] Structure-Level (must be 1)
2702 * Info [O] PTR to Buffer that receives the Result
2703 * cbBuf [I] Size of Buffer at "Info"
2704 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2705 * required for the Buffer at "Info"
2707 * RETURNS
2708 * Success: TRUE and in pcbNeeded the Bytes used in Info
2709 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2710 * if cbBuf is too small
2712 * Native Values returned in Info on Success:
2713 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2714 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2715 *| win9x(Windows 4.0): "%winsysdir%"
2717 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2719 * BUGS
2720 * Only NULL or "" is supported for server
2723 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2724 DWORD level, LPBYTE Info,
2725 DWORD cbBuf, LPDWORD pcbNeeded)
2727 DWORD needed;
2728 const printenv_t * env_t;
2730 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2731 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2733 if(server != NULL && server[0]) {
2734 FIXME("server not supported: %s\n", debugstr_w(server));
2735 SetLastError(ERROR_INVALID_PARAMETER);
2736 return FALSE;
2739 env_t = validate_envW(env);
2740 if(!env_t) return FALSE; /* environment invalid or unsupported */
2742 if(level != 1) {
2743 WARN("(Level: %d) is ignored in win9x\n", level);
2744 SetLastError(ERROR_INVALID_LEVEL);
2745 return FALSE;
2748 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2749 needed = GetSystemDirectoryW(NULL, 0);
2750 /* add the Size for the Subdirectories */
2751 needed += lstrlenW(spoolprtprocsW);
2752 needed += lstrlenW(env_t->subdir);
2753 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2755 if(pcbNeeded) *pcbNeeded = needed;
2756 TRACE ("required: 0x%x/%d\n", needed, needed);
2757 if (needed > cbBuf) {
2758 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2759 return FALSE;
2761 if(pcbNeeded == NULL) {
2762 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2763 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2764 SetLastError(RPC_X_NULL_REF_POINTER);
2765 return FALSE;
2767 if(Info == NULL) {
2768 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2769 SetLastError(RPC_X_NULL_REF_POINTER);
2770 return FALSE;
2773 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2774 /* add the Subdirectories */
2775 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2776 lstrcatW((LPWSTR) Info, env_t->subdir);
2777 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2778 return TRUE;
2781 /*****************************************************************************
2782 * WINSPOOL_OpenDriverReg [internal]
2784 * opens the registry for the printer drivers depending on the given input
2785 * variable pEnvironment
2787 * RETURNS:
2788 * the opened hkey on success
2789 * NULL on error
2791 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2793 HKEY retval = NULL;
2794 LPWSTR buffer;
2795 const printenv_t * env;
2797 TRACE("(%s, %d)\n",
2798 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2800 if (!pEnvironment || unicode) {
2801 /* pEnvironment was NULL or an Unicode-String: use it direct */
2802 env = validate_envW(pEnvironment);
2804 else
2806 /* pEnvironment was an ANSI-String: convert to unicode first */
2807 LPWSTR buffer;
2808 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2809 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2810 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2811 env = validate_envW(buffer);
2812 HeapFree(GetProcessHeap(), 0, buffer);
2814 if (!env) return NULL;
2816 buffer = HeapAlloc( GetProcessHeap(), 0,
2817 (strlenW(DriversW) + strlenW(env->envname) +
2818 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2819 if(buffer) {
2820 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2821 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2822 HeapFree(GetProcessHeap(), 0, buffer);
2824 return retval;
2827 /*****************************************************************************
2828 * AddPrinterW [WINSPOOL.@]
2830 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2832 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2833 LPDEVMODEA dmA;
2834 LPDEVMODEW dmW;
2835 HANDLE retval;
2836 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2837 LONG size;
2838 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2839 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2840 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2841 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2842 statusW[] = {'S','t','a','t','u','s',0},
2843 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2845 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2847 if(pName != NULL) {
2848 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2849 SetLastError(ERROR_INVALID_PARAMETER);
2850 return 0;
2852 if(Level != 2) {
2853 ERR("Level = %d, unsupported!\n", Level);
2854 SetLastError(ERROR_INVALID_LEVEL);
2855 return 0;
2857 if(!pPrinter) {
2858 SetLastError(ERROR_INVALID_PARAMETER);
2859 return 0;
2861 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2862 ERROR_SUCCESS) {
2863 ERR("Can't create Printers key\n");
2864 return 0;
2866 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2867 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2868 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2869 RegCloseKey(hkeyPrinter);
2870 RegCloseKey(hkeyPrinters);
2871 return 0;
2873 RegCloseKey(hkeyPrinter);
2875 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2876 if(!hkeyDrivers) {
2877 ERR("Can't create Drivers key\n");
2878 RegCloseKey(hkeyPrinters);
2879 return 0;
2881 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2882 ERROR_SUCCESS) {
2883 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2884 RegCloseKey(hkeyPrinters);
2885 RegCloseKey(hkeyDrivers);
2886 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2887 return 0;
2889 RegCloseKey(hkeyDriver);
2890 RegCloseKey(hkeyDrivers);
2892 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2893 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2894 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2895 RegCloseKey(hkeyPrinters);
2896 return 0;
2899 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2900 ERROR_SUCCESS) {
2901 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2902 SetLastError(ERROR_INVALID_PRINTER_NAME);
2903 RegCloseKey(hkeyPrinters);
2904 return 0;
2906 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2907 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2908 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2910 /* See if we can load the driver. We may need the devmode structure anyway
2912 * FIXME:
2913 * Note that DocumentPropertiesW will briefly try to open the printer we
2914 * just create to find a DEVMODEA struct (it will use the WINEPS default
2915 * one in case it is not there, so we are ok).
2917 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2919 if(size < 0) {
2920 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2921 size = sizeof(DEVMODEW);
2923 if(pi->pDevMode)
2924 dmW = pi->pDevMode;
2925 else
2927 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2928 dmW->dmSize = size;
2929 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2931 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2932 HeapFree(GetProcessHeap(),0,dmW);
2933 dmW=NULL;
2935 else
2937 /* set devmode to printer name */
2938 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2942 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2943 and we support these drivers. NT writes DEVMODEW so somehow
2944 we'll need to distinguish between these when we support NT
2945 drivers */
2946 if (dmW)
2948 dmA = DEVMODEdupWtoA(dmW);
2949 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2950 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2951 HeapFree(GetProcessHeap(), 0, dmA);
2952 if(!pi->pDevMode)
2953 HeapFree(GetProcessHeap(), 0, dmW);
2955 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2956 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2957 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2958 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2960 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2961 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2962 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2963 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2964 (LPBYTE)&pi->Priority, sizeof(DWORD));
2965 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2966 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2967 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2968 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2969 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2970 (LPBYTE)&pi->Status, sizeof(DWORD));
2971 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2972 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2974 RegCloseKey(hkeyPrinter);
2975 RegCloseKey(hkeyPrinters);
2976 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2977 ERR("OpenPrinter failing\n");
2978 return 0;
2980 return retval;
2983 /*****************************************************************************
2984 * AddPrinterA [WINSPOOL.@]
2986 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2988 UNICODE_STRING pNameW;
2989 PWSTR pwstrNameW;
2990 PRINTER_INFO_2W *piW;
2991 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2992 HANDLE ret;
2994 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2995 if(Level != 2) {
2996 ERR("Level = %d, unsupported!\n", Level);
2997 SetLastError(ERROR_INVALID_LEVEL);
2998 return 0;
3000 pwstrNameW = asciitounicode(&pNameW,pName);
3001 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3003 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3005 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3006 RtlFreeUnicodeString(&pNameW);
3007 return ret;
3011 /*****************************************************************************
3012 * ClosePrinter [WINSPOOL.@]
3014 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3016 UINT_PTR i = (UINT_PTR)hPrinter;
3017 opened_printer_t *printer = NULL;
3018 BOOL ret = FALSE;
3020 TRACE("(%p)\n", hPrinter);
3022 EnterCriticalSection(&printer_handles_cs);
3024 if ((i > 0) && (i <= nb_printer_handles))
3025 printer = printer_handles[i - 1];
3028 if(printer)
3030 struct list *cursor, *cursor2;
3032 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3033 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3034 printer->hXcv, debugstr_w(printer->name), printer->doc );
3036 if(printer->doc)
3037 EndDocPrinter(hPrinter);
3039 if(InterlockedDecrement(&printer->queue->ref) == 0)
3041 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3043 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3044 ScheduleJob(hPrinter, job->job_id);
3046 HeapFree(GetProcessHeap(), 0, printer->queue);
3048 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3049 monitor_unload(printer->pm);
3050 HeapFree(GetProcessHeap(), 0, printer->printername);
3051 HeapFree(GetProcessHeap(), 0, printer->name);
3052 HeapFree(GetProcessHeap(), 0, printer);
3053 printer_handles[i - 1] = NULL;
3054 ret = TRUE;
3056 LeaveCriticalSection(&printer_handles_cs);
3057 return ret;
3060 /*****************************************************************************
3061 * DeleteFormA [WINSPOOL.@]
3063 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3065 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3066 return 1;
3069 /*****************************************************************************
3070 * DeleteFormW [WINSPOOL.@]
3072 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3074 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3075 return 1;
3078 /*****************************************************************************
3079 * DeletePrinter [WINSPOOL.@]
3081 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3083 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3084 HKEY hkeyPrinters, hkey;
3086 if(!lpNameW) {
3087 SetLastError(ERROR_INVALID_HANDLE);
3088 return FALSE;
3090 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3091 RegDeleteTreeW(hkeyPrinters, lpNameW);
3092 RegCloseKey(hkeyPrinters);
3094 WriteProfileStringW(devicesW, lpNameW, NULL);
3095 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3097 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3098 RegDeleteValueW(hkey, lpNameW);
3099 RegCloseKey(hkey);
3102 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3103 RegDeleteValueW(hkey, lpNameW);
3104 RegCloseKey(hkey);
3106 return TRUE;
3109 /*****************************************************************************
3110 * SetPrinterA [WINSPOOL.@]
3112 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3113 DWORD Command)
3115 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3116 return FALSE;
3119 /*****************************************************************************
3120 * SetJobA [WINSPOOL.@]
3122 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3123 LPBYTE pJob, DWORD Command)
3125 BOOL ret;
3126 LPBYTE JobW;
3127 UNICODE_STRING usBuffer;
3129 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3131 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3132 are all ignored by SetJob, so we don't bother copying them */
3133 switch(Level)
3135 case 0:
3136 JobW = NULL;
3137 break;
3138 case 1:
3140 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3141 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3143 JobW = (LPBYTE)info1W;
3144 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3145 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3146 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3147 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3148 info1W->Status = info1A->Status;
3149 info1W->Priority = info1A->Priority;
3150 info1W->Position = info1A->Position;
3151 info1W->PagesPrinted = info1A->PagesPrinted;
3152 break;
3154 case 2:
3156 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3157 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3159 JobW = (LPBYTE)info2W;
3160 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3161 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3162 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3163 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3164 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3165 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3166 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3167 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3168 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3169 info2W->Status = info2A->Status;
3170 info2W->Priority = info2A->Priority;
3171 info2W->Position = info2A->Position;
3172 info2W->StartTime = info2A->StartTime;
3173 info2W->UntilTime = info2A->UntilTime;
3174 info2W->PagesPrinted = info2A->PagesPrinted;
3175 break;
3177 case 3:
3178 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3179 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3180 break;
3181 default:
3182 SetLastError(ERROR_INVALID_LEVEL);
3183 return FALSE;
3186 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3188 switch(Level)
3190 case 1:
3192 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3193 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3194 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3195 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3196 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3197 break;
3199 case 2:
3201 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3202 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3203 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3204 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3205 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3206 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3207 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3208 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3209 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3210 break;
3213 HeapFree(GetProcessHeap(), 0, JobW);
3215 return ret;
3218 /*****************************************************************************
3219 * SetJobW [WINSPOOL.@]
3221 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3222 LPBYTE pJob, DWORD Command)
3224 BOOL ret = FALSE;
3225 job_t *job;
3227 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3228 FIXME("Ignoring everything other than document title\n");
3230 EnterCriticalSection(&printer_handles_cs);
3231 job = get_job(hPrinter, JobId);
3232 if(!job)
3233 goto end;
3235 switch(Level)
3237 case 0:
3238 break;
3239 case 1:
3241 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3242 HeapFree(GetProcessHeap(), 0, job->document_title);
3243 job->document_title = strdupW(info1->pDocument);
3244 break;
3246 case 2:
3248 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3249 HeapFree(GetProcessHeap(), 0, job->document_title);
3250 job->document_title = strdupW(info2->pDocument);
3251 break;
3253 case 3:
3254 break;
3255 default:
3256 SetLastError(ERROR_INVALID_LEVEL);
3257 goto end;
3259 ret = TRUE;
3260 end:
3261 LeaveCriticalSection(&printer_handles_cs);
3262 return ret;
3265 /*****************************************************************************
3266 * EndDocPrinter [WINSPOOL.@]
3268 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3270 opened_printer_t *printer;
3271 BOOL ret = FALSE;
3272 TRACE("(%p)\n", hPrinter);
3274 EnterCriticalSection(&printer_handles_cs);
3276 printer = get_opened_printer(hPrinter);
3277 if(!printer)
3279 SetLastError(ERROR_INVALID_HANDLE);
3280 goto end;
3283 if(!printer->doc)
3285 SetLastError(ERROR_SPL_NO_STARTDOC);
3286 goto end;
3289 CloseHandle(printer->doc->hf);
3290 ScheduleJob(hPrinter, printer->doc->job_id);
3291 HeapFree(GetProcessHeap(), 0, printer->doc);
3292 printer->doc = NULL;
3293 ret = TRUE;
3294 end:
3295 LeaveCriticalSection(&printer_handles_cs);
3296 return ret;
3299 /*****************************************************************************
3300 * EndPagePrinter [WINSPOOL.@]
3302 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3304 FIXME("(%p): stub\n", hPrinter);
3305 return TRUE;
3308 /*****************************************************************************
3309 * StartDocPrinterA [WINSPOOL.@]
3311 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3313 UNICODE_STRING usBuffer;
3314 DOC_INFO_2W doc2W;
3315 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3316 DWORD ret;
3318 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3319 or one (DOC_INFO_3) extra DWORDs */
3321 switch(Level) {
3322 case 2:
3323 doc2W.JobId = doc2->JobId;
3324 /* fall through */
3325 case 3:
3326 doc2W.dwMode = doc2->dwMode;
3327 /* fall through */
3328 case 1:
3329 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3330 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3331 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3332 break;
3334 default:
3335 SetLastError(ERROR_INVALID_LEVEL);
3336 return FALSE;
3339 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3341 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3342 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3343 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3345 return ret;
3348 /*****************************************************************************
3349 * StartDocPrinterW [WINSPOOL.@]
3351 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3353 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3354 opened_printer_t *printer;
3355 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3356 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3357 JOB_INFO_1W job_info;
3358 DWORD needed, ret = 0;
3359 HANDLE hf;
3360 WCHAR *filename;
3362 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3363 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3364 debugstr_w(doc->pDatatype));
3366 if(Level < 1 || Level > 3)
3368 SetLastError(ERROR_INVALID_LEVEL);
3369 return 0;
3372 EnterCriticalSection(&printer_handles_cs);
3373 printer = get_opened_printer(hPrinter);
3374 if(!printer)
3376 SetLastError(ERROR_INVALID_HANDLE);
3377 goto end;
3380 if(printer->doc)
3382 SetLastError(ERROR_INVALID_PRINTER_STATE);
3383 goto end;
3386 /* Even if we're printing to a file we still add a print job, we'll
3387 just ignore the spool file name */
3389 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3391 ERR("AddJob failed gle %u\n", GetLastError());
3392 goto end;
3395 if(doc->pOutputFile)
3396 filename = doc->pOutputFile;
3397 else
3398 filename = addjob->Path;
3400 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3401 if(hf == INVALID_HANDLE_VALUE)
3402 goto end;
3404 memset(&job_info, 0, sizeof(job_info));
3405 job_info.pDocument = doc->pDocName;
3406 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3408 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3409 printer->doc->hf = hf;
3410 ret = printer->doc->job_id = addjob->JobId;
3411 end:
3412 LeaveCriticalSection(&printer_handles_cs);
3414 return ret;
3417 /*****************************************************************************
3418 * StartPagePrinter [WINSPOOL.@]
3420 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3422 FIXME("(%p): stub\n", hPrinter);
3423 return TRUE;
3426 /*****************************************************************************
3427 * GetFormA [WINSPOOL.@]
3429 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3430 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3432 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3433 Level,pForm,cbBuf,pcbNeeded);
3434 return FALSE;
3437 /*****************************************************************************
3438 * GetFormW [WINSPOOL.@]
3440 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3441 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3443 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3444 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3445 return FALSE;
3448 /*****************************************************************************
3449 * SetFormA [WINSPOOL.@]
3451 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3452 LPBYTE pForm)
3454 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3455 return FALSE;
3458 /*****************************************************************************
3459 * SetFormW [WINSPOOL.@]
3461 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3462 LPBYTE pForm)
3464 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3465 return FALSE;
3468 /*****************************************************************************
3469 * ReadPrinter [WINSPOOL.@]
3471 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3472 LPDWORD pNoBytesRead)
3474 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3475 return FALSE;
3478 /*****************************************************************************
3479 * ResetPrinterA [WINSPOOL.@]
3481 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3483 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3484 return FALSE;
3487 /*****************************************************************************
3488 * ResetPrinterW [WINSPOOL.@]
3490 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3492 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3493 return FALSE;
3496 /*****************************************************************************
3497 * WINSPOOL_GetDWORDFromReg
3499 * Return DWORD associated with ValueName from hkey.
3501 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3503 DWORD sz = sizeof(DWORD), type, value = 0;
3504 LONG ret;
3506 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3508 if(ret != ERROR_SUCCESS) {
3509 WARN("Got ret = %d on name %s\n", ret, ValueName);
3510 return 0;
3512 if(type != REG_DWORD) {
3513 ERR("Got type %d\n", type);
3514 return 0;
3516 return value;
3520 /*****************************************************************************
3521 * get_filename_from_reg [internal]
3523 * Get ValueName from hkey storing result in out
3524 * when the Value in the registry has only a filename, use driverdir as prefix
3525 * outlen is space left in out
3526 * String is stored either as unicode or ascii
3530 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3531 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3533 WCHAR filename[MAX_PATH];
3534 DWORD size;
3535 DWORD type;
3536 LONG ret;
3537 LPWSTR buffer = filename;
3538 LPWSTR ptr;
3540 *needed = 0;
3541 size = sizeof(filename);
3542 buffer[0] = '\0';
3543 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3544 if (ret == ERROR_MORE_DATA) {
3545 TRACE("need dynamic buffer: %u\n", size);
3546 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3547 if (!buffer) {
3548 /* No Memory is bad */
3549 return FALSE;
3551 buffer[0] = '\0';
3552 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3555 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3556 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3557 return FALSE;
3560 ptr = buffer;
3561 while (ptr) {
3562 /* do we have a full path ? */
3563 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3564 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3566 if (!ret) {
3567 /* we must build the full Path */
3568 *needed += dirlen;
3569 if ((out) && (outlen > dirlen)) {
3570 if (unicode) {
3571 lstrcpyW((LPWSTR)out, driverdir);
3573 else
3575 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3577 out += dirlen;
3578 outlen -= dirlen;
3580 else
3581 out = NULL;
3584 /* write the filename */
3585 if (unicode) {
3586 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3587 if ((out) && (outlen >= size)) {
3588 lstrcpyW((LPWSTR)out, ptr);
3589 out += size;
3590 outlen -= size;
3592 else
3593 out = NULL;
3595 else
3597 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3598 if ((out) && (outlen >= size)) {
3599 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3600 out += size;
3601 outlen -= size;
3603 else
3604 out = NULL;
3606 *needed += size;
3607 ptr += lstrlenW(ptr)+1;
3608 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3611 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3613 /* write the multisz-termination */
3614 if (type == REG_MULTI_SZ) {
3615 size = (unicode) ? sizeof(WCHAR) : 1;
3617 *needed += size;
3618 if (out && (outlen >= size)) {
3619 memset (out, 0, size);
3622 return TRUE;
3625 /*****************************************************************************
3626 * WINSPOOL_GetStringFromReg
3628 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3629 * String is stored either as unicode or ascii.
3630 * Bit of a hack here to get the ValueName if we want ascii.
3632 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3633 DWORD buflen, DWORD *needed,
3634 BOOL unicode)
3636 DWORD sz = buflen, type;
3637 LONG ret;
3639 if(unicode)
3640 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3641 else {
3642 LPSTR ValueNameA = strdupWtoA(ValueName);
3643 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3644 HeapFree(GetProcessHeap(),0,ValueNameA);
3646 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3647 WARN("Got ret = %d\n", ret);
3648 *needed = 0;
3649 return FALSE;
3651 /* add space for terminating '\0' */
3652 sz += unicode ? sizeof(WCHAR) : 1;
3653 *needed = sz;
3655 if (ptr)
3656 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3658 return TRUE;
3661 /*****************************************************************************
3662 * WINSPOOL_GetDefaultDevMode
3664 * Get a default DevMode values for wineps.
3665 * FIXME - use ppd.
3668 static void WINSPOOL_GetDefaultDevMode(
3669 LPBYTE ptr,
3670 DWORD buflen, DWORD *needed,
3671 BOOL unicode)
3673 DEVMODEA dm;
3674 static const char szwps[] = "wineps.drv";
3676 /* fill default DEVMODE - should be read from ppd... */
3677 ZeroMemory( &dm, sizeof(dm) );
3678 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3679 dm.dmSpecVersion = DM_SPECVERSION;
3680 dm.dmDriverVersion = 1;
3681 dm.dmSize = sizeof(DEVMODEA);
3682 dm.dmDriverExtra = 0;
3683 dm.dmFields =
3684 DM_ORIENTATION | DM_PAPERSIZE |
3685 DM_PAPERLENGTH | DM_PAPERWIDTH |
3686 DM_SCALE |
3687 DM_COPIES |
3688 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3689 DM_YRESOLUTION | DM_TTOPTION;
3691 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3692 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3693 dm.u1.s1.dmPaperLength = 2970;
3694 dm.u1.s1.dmPaperWidth = 2100;
3696 dm.u1.s1.dmScale = 100;
3697 dm.u1.s1.dmCopies = 1;
3698 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3699 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3700 /* dm.dmColor */
3701 /* dm.dmDuplex */
3702 dm.dmYResolution = 300; /* 300dpi */
3703 dm.dmTTOption = DMTT_BITMAP;
3704 /* dm.dmCollate */
3705 /* dm.dmFormName */
3706 /* dm.dmLogPixels */
3707 /* dm.dmBitsPerPel */
3708 /* dm.dmPelsWidth */
3709 /* dm.dmPelsHeight */
3710 /* dm.u2.dmDisplayFlags */
3711 /* dm.dmDisplayFrequency */
3712 /* dm.dmICMMethod */
3713 /* dm.dmICMIntent */
3714 /* dm.dmMediaType */
3715 /* dm.dmDitherType */
3716 /* dm.dmReserved1 */
3717 /* dm.dmReserved2 */
3718 /* dm.dmPanningWidth */
3719 /* dm.dmPanningHeight */
3721 if(unicode) {
3722 if(buflen >= sizeof(DEVMODEW)) {
3723 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3724 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3725 HeapFree(GetProcessHeap(),0,pdmW);
3727 *needed = sizeof(DEVMODEW);
3729 else
3731 if(buflen >= sizeof(DEVMODEA)) {
3732 memcpy(ptr, &dm, sizeof(DEVMODEA));
3734 *needed = sizeof(DEVMODEA);
3738 /*****************************************************************************
3739 * WINSPOOL_GetDevModeFromReg
3741 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3742 * DevMode is stored either as unicode or ascii.
3744 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3745 LPBYTE ptr,
3746 DWORD buflen, DWORD *needed,
3747 BOOL unicode)
3749 DWORD sz = buflen, type;
3750 LONG ret;
3752 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3753 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3754 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3755 if (sz < sizeof(DEVMODEA))
3757 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3758 return FALSE;
3760 /* ensures that dmSize is not erratically bogus if registry is invalid */
3761 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3762 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3763 if(unicode) {
3764 sz += (CCHDEVICENAME + CCHFORMNAME);
3765 if(buflen >= sz) {
3766 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3767 memcpy(ptr, dmW, sz);
3768 HeapFree(GetProcessHeap(),0,dmW);
3771 *needed = sz;
3772 return TRUE;
3775 /*********************************************************************
3776 * WINSPOOL_GetPrinter_1
3778 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3779 * The strings are either stored as unicode or ascii.
3781 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3782 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3783 BOOL unicode)
3785 DWORD size, left = cbBuf;
3786 BOOL space = (cbBuf > 0);
3787 LPBYTE ptr = buf;
3789 *pcbNeeded = 0;
3791 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3792 unicode)) {
3793 if(space && size <= left) {
3794 pi1->pName = (LPWSTR)ptr;
3795 ptr += size;
3796 left -= size;
3797 } else
3798 space = FALSE;
3799 *pcbNeeded += size;
3802 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3803 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3804 unicode)) {
3805 if(space && size <= left) {
3806 pi1->pDescription = (LPWSTR)ptr;
3807 ptr += size;
3808 left -= size;
3809 } else
3810 space = FALSE;
3811 *pcbNeeded += size;
3814 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3815 unicode)) {
3816 if(space && size <= left) {
3817 pi1->pComment = (LPWSTR)ptr;
3818 ptr += size;
3819 left -= size;
3820 } else
3821 space = FALSE;
3822 *pcbNeeded += size;
3825 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3827 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3828 memset(pi1, 0, sizeof(*pi1));
3830 return space;
3832 /*********************************************************************
3833 * WINSPOOL_GetPrinter_2
3835 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3836 * The strings are either stored as unicode or ascii.
3838 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3839 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3840 BOOL unicode)
3842 DWORD size, left = cbBuf;
3843 BOOL space = (cbBuf > 0);
3844 LPBYTE ptr = buf;
3846 *pcbNeeded = 0;
3848 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3849 unicode)) {
3850 if(space && size <= left) {
3851 pi2->pPrinterName = (LPWSTR)ptr;
3852 ptr += size;
3853 left -= size;
3854 } else
3855 space = FALSE;
3856 *pcbNeeded += size;
3858 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3859 unicode)) {
3860 if(space && size <= left) {
3861 pi2->pShareName = (LPWSTR)ptr;
3862 ptr += size;
3863 left -= size;
3864 } else
3865 space = FALSE;
3866 *pcbNeeded += size;
3868 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3869 unicode)) {
3870 if(space && size <= left) {
3871 pi2->pPortName = (LPWSTR)ptr;
3872 ptr += size;
3873 left -= size;
3874 } else
3875 space = FALSE;
3876 *pcbNeeded += size;
3878 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3879 &size, unicode)) {
3880 if(space && size <= left) {
3881 pi2->pDriverName = (LPWSTR)ptr;
3882 ptr += size;
3883 left -= size;
3884 } else
3885 space = FALSE;
3886 *pcbNeeded += size;
3888 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3889 unicode)) {
3890 if(space && size <= left) {
3891 pi2->pComment = (LPWSTR)ptr;
3892 ptr += size;
3893 left -= size;
3894 } else
3895 space = FALSE;
3896 *pcbNeeded += size;
3898 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3899 unicode)) {
3900 if(space && size <= left) {
3901 pi2->pLocation = (LPWSTR)ptr;
3902 ptr += size;
3903 left -= size;
3904 } else
3905 space = FALSE;
3906 *pcbNeeded += size;
3908 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3909 &size, unicode)) {
3910 if(space && size <= left) {
3911 pi2->pDevMode = (LPDEVMODEW)ptr;
3912 ptr += size;
3913 left -= size;
3914 } else
3915 space = FALSE;
3916 *pcbNeeded += size;
3918 else
3920 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3921 if(space && size <= left) {
3922 pi2->pDevMode = (LPDEVMODEW)ptr;
3923 ptr += size;
3924 left -= size;
3925 } else
3926 space = FALSE;
3927 *pcbNeeded += size;
3929 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3930 &size, unicode)) {
3931 if(space && size <= left) {
3932 pi2->pSepFile = (LPWSTR)ptr;
3933 ptr += size;
3934 left -= size;
3935 } else
3936 space = FALSE;
3937 *pcbNeeded += size;
3939 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3940 &size, unicode)) {
3941 if(space && size <= left) {
3942 pi2->pPrintProcessor = (LPWSTR)ptr;
3943 ptr += size;
3944 left -= size;
3945 } else
3946 space = FALSE;
3947 *pcbNeeded += size;
3949 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3950 &size, unicode)) {
3951 if(space && size <= left) {
3952 pi2->pDatatype = (LPWSTR)ptr;
3953 ptr += size;
3954 left -= size;
3955 } else
3956 space = FALSE;
3957 *pcbNeeded += size;
3959 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3960 &size, unicode)) {
3961 if(space && size <= left) {
3962 pi2->pParameters = (LPWSTR)ptr;
3963 ptr += size;
3964 left -= size;
3965 } else
3966 space = FALSE;
3967 *pcbNeeded += size;
3969 if(pi2) {
3970 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3971 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3972 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3973 "Default Priority");
3974 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3975 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3978 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3979 memset(pi2, 0, sizeof(*pi2));
3981 return space;
3984 /*********************************************************************
3985 * WINSPOOL_GetPrinter_4
3987 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3989 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3990 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3991 BOOL unicode)
3993 DWORD size, left = cbBuf;
3994 BOOL space = (cbBuf > 0);
3995 LPBYTE ptr = buf;
3997 *pcbNeeded = 0;
3999 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4000 unicode)) {
4001 if(space && size <= left) {
4002 pi4->pPrinterName = (LPWSTR)ptr;
4003 ptr += size;
4004 left -= size;
4005 } else
4006 space = FALSE;
4007 *pcbNeeded += size;
4009 if(pi4) {
4010 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4013 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4014 memset(pi4, 0, sizeof(*pi4));
4016 return space;
4019 /*********************************************************************
4020 * WINSPOOL_GetPrinter_5
4022 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4024 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4025 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4026 BOOL unicode)
4028 DWORD size, left = cbBuf;
4029 BOOL space = (cbBuf > 0);
4030 LPBYTE ptr = buf;
4032 *pcbNeeded = 0;
4034 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4035 unicode)) {
4036 if(space && size <= left) {
4037 pi5->pPrinterName = (LPWSTR)ptr;
4038 ptr += size;
4039 left -= size;
4040 } else
4041 space = FALSE;
4042 *pcbNeeded += size;
4044 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4045 unicode)) {
4046 if(space && size <= left) {
4047 pi5->pPortName = (LPWSTR)ptr;
4048 ptr += size;
4049 left -= size;
4050 } else
4051 space = FALSE;
4052 *pcbNeeded += size;
4054 if(pi5) {
4055 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4056 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4057 "dnsTimeout");
4058 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4059 "txTimeout");
4062 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4063 memset(pi5, 0, sizeof(*pi5));
4065 return space;
4068 /*********************************************************************
4069 * WINSPOOL_GetPrinter_7
4071 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4073 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4074 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4076 DWORD size, left = cbBuf;
4077 BOOL space = (cbBuf > 0);
4078 LPBYTE ptr = buf;
4080 *pcbNeeded = 0;
4082 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4084 if (space && size <= left) {
4085 pi7->pszObjectGUID = (LPWSTR)ptr;
4086 ptr += size;
4087 left -= size;
4088 } else
4089 space = FALSE;
4090 *pcbNeeded += size;
4092 if (pi7) {
4093 /* We do not have a Directory Service */
4094 pi7->dwAction = DSPRINT_UNPUBLISH;
4097 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4098 memset(pi7, 0, sizeof(*pi7));
4100 return space;
4103 /*********************************************************************
4104 * WINSPOOL_GetPrinter_9
4106 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4107 * The strings are either stored as unicode or ascii.
4109 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4110 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4112 DWORD size;
4113 BOOL space = (cbBuf > 0);
4115 *pcbNeeded = 0;
4117 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4118 if(space && size <= cbBuf) {
4119 pi9->pDevMode = (LPDEVMODEW)buf;
4120 } else
4121 space = FALSE;
4122 *pcbNeeded += size;
4124 else
4126 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4127 if(space && size <= cbBuf) {
4128 pi9->pDevMode = (LPDEVMODEW)buf;
4129 } else
4130 space = FALSE;
4131 *pcbNeeded += size;
4134 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4135 memset(pi9, 0, sizeof(*pi9));
4137 return space;
4140 /*****************************************************************************
4141 * WINSPOOL_GetPrinter
4143 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4144 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4145 * just a collection of pointers to strings.
4147 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4148 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4150 LPCWSTR name;
4151 DWORD size, needed = 0;
4152 LPBYTE ptr = NULL;
4153 HKEY hkeyPrinter, hkeyPrinters;
4154 BOOL ret;
4156 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4158 if (!(name = get_opened_printer_name(hPrinter))) {
4159 SetLastError(ERROR_INVALID_HANDLE);
4160 return FALSE;
4163 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4164 ERROR_SUCCESS) {
4165 ERR("Can't create Printers key\n");
4166 return FALSE;
4168 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4170 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4171 RegCloseKey(hkeyPrinters);
4172 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4173 return FALSE;
4176 switch(Level) {
4177 case 2:
4179 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4181 size = sizeof(PRINTER_INFO_2W);
4182 if(size <= cbBuf) {
4183 ptr = pPrinter + size;
4184 cbBuf -= size;
4185 memset(pPrinter, 0, size);
4186 } else {
4187 pi2 = NULL;
4188 cbBuf = 0;
4190 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4191 unicode);
4192 needed += size;
4193 break;
4196 case 4:
4198 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4200 size = sizeof(PRINTER_INFO_4W);
4201 if(size <= cbBuf) {
4202 ptr = pPrinter + size;
4203 cbBuf -= size;
4204 memset(pPrinter, 0, size);
4205 } else {
4206 pi4 = NULL;
4207 cbBuf = 0;
4209 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4210 unicode);
4211 needed += size;
4212 break;
4216 case 5:
4218 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4220 size = sizeof(PRINTER_INFO_5W);
4221 if(size <= cbBuf) {
4222 ptr = pPrinter + size;
4223 cbBuf -= size;
4224 memset(pPrinter, 0, size);
4225 } else {
4226 pi5 = NULL;
4227 cbBuf = 0;
4230 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4231 unicode);
4232 needed += size;
4233 break;
4237 case 6:
4239 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4241 size = sizeof(PRINTER_INFO_6);
4242 if (size <= cbBuf) {
4243 /* FIXME: We do not update the status yet */
4244 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4245 ret = TRUE;
4246 } else {
4247 ret = FALSE;
4250 needed += size;
4251 break;
4254 case 7:
4256 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4258 size = sizeof(PRINTER_INFO_7W);
4259 if (size <= cbBuf) {
4260 ptr = pPrinter + size;
4261 cbBuf -= size;
4262 memset(pPrinter, 0, size);
4263 } else {
4264 pi7 = NULL;
4265 cbBuf = 0;
4268 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4269 needed += size;
4270 break;
4274 case 9:
4276 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4278 size = sizeof(PRINTER_INFO_9W);
4279 if(size <= cbBuf) {
4280 ptr = pPrinter + size;
4281 cbBuf -= size;
4282 memset(pPrinter, 0, size);
4283 } else {
4284 pi9 = NULL;
4285 cbBuf = 0;
4288 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4289 needed += size;
4290 break;
4294 default:
4295 FIXME("Unimplemented level %d\n", Level);
4296 SetLastError(ERROR_INVALID_LEVEL);
4297 RegCloseKey(hkeyPrinters);
4298 RegCloseKey(hkeyPrinter);
4299 return FALSE;
4302 RegCloseKey(hkeyPrinter);
4303 RegCloseKey(hkeyPrinters);
4305 TRACE("returning %d needed = %d\n", ret, needed);
4306 if(pcbNeeded) *pcbNeeded = needed;
4307 if(!ret)
4308 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4309 return ret;
4312 /*****************************************************************************
4313 * GetPrinterW [WINSPOOL.@]
4315 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4316 DWORD cbBuf, LPDWORD pcbNeeded)
4318 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4319 TRUE);
4322 /*****************************************************************************
4323 * GetPrinterA [WINSPOOL.@]
4325 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4326 DWORD cbBuf, LPDWORD pcbNeeded)
4328 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4329 FALSE);
4332 /*****************************************************************************
4333 * WINSPOOL_EnumPrinters
4335 * Implementation of EnumPrintersA|W
4337 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4338 DWORD dwLevel, LPBYTE lpbPrinters,
4339 DWORD cbBuf, LPDWORD lpdwNeeded,
4340 LPDWORD lpdwReturned, BOOL unicode)
4343 HKEY hkeyPrinters, hkeyPrinter;
4344 WCHAR PrinterName[255];
4345 DWORD needed = 0, number = 0;
4346 DWORD used, i, left;
4347 PBYTE pi, buf;
4349 if(lpbPrinters)
4350 memset(lpbPrinters, 0, cbBuf);
4351 if(lpdwReturned)
4352 *lpdwReturned = 0;
4353 if(lpdwNeeded)
4354 *lpdwNeeded = 0;
4356 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4357 if(dwType == PRINTER_ENUM_DEFAULT)
4358 return TRUE;
4360 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4361 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4362 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4363 if (!dwType) {
4364 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4365 *lpdwNeeded = 0;
4366 *lpdwReturned = 0;
4367 return TRUE;
4372 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4373 FIXME("dwType = %08x\n", dwType);
4374 SetLastError(ERROR_INVALID_FLAGS);
4375 return FALSE;
4378 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4379 ERROR_SUCCESS) {
4380 ERR("Can't create Printers key\n");
4381 return FALSE;
4384 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4385 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4386 RegCloseKey(hkeyPrinters);
4387 ERR("Can't query Printers key\n");
4388 return FALSE;
4390 TRACE("Found %d printers\n", number);
4392 switch(dwLevel) {
4393 case 1:
4394 used = number * sizeof(PRINTER_INFO_1W);
4395 break;
4396 case 2:
4397 used = number * sizeof(PRINTER_INFO_2W);
4398 break;
4399 case 4:
4400 used = number * sizeof(PRINTER_INFO_4W);
4401 break;
4402 case 5:
4403 used = number * sizeof(PRINTER_INFO_5W);
4404 break;
4406 default:
4407 SetLastError(ERROR_INVALID_LEVEL);
4408 RegCloseKey(hkeyPrinters);
4409 return FALSE;
4411 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4413 for(i = 0; i < number; i++) {
4414 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4415 ERROR_SUCCESS) {
4416 ERR("Can't enum key number %d\n", i);
4417 RegCloseKey(hkeyPrinters);
4418 return FALSE;
4420 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4421 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4422 ERROR_SUCCESS) {
4423 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4424 RegCloseKey(hkeyPrinters);
4425 return FALSE;
4428 if(cbBuf > used) {
4429 buf = lpbPrinters + used;
4430 left = cbBuf - used;
4431 } else {
4432 buf = NULL;
4433 left = 0;
4436 switch(dwLevel) {
4437 case 1:
4438 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4439 left, &needed, unicode);
4440 used += needed;
4441 if(pi) pi += sizeof(PRINTER_INFO_1W);
4442 break;
4443 case 2:
4444 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4445 left, &needed, unicode);
4446 used += needed;
4447 if(pi) pi += sizeof(PRINTER_INFO_2W);
4448 break;
4449 case 4:
4450 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4451 left, &needed, unicode);
4452 used += needed;
4453 if(pi) pi += sizeof(PRINTER_INFO_4W);
4454 break;
4455 case 5:
4456 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4457 left, &needed, unicode);
4458 used += needed;
4459 if(pi) pi += sizeof(PRINTER_INFO_5W);
4460 break;
4461 default:
4462 ERR("Shouldn't be here!\n");
4463 RegCloseKey(hkeyPrinter);
4464 RegCloseKey(hkeyPrinters);
4465 return FALSE;
4467 RegCloseKey(hkeyPrinter);
4469 RegCloseKey(hkeyPrinters);
4471 if(lpdwNeeded)
4472 *lpdwNeeded = used;
4474 if(used > cbBuf) {
4475 if(lpbPrinters)
4476 memset(lpbPrinters, 0, cbBuf);
4477 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4478 return FALSE;
4480 if(lpdwReturned)
4481 *lpdwReturned = number;
4482 SetLastError(ERROR_SUCCESS);
4483 return TRUE;
4487 /******************************************************************
4488 * EnumPrintersW [WINSPOOL.@]
4490 * Enumerates the available printers, print servers and print
4491 * providers, depending on the specified flags, name and level.
4493 * RETURNS:
4495 * If level is set to 1:
4496 * Returns an array of PRINTER_INFO_1 data structures in the
4497 * lpbPrinters buffer.
4499 * If level is set to 2:
4500 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4501 * Returns an array of PRINTER_INFO_2 data structures in the
4502 * lpbPrinters buffer. Note that according to MSDN also an
4503 * OpenPrinter should be performed on every remote printer.
4505 * If level is set to 4 (officially WinNT only):
4506 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4507 * Fast: Only the registry is queried to retrieve printer names,
4508 * no connection to the driver is made.
4509 * Returns an array of PRINTER_INFO_4 data structures in the
4510 * lpbPrinters buffer.
4512 * If level is set to 5 (officially WinNT4/Win9x only):
4513 * Fast: Only the registry is queried to retrieve printer names,
4514 * no connection to the driver is made.
4515 * Returns an array of PRINTER_INFO_5 data structures in the
4516 * lpbPrinters buffer.
4518 * If level set to 3 or 6+:
4519 * returns zero (failure!)
4521 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4522 * for information.
4524 * BUGS:
4525 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4526 * - Only levels 2, 4 and 5 are implemented at the moment.
4527 * - 16-bit printer drivers are not enumerated.
4528 * - Returned amount of bytes used/needed does not match the real Windoze
4529 * implementation (as in this implementation, all strings are part
4530 * of the buffer, whereas Win32 keeps them somewhere else)
4531 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4533 * NOTE:
4534 * - In a regular Wine installation, no registry settings for printers
4535 * exist, which makes this function return an empty list.
4537 BOOL WINAPI EnumPrintersW(
4538 DWORD dwType, /* [in] Types of print objects to enumerate */
4539 LPWSTR lpszName, /* [in] name of objects to enumerate */
4540 DWORD dwLevel, /* [in] type of printer info structure */
4541 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4542 DWORD cbBuf, /* [in] max size of buffer in bytes */
4543 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4544 LPDWORD lpdwReturned /* [out] number of entries returned */
4547 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4548 lpdwNeeded, lpdwReturned, TRUE);
4551 /******************************************************************
4552 * EnumPrintersA [WINSPOOL.@]
4554 * See EnumPrintersW
4557 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4558 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4560 BOOL ret;
4561 UNICODE_STRING pNameU;
4562 LPWSTR pNameW;
4563 LPBYTE pPrintersW;
4565 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4566 pPrinters, cbBuf, pcbNeeded, pcReturned);
4568 pNameW = asciitounicode(&pNameU, pName);
4570 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4571 MS Office need this */
4572 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4574 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4576 RtlFreeUnicodeString(&pNameU);
4577 if (ret) {
4578 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4580 HeapFree(GetProcessHeap(), 0, pPrintersW);
4581 return ret;
4584 /*****************************************************************************
4585 * WINSPOOL_GetDriverInfoFromReg [internal]
4587 * Enters the information from the registry into the DRIVER_INFO struct
4589 * RETURNS
4590 * zero if the printer driver does not exist in the registry
4591 * (only if Level > 1) otherwise nonzero
4593 static BOOL WINSPOOL_GetDriverInfoFromReg(
4594 HKEY hkeyDrivers,
4595 LPWSTR DriverName,
4596 const printenv_t * env,
4597 DWORD Level,
4598 LPBYTE ptr, /* DRIVER_INFO */
4599 LPBYTE pDriverStrings, /* strings buffer */
4600 DWORD cbBuf, /* size of string buffer */
4601 LPDWORD pcbNeeded, /* space needed for str. */
4602 BOOL unicode) /* type of strings */
4604 DWORD size, tmp;
4605 HKEY hkeyDriver;
4606 WCHAR driverdir[MAX_PATH];
4607 DWORD dirlen;
4608 LPBYTE strPtr = pDriverStrings;
4609 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4611 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4612 debugstr_w(DriverName), env,
4613 Level, di, pDriverStrings, cbBuf, unicode);
4615 if (di) ZeroMemory(di, di_sizeof[Level]);
4617 if (unicode) {
4618 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4619 if (*pcbNeeded <= cbBuf)
4620 strcpyW((LPWSTR)strPtr, DriverName);
4622 else
4624 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4625 if (*pcbNeeded <= cbBuf)
4626 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4629 /* pName for level 1 has a different offset! */
4630 if (Level == 1) {
4631 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4632 return TRUE;
4635 /* .cVersion and .pName for level > 1 */
4636 if (di) {
4637 di->cVersion = env->driverversion;
4638 di->pName = (LPWSTR) strPtr;
4639 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4642 /* Reserve Space for the largest subdir and a Backslash*/
4643 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4644 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4645 /* Should never Fail */
4646 return FALSE;
4648 lstrcatW(driverdir, env->versionsubdir);
4649 lstrcatW(driverdir, backslashW);
4651 /* dirlen must not include the terminating zero */
4652 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4653 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4655 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4656 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4657 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4658 return FALSE;
4661 /* pEnvironment */
4662 if (unicode)
4663 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4664 else
4665 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4667 *pcbNeeded += size;
4668 if (*pcbNeeded <= cbBuf) {
4669 if (unicode) {
4670 lstrcpyW((LPWSTR)strPtr, env->envname);
4672 else
4674 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4676 if (di) di->pEnvironment = (LPWSTR)strPtr;
4677 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4680 /* .pDriverPath is the Graphics rendering engine.
4681 The full Path is required to avoid a crash in some apps */
4682 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4683 *pcbNeeded += size;
4684 if (*pcbNeeded <= cbBuf)
4685 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4687 if (di) di->pDriverPath = (LPWSTR)strPtr;
4688 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4691 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4692 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4693 *pcbNeeded += size;
4694 if (*pcbNeeded <= cbBuf)
4695 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4697 if (di) di->pDataFile = (LPWSTR)strPtr;
4698 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4701 /* .pConfigFile is the Driver user Interface */
4702 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4703 *pcbNeeded += size;
4704 if (*pcbNeeded <= cbBuf)
4705 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4707 if (di) di->pConfigFile = (LPWSTR)strPtr;
4708 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4711 if (Level == 2 ) {
4712 RegCloseKey(hkeyDriver);
4713 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4714 return TRUE;
4717 if (Level == 5 ) {
4718 RegCloseKey(hkeyDriver);
4719 FIXME("level 5: incomplete\n");
4720 return TRUE;
4723 /* .pHelpFile */
4724 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4725 *pcbNeeded += size;
4726 if (*pcbNeeded <= cbBuf)
4727 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4729 if (di) di->pHelpFile = (LPWSTR)strPtr;
4730 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4733 /* .pDependentFiles */
4734 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4735 *pcbNeeded += size;
4736 if (*pcbNeeded <= cbBuf)
4737 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4739 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4740 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4742 else if (GetVersion() & 0x80000000) {
4743 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4744 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4745 *pcbNeeded += size;
4746 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4748 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4749 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4752 /* .pMonitorName is the optional Language Monitor */
4753 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4754 *pcbNeeded += size;
4755 if (*pcbNeeded <= cbBuf)
4756 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4758 if (di) di->pMonitorName = (LPWSTR)strPtr;
4759 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4762 /* .pDefaultDataType */
4763 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4764 *pcbNeeded += size;
4765 if(*pcbNeeded <= cbBuf)
4766 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4768 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4769 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4772 if (Level == 3 ) {
4773 RegCloseKey(hkeyDriver);
4774 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4775 return TRUE;
4778 /* .pszzPreviousNames */
4779 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4780 *pcbNeeded += size;
4781 if(*pcbNeeded <= cbBuf)
4782 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4784 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4785 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4788 if (Level == 4 ) {
4789 RegCloseKey(hkeyDriver);
4790 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4791 return TRUE;
4794 /* support is missing, but not important enough for a FIXME */
4795 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4797 /* .pszMfgName */
4798 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4799 *pcbNeeded += size;
4800 if(*pcbNeeded <= cbBuf)
4801 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4803 if (di) di->pszMfgName = (LPWSTR)strPtr;
4804 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4807 /* .pszOEMUrl */
4808 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4809 *pcbNeeded += size;
4810 if(*pcbNeeded <= cbBuf)
4811 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4813 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4814 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4817 /* .pszHardwareID */
4818 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4819 *pcbNeeded += size;
4820 if(*pcbNeeded <= cbBuf)
4821 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4823 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4824 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4827 /* .pszProvider */
4828 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4829 *pcbNeeded += size;
4830 if(*pcbNeeded <= cbBuf)
4831 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4833 if (di) di->pszProvider = (LPWSTR)strPtr;
4834 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4837 if (Level == 6 ) {
4838 RegCloseKey(hkeyDriver);
4839 return TRUE;
4842 /* support is missing, but not important enough for a FIXME */
4843 TRACE("level 8: incomplete\n");
4845 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4846 RegCloseKey(hkeyDriver);
4847 return TRUE;
4850 /*****************************************************************************
4851 * WINSPOOL_GetPrinterDriver
4853 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4854 DWORD Level, LPBYTE pDriverInfo,
4855 DWORD cbBuf, LPDWORD pcbNeeded,
4856 BOOL unicode)
4858 LPCWSTR name;
4859 WCHAR DriverName[100];
4860 DWORD ret, type, size, needed = 0;
4861 LPBYTE ptr = NULL;
4862 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4863 const printenv_t * env;
4865 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4866 Level,pDriverInfo,cbBuf, pcbNeeded);
4869 if (!(name = get_opened_printer_name(hPrinter))) {
4870 SetLastError(ERROR_INVALID_HANDLE);
4871 return FALSE;
4874 if (Level < 1 || Level == 7 || Level > 8) {
4875 SetLastError(ERROR_INVALID_LEVEL);
4876 return FALSE;
4879 env = validate_envW(pEnvironment);
4880 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4882 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4883 ERROR_SUCCESS) {
4884 ERR("Can't create Printers key\n");
4885 return FALSE;
4887 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4888 != ERROR_SUCCESS) {
4889 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4890 RegCloseKey(hkeyPrinters);
4891 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4892 return FALSE;
4894 size = sizeof(DriverName);
4895 DriverName[0] = 0;
4896 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4897 (LPBYTE)DriverName, &size);
4898 RegCloseKey(hkeyPrinter);
4899 RegCloseKey(hkeyPrinters);
4900 if(ret != ERROR_SUCCESS) {
4901 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4902 return FALSE;
4905 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4906 if(!hkeyDrivers) {
4907 ERR("Can't create Drivers key\n");
4908 return FALSE;
4911 size = di_sizeof[Level];
4912 if ((size <= cbBuf) && pDriverInfo)
4913 ptr = pDriverInfo + size;
4915 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4916 env, Level, pDriverInfo, ptr,
4917 (cbBuf < size) ? 0 : cbBuf - size,
4918 &needed, unicode)) {
4919 RegCloseKey(hkeyDrivers);
4920 return FALSE;
4923 RegCloseKey(hkeyDrivers);
4925 if(pcbNeeded) *pcbNeeded = size + needed;
4926 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4927 if(cbBuf >= needed) return TRUE;
4928 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4929 return FALSE;
4932 /*****************************************************************************
4933 * GetPrinterDriverA [WINSPOOL.@]
4935 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4936 DWORD Level, LPBYTE pDriverInfo,
4937 DWORD cbBuf, LPDWORD pcbNeeded)
4939 BOOL ret;
4940 UNICODE_STRING pEnvW;
4941 PWSTR pwstrEnvW;
4943 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4944 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4945 cbBuf, pcbNeeded, FALSE);
4946 RtlFreeUnicodeString(&pEnvW);
4947 return ret;
4949 /*****************************************************************************
4950 * GetPrinterDriverW [WINSPOOL.@]
4952 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4953 DWORD Level, LPBYTE pDriverInfo,
4954 DWORD cbBuf, LPDWORD pcbNeeded)
4956 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4957 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4960 /*****************************************************************************
4961 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4963 * Return the PATH for the Printer-Drivers (UNICODE)
4965 * PARAMS
4966 * pName [I] Servername (NT only) or NULL (local Computer)
4967 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4968 * Level [I] Structure-Level (must be 1)
4969 * pDriverDirectory [O] PTR to Buffer that receives the Result
4970 * cbBuf [I] Size of Buffer at pDriverDirectory
4971 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4972 * required for pDriverDirectory
4974 * RETURNS
4975 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4976 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4977 * if cbBuf is too small
4979 * Native Values returned in pDriverDirectory on Success:
4980 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4981 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4982 *| win9x(Windows 4.0): "%winsysdir%"
4984 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4986 * FIXME
4987 *- Only NULL or "" is supported for pName
4990 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4991 DWORD Level, LPBYTE pDriverDirectory,
4992 DWORD cbBuf, LPDWORD pcbNeeded)
4994 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4995 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4997 if ((backend == NULL) && !load_backend()) return FALSE;
4999 if (Level != 1) {
5000 /* (Level != 1) is ignored in win9x */
5001 SetLastError(ERROR_INVALID_LEVEL);
5002 return FALSE;
5004 if (pcbNeeded == NULL) {
5005 /* (pcbNeeded == NULL) is ignored in win9x */
5006 SetLastError(RPC_X_NULL_REF_POINTER);
5007 return FALSE;
5010 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5011 pDriverDirectory, cbBuf, pcbNeeded);
5016 /*****************************************************************************
5017 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5019 * Return the PATH for the Printer-Drivers (ANSI)
5021 * See GetPrinterDriverDirectoryW.
5023 * NOTES
5024 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5027 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5028 DWORD Level, LPBYTE pDriverDirectory,
5029 DWORD cbBuf, LPDWORD pcbNeeded)
5031 UNICODE_STRING nameW, environmentW;
5032 BOOL ret;
5033 DWORD pcbNeededW;
5034 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5035 WCHAR *driverDirectoryW = NULL;
5037 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5038 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5040 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5042 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5043 else nameW.Buffer = NULL;
5044 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5045 else environmentW.Buffer = NULL;
5047 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5048 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5049 if (ret) {
5050 DWORD needed;
5051 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5052 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5053 if(pcbNeeded)
5054 *pcbNeeded = needed;
5055 ret = (needed <= cbBuf) ? TRUE : FALSE;
5056 } else
5057 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5059 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5061 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5062 RtlFreeUnicodeString(&environmentW);
5063 RtlFreeUnicodeString(&nameW);
5065 return ret;
5068 /*****************************************************************************
5069 * AddPrinterDriverA [WINSPOOL.@]
5071 * See AddPrinterDriverW.
5074 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5076 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5077 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5080 /******************************************************************************
5081 * AddPrinterDriverW (WINSPOOL.@)
5083 * Install a Printer Driver
5085 * PARAMS
5086 * pName [I] Servername or NULL (local Computer)
5087 * level [I] Level for the supplied DRIVER_INFO_*W struct
5088 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5090 * RESULTS
5091 * Success: TRUE
5092 * Failure: FALSE
5095 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5097 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5098 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5101 /*****************************************************************************
5102 * AddPrintProcessorA [WINSPOOL.@]
5104 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5105 LPSTR pPrintProcessorName)
5107 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5108 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5109 return FALSE;
5112 /*****************************************************************************
5113 * AddPrintProcessorW [WINSPOOL.@]
5115 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5116 LPWSTR pPrintProcessorName)
5118 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5119 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5120 return FALSE;
5123 /*****************************************************************************
5124 * AddPrintProvidorA [WINSPOOL.@]
5126 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5128 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5129 return FALSE;
5132 /*****************************************************************************
5133 * AddPrintProvidorW [WINSPOOL.@]
5135 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5137 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5138 return FALSE;
5141 /*****************************************************************************
5142 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5144 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5145 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5147 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5148 pDevModeOutput, pDevModeInput);
5149 return 0;
5152 /*****************************************************************************
5153 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5155 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5156 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5158 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5159 pDevModeOutput, pDevModeInput);
5160 return 0;
5163 /*****************************************************************************
5164 * PrinterProperties [WINSPOOL.@]
5166 * Displays a dialog to set the properties of the printer.
5168 * RETURNS
5169 * nonzero on success or zero on failure
5171 * BUGS
5172 * implemented as stub only
5174 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5175 HANDLE hPrinter /* [in] handle to printer object */
5177 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5178 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5179 return FALSE;
5182 /*****************************************************************************
5183 * EnumJobsA [WINSPOOL.@]
5186 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5187 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5188 LPDWORD pcReturned)
5190 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5191 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5193 if(pcbNeeded) *pcbNeeded = 0;
5194 if(pcReturned) *pcReturned = 0;
5195 return FALSE;
5199 /*****************************************************************************
5200 * EnumJobsW [WINSPOOL.@]
5203 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5204 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5205 LPDWORD pcReturned)
5207 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5208 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5210 if(pcbNeeded) *pcbNeeded = 0;
5211 if(pcReturned) *pcReturned = 0;
5212 return FALSE;
5215 /*****************************************************************************
5216 * WINSPOOL_EnumPrinterDrivers [internal]
5218 * Delivers information about all printer drivers installed on the
5219 * localhost or a given server
5221 * RETURNS
5222 * nonzero on success or zero on failure. If the buffer for the returned
5223 * information is too small the function will return an error
5225 * BUGS
5226 * - only implemented for localhost, foreign hosts will return an error
5228 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5229 DWORD Level, LPBYTE pDriverInfo,
5230 DWORD cbBuf, LPDWORD pcbNeeded,
5231 LPDWORD pcReturned, BOOL unicode)
5233 { HKEY hkeyDrivers;
5234 DWORD i, needed, number = 0, size = 0;
5235 WCHAR DriverNameW[255];
5236 PBYTE ptr;
5237 const printenv_t * env;
5239 TRACE("%s,%s,%d,%p,%d,%d\n",
5240 debugstr_w(pName), debugstr_w(pEnvironment),
5241 Level, pDriverInfo, cbBuf, unicode);
5243 /* check for local drivers */
5244 if((pName) && (pName[0])) {
5245 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5246 SetLastError(ERROR_ACCESS_DENIED);
5247 return FALSE;
5250 env = validate_envW(pEnvironment);
5251 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5253 /* check input parameter */
5254 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5255 SetLastError(ERROR_INVALID_LEVEL);
5256 return FALSE;
5259 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5260 SetLastError(RPC_X_NULL_REF_POINTER);
5261 return FALSE;
5264 /* initialize return values */
5265 if(pDriverInfo)
5266 memset( pDriverInfo, 0, cbBuf);
5267 *pcbNeeded = 0;
5268 *pcReturned = 0;
5270 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5271 if(!hkeyDrivers) {
5272 ERR("Can't open Drivers key\n");
5273 return FALSE;
5276 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5277 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5278 RegCloseKey(hkeyDrivers);
5279 ERR("Can't query Drivers key\n");
5280 return FALSE;
5282 TRACE("Found %d Drivers\n", number);
5284 /* get size of single struct
5285 * unicode and ascii structure have the same size
5287 size = di_sizeof[Level];
5289 /* calculate required buffer size */
5290 *pcbNeeded = size * number;
5292 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5293 i < number;
5294 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5295 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5296 != ERROR_SUCCESS) {
5297 ERR("Can't enum key number %d\n", i);
5298 RegCloseKey(hkeyDrivers);
5299 return FALSE;
5301 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5302 env, Level, ptr,
5303 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5304 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5305 &needed, unicode)) {
5306 RegCloseKey(hkeyDrivers);
5307 return FALSE;
5309 (*pcbNeeded) += needed;
5312 RegCloseKey(hkeyDrivers);
5314 if(cbBuf < *pcbNeeded){
5315 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5316 return FALSE;
5319 *pcReturned = number;
5320 return TRUE;
5323 /*****************************************************************************
5324 * EnumPrinterDriversW [WINSPOOL.@]
5326 * see function EnumPrinterDrivers for RETURNS, BUGS
5328 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5329 LPBYTE pDriverInfo, DWORD cbBuf,
5330 LPDWORD pcbNeeded, LPDWORD pcReturned)
5332 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5333 cbBuf, pcbNeeded, pcReturned, TRUE);
5336 /*****************************************************************************
5337 * EnumPrinterDriversA [WINSPOOL.@]
5339 * see function EnumPrinterDrivers for RETURNS, BUGS
5341 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5342 LPBYTE pDriverInfo, DWORD cbBuf,
5343 LPDWORD pcbNeeded, LPDWORD pcReturned)
5344 { BOOL ret;
5345 UNICODE_STRING pNameW, pEnvironmentW;
5346 PWSTR pwstrNameW, pwstrEnvironmentW;
5348 pwstrNameW = asciitounicode(&pNameW, pName);
5349 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5351 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5352 Level, pDriverInfo, cbBuf, pcbNeeded,
5353 pcReturned, FALSE);
5354 RtlFreeUnicodeString(&pNameW);
5355 RtlFreeUnicodeString(&pEnvironmentW);
5357 return ret;
5360 /******************************************************************************
5361 * EnumPortsA (WINSPOOL.@)
5363 * See EnumPortsW.
5366 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5367 LPDWORD pcbNeeded, LPDWORD pcReturned)
5369 BOOL res;
5370 LPBYTE bufferW = NULL;
5371 LPWSTR nameW = NULL;
5372 DWORD needed = 0;
5373 DWORD numentries = 0;
5374 INT len;
5376 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5377 cbBuf, pcbNeeded, pcReturned);
5379 /* convert servername to unicode */
5380 if (pName) {
5381 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5382 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5383 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5385 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5386 needed = cbBuf * sizeof(WCHAR);
5387 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5388 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5390 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5391 if (pcbNeeded) needed = *pcbNeeded;
5392 /* HeapReAlloc return NULL, when bufferW was NULL */
5393 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5394 HeapAlloc(GetProcessHeap(), 0, needed);
5396 /* Try again with the large Buffer */
5397 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5399 needed = pcbNeeded ? *pcbNeeded : 0;
5400 numentries = pcReturned ? *pcReturned : 0;
5403 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5404 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5406 if (res) {
5407 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5408 DWORD entrysize = 0;
5409 DWORD index;
5410 LPSTR ptr;
5411 LPPORT_INFO_2W pi2w;
5412 LPPORT_INFO_2A pi2a;
5414 needed = 0;
5415 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5417 /* First pass: calculate the size for all Entries */
5418 pi2w = (LPPORT_INFO_2W) bufferW;
5419 pi2a = (LPPORT_INFO_2A) pPorts;
5420 index = 0;
5421 while (index < numentries) {
5422 index++;
5423 needed += entrysize; /* PORT_INFO_?A */
5424 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5426 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5427 NULL, 0, NULL, NULL);
5428 if (Level > 1) {
5429 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5430 NULL, 0, NULL, NULL);
5431 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5432 NULL, 0, NULL, NULL);
5434 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5435 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5436 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5439 /* check for errors and quit on failure */
5440 if (cbBuf < needed) {
5441 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5442 res = FALSE;
5443 goto cleanup;
5445 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5446 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5447 cbBuf -= len ; /* free Bytes in the user-Buffer */
5448 pi2w = (LPPORT_INFO_2W) bufferW;
5449 pi2a = (LPPORT_INFO_2A) pPorts;
5450 index = 0;
5451 /* Second Pass: Fill the User Buffer (if we have one) */
5452 while ((index < numentries) && pPorts) {
5453 index++;
5454 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5455 pi2a->pPortName = ptr;
5456 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5457 ptr, cbBuf , NULL, NULL);
5458 ptr += len;
5459 cbBuf -= len;
5460 if (Level > 1) {
5461 pi2a->pMonitorName = ptr;
5462 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5463 ptr, cbBuf, NULL, NULL);
5464 ptr += len;
5465 cbBuf -= len;
5467 pi2a->pDescription = ptr;
5468 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5469 ptr, cbBuf, NULL, NULL);
5470 ptr += len;
5471 cbBuf -= len;
5473 pi2a->fPortType = pi2w->fPortType;
5474 pi2a->Reserved = 0; /* documented: "must be zero" */
5477 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5478 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5479 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5483 cleanup:
5484 if (pcbNeeded) *pcbNeeded = needed;
5485 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5487 HeapFree(GetProcessHeap(), 0, nameW);
5488 HeapFree(GetProcessHeap(), 0, bufferW);
5490 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5491 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5493 return (res);
5497 /******************************************************************************
5498 * EnumPortsW (WINSPOOL.@)
5500 * Enumerate available Ports
5502 * PARAMS
5503 * name [I] Servername or NULL (local Computer)
5504 * level [I] Structure-Level (1 or 2)
5505 * buffer [O] PTR to Buffer that receives the Result
5506 * bufsize [I] Size of Buffer at buffer
5507 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5508 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5510 * RETURNS
5511 * Success: TRUE
5512 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5516 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5518 DWORD needed = 0;
5519 DWORD numentries = 0;
5520 BOOL res = FALSE;
5522 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5523 cbBuf, pcbNeeded, pcReturned);
5525 if (pName && (pName[0])) {
5526 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5527 SetLastError(ERROR_ACCESS_DENIED);
5528 goto emP_cleanup;
5531 /* Level is not checked in win9x */
5532 if (!Level || (Level > 2)) {
5533 WARN("level (%d) is ignored in win9x\n", Level);
5534 SetLastError(ERROR_INVALID_LEVEL);
5535 goto emP_cleanup;
5537 if (!pcbNeeded) {
5538 SetLastError(RPC_X_NULL_REF_POINTER);
5539 goto emP_cleanup;
5542 EnterCriticalSection(&monitor_handles_cs);
5543 monitor_loadall();
5545 /* Scan all local Ports */
5546 numentries = 0;
5547 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5549 /* we calculated the needed buffersize. now do the error-checks */
5550 if (cbBuf < needed) {
5551 monitor_unloadall();
5552 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5553 goto emP_cleanup_cs;
5555 else if (!pPorts || !pcReturned) {
5556 monitor_unloadall();
5557 SetLastError(RPC_X_NULL_REF_POINTER);
5558 goto emP_cleanup_cs;
5561 /* Fill the Buffer */
5562 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5563 res = TRUE;
5564 monitor_unloadall();
5566 emP_cleanup_cs:
5567 LeaveCriticalSection(&monitor_handles_cs);
5569 emP_cleanup:
5570 if (pcbNeeded) *pcbNeeded = needed;
5571 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5573 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5574 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5576 return (res);
5579 /******************************************************************************
5580 * GetDefaultPrinterW (WINSPOOL.@)
5582 * FIXME
5583 * This function must read the value from data 'device' of key
5584 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5586 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5588 BOOL retval = TRUE;
5589 DWORD insize, len;
5590 WCHAR *buffer, *ptr;
5592 if (!namesize)
5594 SetLastError(ERROR_INVALID_PARAMETER);
5595 return FALSE;
5598 /* make the buffer big enough for the stuff from the profile/registry,
5599 * the content must fit into the local buffer to compute the correct
5600 * size even if the extern buffer is too small or not given.
5601 * (20 for ,driver,port) */
5602 insize = *namesize;
5603 len = max(100, (insize + 20));
5604 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5606 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5608 SetLastError (ERROR_FILE_NOT_FOUND);
5609 retval = FALSE;
5610 goto end;
5612 TRACE("%s\n", debugstr_w(buffer));
5614 if ((ptr = strchrW(buffer, ',')) == NULL)
5616 SetLastError(ERROR_INVALID_NAME);
5617 retval = FALSE;
5618 goto end;
5621 *ptr = 0;
5622 *namesize = strlenW(buffer) + 1;
5623 if(!name || (*namesize > insize))
5625 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5626 retval = FALSE;
5627 goto end;
5629 strcpyW(name, buffer);
5631 end:
5632 HeapFree( GetProcessHeap(), 0, buffer);
5633 return retval;
5637 /******************************************************************************
5638 * GetDefaultPrinterA (WINSPOOL.@)
5640 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5642 BOOL retval = TRUE;
5643 DWORD insize = 0;
5644 WCHAR *bufferW = NULL;
5646 if (!namesize)
5648 SetLastError(ERROR_INVALID_PARAMETER);
5649 return FALSE;
5652 if(name && *namesize) {
5653 insize = *namesize;
5654 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5657 if(!GetDefaultPrinterW( bufferW, namesize)) {
5658 retval = FALSE;
5659 goto end;
5662 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5663 NULL, NULL);
5664 if (!*namesize)
5666 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5667 retval = FALSE;
5669 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5671 end:
5672 HeapFree( GetProcessHeap(), 0, bufferW);
5673 return retval;
5677 /******************************************************************************
5678 * SetDefaultPrinterW (WINSPOOL.204)
5680 * Set the Name of the Default Printer
5682 * PARAMS
5683 * pszPrinter [I] Name of the Printer or NULL
5685 * RETURNS
5686 * Success: True
5687 * Failure: FALSE
5689 * NOTES
5690 * When the Parameter is NULL or points to an Empty String and
5691 * a Default Printer was already present, then this Function changes nothing.
5692 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5693 * the First enumerated local Printer is used.
5696 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5699 TRACE("(%s)\n", debugstr_w(pszPrinter));
5701 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5702 return FALSE;
5705 /******************************************************************************
5706 * SetDefaultPrinterA (WINSPOOL.202)
5708 * See SetDefaultPrinterW.
5711 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5714 TRACE("(%s)\n", debugstr_a(pszPrinter));
5716 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5717 return FALSE;
5721 /******************************************************************************
5722 * SetPrinterDataExA (WINSPOOL.@)
5724 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5725 LPCSTR pValueName, DWORD Type,
5726 LPBYTE pData, DWORD cbData)
5728 HKEY hkeyPrinter, hkeySubkey;
5729 DWORD ret;
5731 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5732 debugstr_a(pValueName), Type, pData, cbData);
5734 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5735 != ERROR_SUCCESS)
5736 return ret;
5738 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5739 != ERROR_SUCCESS) {
5740 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5741 RegCloseKey(hkeyPrinter);
5742 return ret;
5744 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5745 RegCloseKey(hkeySubkey);
5746 RegCloseKey(hkeyPrinter);
5747 return ret;
5750 /******************************************************************************
5751 * SetPrinterDataExW (WINSPOOL.@)
5753 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5754 LPCWSTR pValueName, DWORD Type,
5755 LPBYTE pData, DWORD cbData)
5757 HKEY hkeyPrinter, hkeySubkey;
5758 DWORD ret;
5760 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5761 debugstr_w(pValueName), Type, pData, cbData);
5763 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5764 != ERROR_SUCCESS)
5765 return ret;
5767 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5768 != ERROR_SUCCESS) {
5769 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5770 RegCloseKey(hkeyPrinter);
5771 return ret;
5773 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5774 RegCloseKey(hkeySubkey);
5775 RegCloseKey(hkeyPrinter);
5776 return ret;
5779 /******************************************************************************
5780 * SetPrinterDataA (WINSPOOL.@)
5782 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5783 LPBYTE pData, DWORD cbData)
5785 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5786 pData, cbData);
5789 /******************************************************************************
5790 * SetPrinterDataW (WINSPOOL.@)
5792 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5793 LPBYTE pData, DWORD cbData)
5795 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5796 pData, cbData);
5799 /******************************************************************************
5800 * GetPrinterDataExA (WINSPOOL.@)
5802 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5803 LPCSTR pValueName, LPDWORD pType,
5804 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5806 HKEY hkeyPrinter, hkeySubkey;
5807 DWORD ret;
5809 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5810 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5811 pcbNeeded);
5813 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5814 != ERROR_SUCCESS)
5815 return ret;
5817 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5818 != ERROR_SUCCESS) {
5819 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5820 RegCloseKey(hkeyPrinter);
5821 return ret;
5823 *pcbNeeded = nSize;
5824 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5825 RegCloseKey(hkeySubkey);
5826 RegCloseKey(hkeyPrinter);
5827 return ret;
5830 /******************************************************************************
5831 * GetPrinterDataExW (WINSPOOL.@)
5833 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5834 LPCWSTR pValueName, LPDWORD pType,
5835 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5837 HKEY hkeyPrinter, hkeySubkey;
5838 DWORD ret;
5840 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5841 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5842 pcbNeeded);
5844 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5845 != ERROR_SUCCESS)
5846 return ret;
5848 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5849 != ERROR_SUCCESS) {
5850 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5851 RegCloseKey(hkeyPrinter);
5852 return ret;
5854 *pcbNeeded = nSize;
5855 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5856 RegCloseKey(hkeySubkey);
5857 RegCloseKey(hkeyPrinter);
5858 return ret;
5861 /******************************************************************************
5862 * GetPrinterDataA (WINSPOOL.@)
5864 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5865 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5867 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5868 pData, nSize, pcbNeeded);
5871 /******************************************************************************
5872 * GetPrinterDataW (WINSPOOL.@)
5874 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5875 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5877 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5878 pData, nSize, pcbNeeded);
5881 /*******************************************************************************
5882 * EnumPrinterDataExW [WINSPOOL.@]
5884 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5885 LPBYTE pEnumValues, DWORD cbEnumValues,
5886 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5888 HKEY hkPrinter, hkSubKey;
5889 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5890 cbValueNameLen, cbMaxValueLen, cbValueLen,
5891 cbBufSize, dwType;
5892 LPWSTR lpValueName;
5893 HANDLE hHeap;
5894 PBYTE lpValue;
5895 PPRINTER_ENUM_VALUESW ppev;
5897 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5899 if (pKeyName == NULL || *pKeyName == 0)
5900 return ERROR_INVALID_PARAMETER;
5902 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5903 if (ret != ERROR_SUCCESS)
5905 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5906 hPrinter, ret);
5907 return ret;
5910 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5911 if (ret != ERROR_SUCCESS)
5913 r = RegCloseKey (hkPrinter);
5914 if (r != ERROR_SUCCESS)
5915 WARN ("RegCloseKey returned %i\n", r);
5916 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5917 debugstr_w (pKeyName), ret);
5918 return ret;
5921 ret = RegCloseKey (hkPrinter);
5922 if (ret != ERROR_SUCCESS)
5924 ERR ("RegCloseKey returned %i\n", ret);
5925 r = RegCloseKey (hkSubKey);
5926 if (r != ERROR_SUCCESS)
5927 WARN ("RegCloseKey returned %i\n", r);
5928 return ret;
5931 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5932 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5933 if (ret != ERROR_SUCCESS)
5935 r = RegCloseKey (hkSubKey);
5936 if (r != ERROR_SUCCESS)
5937 WARN ("RegCloseKey returned %i\n", r);
5938 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5939 return ret;
5942 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5943 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5945 if (cValues == 0) /* empty key */
5947 r = RegCloseKey (hkSubKey);
5948 if (r != ERROR_SUCCESS)
5949 WARN ("RegCloseKey returned %i\n", r);
5950 *pcbEnumValues = *pnEnumValues = 0;
5951 return ERROR_SUCCESS;
5954 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5956 hHeap = GetProcessHeap ();
5957 if (hHeap == NULL)
5959 ERR ("GetProcessHeap failed\n");
5960 r = RegCloseKey (hkSubKey);
5961 if (r != ERROR_SUCCESS)
5962 WARN ("RegCloseKey returned %i\n", r);
5963 return ERROR_OUTOFMEMORY;
5966 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5967 if (lpValueName == NULL)
5969 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5970 r = RegCloseKey (hkSubKey);
5971 if (r != ERROR_SUCCESS)
5972 WARN ("RegCloseKey returned %i\n", r);
5973 return ERROR_OUTOFMEMORY;
5976 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5977 if (lpValue == NULL)
5979 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5980 if (HeapFree (hHeap, 0, lpValueName) == 0)
5981 WARN ("HeapFree failed with code %i\n", GetLastError ());
5982 r = RegCloseKey (hkSubKey);
5983 if (r != ERROR_SUCCESS)
5984 WARN ("RegCloseKey returned %i\n", r);
5985 return ERROR_OUTOFMEMORY;
5988 TRACE ("pass 1: calculating buffer required for all names and values\n");
5990 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5992 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5994 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5996 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5997 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5998 NULL, NULL, lpValue, &cbValueLen);
5999 if (ret != ERROR_SUCCESS)
6001 if (HeapFree (hHeap, 0, lpValue) == 0)
6002 WARN ("HeapFree failed with code %i\n", GetLastError ());
6003 if (HeapFree (hHeap, 0, lpValueName) == 0)
6004 WARN ("HeapFree failed with code %i\n", GetLastError ());
6005 r = RegCloseKey (hkSubKey);
6006 if (r != ERROR_SUCCESS)
6007 WARN ("RegCloseKey returned %i\n", r);
6008 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6009 return ret;
6012 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6013 debugstr_w (lpValueName), dwIndex,
6014 cbValueNameLen + 1, cbValueLen);
6016 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6017 cbBufSize += cbValueLen;
6020 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6022 *pcbEnumValues = cbBufSize;
6023 *pnEnumValues = cValues;
6025 if (cbEnumValues < cbBufSize) /* buffer too small */
6027 if (HeapFree (hHeap, 0, lpValue) == 0)
6028 WARN ("HeapFree failed with code %i\n", GetLastError ());
6029 if (HeapFree (hHeap, 0, lpValueName) == 0)
6030 WARN ("HeapFree failed with code %i\n", GetLastError ());
6031 r = RegCloseKey (hkSubKey);
6032 if (r != ERROR_SUCCESS)
6033 WARN ("RegCloseKey returned %i\n", r);
6034 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6035 return ERROR_MORE_DATA;
6038 TRACE ("pass 2: copying all names and values to buffer\n");
6040 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6041 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6043 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6045 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6046 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6047 NULL, &dwType, lpValue, &cbValueLen);
6048 if (ret != ERROR_SUCCESS)
6050 if (HeapFree (hHeap, 0, lpValue) == 0)
6051 WARN ("HeapFree failed with code %i\n", GetLastError ());
6052 if (HeapFree (hHeap, 0, lpValueName) == 0)
6053 WARN ("HeapFree failed with code %i\n", GetLastError ());
6054 r = RegCloseKey (hkSubKey);
6055 if (r != ERROR_SUCCESS)
6056 WARN ("RegCloseKey returned %i\n", r);
6057 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6058 return ret;
6061 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6062 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6063 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6064 pEnumValues += cbValueNameLen;
6066 /* return # of *bytes* (including trailing \0), not # of chars */
6067 ppev[dwIndex].cbValueName = cbValueNameLen;
6069 ppev[dwIndex].dwType = dwType;
6071 memcpy (pEnumValues, lpValue, cbValueLen);
6072 ppev[dwIndex].pData = pEnumValues;
6073 pEnumValues += cbValueLen;
6075 ppev[dwIndex].cbData = cbValueLen;
6077 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6078 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6081 if (HeapFree (hHeap, 0, lpValue) == 0)
6083 ret = GetLastError ();
6084 ERR ("HeapFree failed with code %i\n", ret);
6085 if (HeapFree (hHeap, 0, lpValueName) == 0)
6086 WARN ("HeapFree failed with code %i\n", GetLastError ());
6087 r = RegCloseKey (hkSubKey);
6088 if (r != ERROR_SUCCESS)
6089 WARN ("RegCloseKey returned %i\n", r);
6090 return ret;
6093 if (HeapFree (hHeap, 0, lpValueName) == 0)
6095 ret = GetLastError ();
6096 ERR ("HeapFree failed with code %i\n", ret);
6097 r = RegCloseKey (hkSubKey);
6098 if (r != ERROR_SUCCESS)
6099 WARN ("RegCloseKey returned %i\n", r);
6100 return ret;
6103 ret = RegCloseKey (hkSubKey);
6104 if (ret != ERROR_SUCCESS)
6106 ERR ("RegCloseKey returned %i\n", ret);
6107 return ret;
6110 return ERROR_SUCCESS;
6113 /*******************************************************************************
6114 * EnumPrinterDataExA [WINSPOOL.@]
6116 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6117 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6118 * what Windows 2000 SP1 does.
6121 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6122 LPBYTE pEnumValues, DWORD cbEnumValues,
6123 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6125 INT len;
6126 LPWSTR pKeyNameW;
6127 DWORD ret, dwIndex, dwBufSize;
6128 HANDLE hHeap;
6129 LPSTR pBuffer;
6131 TRACE ("%p %s\n", hPrinter, pKeyName);
6133 if (pKeyName == NULL || *pKeyName == 0)
6134 return ERROR_INVALID_PARAMETER;
6136 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6137 if (len == 0)
6139 ret = GetLastError ();
6140 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6141 return ret;
6144 hHeap = GetProcessHeap ();
6145 if (hHeap == NULL)
6147 ERR ("GetProcessHeap failed\n");
6148 return ERROR_OUTOFMEMORY;
6151 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6152 if (pKeyNameW == NULL)
6154 ERR ("Failed to allocate %i bytes from process heap\n",
6155 (LONG)(len * sizeof (WCHAR)));
6156 return ERROR_OUTOFMEMORY;
6159 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6161 ret = GetLastError ();
6162 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6163 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6164 WARN ("HeapFree failed with code %i\n", GetLastError ());
6165 return ret;
6168 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6169 pcbEnumValues, pnEnumValues);
6170 if (ret != ERROR_SUCCESS)
6172 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6173 WARN ("HeapFree failed with code %i\n", GetLastError ());
6174 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6175 return ret;
6178 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6180 ret = GetLastError ();
6181 ERR ("HeapFree failed with code %i\n", ret);
6182 return ret;
6185 if (*pnEnumValues == 0) /* empty key */
6186 return ERROR_SUCCESS;
6188 dwBufSize = 0;
6189 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6191 PPRINTER_ENUM_VALUESW ppev =
6192 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6194 if (dwBufSize < ppev->cbValueName)
6195 dwBufSize = ppev->cbValueName;
6197 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6198 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6199 dwBufSize = ppev->cbData;
6202 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6204 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6205 if (pBuffer == NULL)
6207 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6208 return ERROR_OUTOFMEMORY;
6211 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6213 PPRINTER_ENUM_VALUESW ppev =
6214 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6216 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6217 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6218 NULL);
6219 if (len == 0)
6221 ret = GetLastError ();
6222 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6223 if (HeapFree (hHeap, 0, pBuffer) == 0)
6224 WARN ("HeapFree failed with code %i\n", GetLastError ());
6225 return ret;
6228 memcpy (ppev->pValueName, pBuffer, len);
6230 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6232 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6233 ppev->dwType != REG_MULTI_SZ)
6234 continue;
6236 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6237 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6238 if (len == 0)
6240 ret = GetLastError ();
6241 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6242 if (HeapFree (hHeap, 0, pBuffer) == 0)
6243 WARN ("HeapFree failed with code %i\n", GetLastError ());
6244 return ret;
6247 memcpy (ppev->pData, pBuffer, len);
6249 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6250 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6253 if (HeapFree (hHeap, 0, pBuffer) == 0)
6255 ret = GetLastError ();
6256 ERR ("HeapFree failed with code %i\n", ret);
6257 return ret;
6260 return ERROR_SUCCESS;
6263 /******************************************************************************
6264 * AbortPrinter (WINSPOOL.@)
6266 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6268 FIXME("(%p), stub!\n", hPrinter);
6269 return TRUE;
6272 /******************************************************************************
6273 * AddPortA (WINSPOOL.@)
6275 * See AddPortW.
6278 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6280 LPWSTR nameW = NULL;
6281 LPWSTR monitorW = NULL;
6282 DWORD len;
6283 BOOL res;
6285 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6287 if (pName) {
6288 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6289 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6290 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6293 if (pMonitorName) {
6294 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6295 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6296 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6298 res = AddPortW(nameW, hWnd, monitorW);
6299 HeapFree(GetProcessHeap(), 0, nameW);
6300 HeapFree(GetProcessHeap(), 0, monitorW);
6301 return res;
6304 /******************************************************************************
6305 * AddPortW (WINSPOOL.@)
6307 * Add a Port for a specific Monitor
6309 * PARAMS
6310 * pName [I] Servername or NULL (local Computer)
6311 * hWnd [I] Handle to parent Window for the Dialog-Box
6312 * pMonitorName [I] Name of the Monitor that manage the Port
6314 * RETURNS
6315 * Success: TRUE
6316 * Failure: FALSE
6319 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6321 monitor_t * pm;
6322 monitor_t * pui;
6323 DWORD res;
6325 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6327 if (pName && pName[0]) {
6328 SetLastError(ERROR_INVALID_PARAMETER);
6329 return FALSE;
6332 if (!pMonitorName) {
6333 SetLastError(RPC_X_NULL_REF_POINTER);
6334 return FALSE;
6337 /* an empty Monitorname is Invalid */
6338 if (!pMonitorName[0]) {
6339 SetLastError(ERROR_NOT_SUPPORTED);
6340 return FALSE;
6343 pm = monitor_load(pMonitorName, NULL);
6344 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6345 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6346 TRACE("got %d with %u\n", res, GetLastError());
6347 res = TRUE;
6349 else
6351 pui = monitor_loadui(pm);
6352 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6353 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6354 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6355 TRACE("got %d with %u\n", res, GetLastError());
6356 res = TRUE;
6358 else
6360 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6361 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6363 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6364 SetLastError(ERROR_NOT_SUPPORTED);
6365 res = FALSE;
6367 monitor_unload(pui);
6369 monitor_unload(pm);
6370 TRACE("returning %d with %u\n", res, GetLastError());
6371 return res;
6374 /******************************************************************************
6375 * AddPortExA (WINSPOOL.@)
6377 * See AddPortExW.
6380 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6382 PORT_INFO_2W pi2W;
6383 PORT_INFO_2A * pi2A;
6384 LPWSTR nameW = NULL;
6385 LPWSTR monitorW = NULL;
6386 DWORD len;
6387 BOOL res;
6389 pi2A = (PORT_INFO_2A *) pBuffer;
6391 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6392 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6394 if ((level < 1) || (level > 2)) {
6395 SetLastError(ERROR_INVALID_LEVEL);
6396 return FALSE;
6399 if (!pi2A) {
6400 SetLastError(ERROR_INVALID_PARAMETER);
6401 return FALSE;
6404 if (pName) {
6405 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6406 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6407 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6410 if (pMonitorName) {
6411 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6412 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6413 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6416 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6418 if (pi2A->pPortName) {
6419 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6420 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6421 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6424 if (level > 1) {
6425 if (pi2A->pMonitorName) {
6426 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6427 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6428 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6431 if (pi2A->pDescription) {
6432 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6433 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6434 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6436 pi2W.fPortType = pi2A->fPortType;
6437 pi2W.Reserved = pi2A->Reserved;
6440 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6442 HeapFree(GetProcessHeap(), 0, nameW);
6443 HeapFree(GetProcessHeap(), 0, monitorW);
6444 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6445 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6446 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6447 return res;
6451 /******************************************************************************
6452 * AddPortExW (WINSPOOL.@)
6454 * Add a Port for a specific Monitor, without presenting a user interface
6456 * PARAMS
6457 * pName [I] Servername or NULL (local Computer)
6458 * level [I] Structure-Level (1 or 2) for pBuffer
6459 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6460 * pMonitorName [I] Name of the Monitor that manage the Port
6462 * RETURNS
6463 * Success: TRUE
6464 * Failure: FALSE
6467 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6469 PORT_INFO_2W * pi2;
6470 monitor_t * pm;
6471 DWORD res = FALSE;
6473 pi2 = (PORT_INFO_2W *) pBuffer;
6475 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6476 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6477 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6478 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6481 if ((level < 1) || (level > 2)) {
6482 SetLastError(ERROR_INVALID_LEVEL);
6483 return FALSE;
6486 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6487 SetLastError(ERROR_INVALID_PARAMETER);
6488 return FALSE;
6491 /* load the Monitor */
6492 pm = monitor_load(pMonitorName, NULL);
6493 if (!pm) {
6494 SetLastError(ERROR_INVALID_PARAMETER);
6495 return FALSE;
6498 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6499 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6500 TRACE("got %u with %u\n", res, GetLastError());
6502 else
6504 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6506 monitor_unload(pm);
6507 return res;
6510 /******************************************************************************
6511 * AddPrinterConnectionA (WINSPOOL.@)
6513 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6515 FIXME("%s\n", debugstr_a(pName));
6516 return FALSE;
6519 /******************************************************************************
6520 * AddPrinterConnectionW (WINSPOOL.@)
6522 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6524 FIXME("%s\n", debugstr_w(pName));
6525 return FALSE;
6528 /******************************************************************************
6529 * AddPrinterDriverExW (WINSPOOL.@)
6531 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6533 * PARAMS
6534 * pName [I] Servername or NULL (local Computer)
6535 * level [I] Level for the supplied DRIVER_INFO_*W struct
6536 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6537 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6539 * RESULTS
6540 * Success: TRUE
6541 * Failure: FALSE
6544 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6546 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6548 if ((backend == NULL) && !load_backend()) return FALSE;
6550 if (level < 2 || level == 5 || level == 7 || level > 8) {
6551 SetLastError(ERROR_INVALID_LEVEL);
6552 return FALSE;
6555 if (!pDriverInfo) {
6556 SetLastError(ERROR_INVALID_PARAMETER);
6557 return FALSE;
6560 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6563 /******************************************************************************
6564 * AddPrinterDriverExA (WINSPOOL.@)
6566 * See AddPrinterDriverExW.
6569 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6571 DRIVER_INFO_8A *diA;
6572 DRIVER_INFO_8W diW;
6573 LPWSTR nameW = NULL;
6574 DWORD lenA;
6575 DWORD len;
6576 DWORD res = FALSE;
6578 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6580 diA = (DRIVER_INFO_8A *) pDriverInfo;
6581 ZeroMemory(&diW, sizeof(diW));
6583 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6584 SetLastError(ERROR_INVALID_LEVEL);
6585 return FALSE;
6588 if (diA == NULL) {
6589 SetLastError(ERROR_INVALID_PARAMETER);
6590 return FALSE;
6593 /* convert servername to unicode */
6594 if (pName) {
6595 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6596 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6597 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6600 /* common fields */
6601 diW.cVersion = diA->cVersion;
6603 if (diA->pName) {
6604 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6605 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6606 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6609 if (diA->pEnvironment) {
6610 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6611 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6612 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6615 if (diA->pDriverPath) {
6616 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6617 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6618 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6621 if (diA->pDataFile) {
6622 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6623 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6624 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6627 if (diA->pConfigFile) {
6628 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6629 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6630 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6633 if ((Level > 2) && diA->pDependentFiles) {
6634 lenA = multi_sz_lenA(diA->pDependentFiles);
6635 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6636 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6637 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6640 if ((Level > 2) && diA->pMonitorName) {
6641 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6642 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6643 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6646 if ((Level > 3) && diA->pDefaultDataType) {
6647 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6648 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6649 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6652 if ((Level > 3) && diA->pszzPreviousNames) {
6653 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6654 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6655 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6656 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6659 if ((Level > 5) && diA->pszMfgName) {
6660 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6661 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6662 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6665 if ((Level > 5) && diA->pszOEMUrl) {
6666 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6667 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6668 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6671 if ((Level > 5) && diA->pszHardwareID) {
6672 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6673 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6674 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6677 if ((Level > 5) && diA->pszProvider) {
6678 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6679 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6680 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6683 if (Level > 7) {
6684 FIXME("level %u is incomplete\n", Level);
6687 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6688 TRACE("got %u with %u\n", res, GetLastError());
6689 HeapFree(GetProcessHeap(), 0, nameW);
6690 HeapFree(GetProcessHeap(), 0, diW.pName);
6691 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6692 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6693 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6694 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6695 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6696 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6697 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6698 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6699 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6700 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6701 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6702 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6704 TRACE("=> %u with %u\n", res, GetLastError());
6705 return res;
6708 /******************************************************************************
6709 * ConfigurePortA (WINSPOOL.@)
6711 * See ConfigurePortW.
6714 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6716 LPWSTR nameW = NULL;
6717 LPWSTR portW = NULL;
6718 INT len;
6719 DWORD res;
6721 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6723 /* convert servername to unicode */
6724 if (pName) {
6725 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6726 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6727 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6730 /* convert portname to unicode */
6731 if (pPortName) {
6732 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6733 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6734 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6737 res = ConfigurePortW(nameW, hWnd, portW);
6738 HeapFree(GetProcessHeap(), 0, nameW);
6739 HeapFree(GetProcessHeap(), 0, portW);
6740 return res;
6743 /******************************************************************************
6744 * ConfigurePortW (WINSPOOL.@)
6746 * Display the Configuration-Dialog for a specific Port
6748 * PARAMS
6749 * pName [I] Servername or NULL (local Computer)
6750 * hWnd [I] Handle to parent Window for the Dialog-Box
6751 * pPortName [I] Name of the Port, that should be configured
6753 * RETURNS
6754 * Success: TRUE
6755 * Failure: FALSE
6758 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6760 monitor_t * pm;
6761 monitor_t * pui;
6762 DWORD res;
6764 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6766 if (pName && pName[0]) {
6767 SetLastError(ERROR_INVALID_PARAMETER);
6768 return FALSE;
6771 if (!pPortName) {
6772 SetLastError(RPC_X_NULL_REF_POINTER);
6773 return FALSE;
6776 /* an empty Portname is Invalid, but can popup a Dialog */
6777 if (!pPortName[0]) {
6778 SetLastError(ERROR_NOT_SUPPORTED);
6779 return FALSE;
6782 pm = monitor_load_by_port(pPortName);
6783 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6784 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6785 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6786 TRACE("got %d with %u\n", res, GetLastError());
6788 else
6790 pui = monitor_loadui(pm);
6791 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6792 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6793 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6794 TRACE("got %d with %u\n", res, GetLastError());
6796 else
6798 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6799 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6801 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6802 SetLastError(ERROR_NOT_SUPPORTED);
6803 res = FALSE;
6805 monitor_unload(pui);
6807 monitor_unload(pm);
6809 TRACE("returning %d with %u\n", res, GetLastError());
6810 return res;
6813 /******************************************************************************
6814 * ConnectToPrinterDlg (WINSPOOL.@)
6816 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6818 FIXME("%p %x\n", hWnd, Flags);
6819 return NULL;
6822 /******************************************************************************
6823 * DeletePrinterConnectionA (WINSPOOL.@)
6825 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6827 FIXME("%s\n", debugstr_a(pName));
6828 return TRUE;
6831 /******************************************************************************
6832 * DeletePrinterConnectionW (WINSPOOL.@)
6834 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6836 FIXME("%s\n", debugstr_w(pName));
6837 return TRUE;
6840 /******************************************************************************
6841 * DeletePrinterDriverExW (WINSPOOL.@)
6843 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6844 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6846 HKEY hkey_drivers;
6847 BOOL ret = FALSE;
6849 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6850 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6852 if(pName && pName[0])
6854 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6855 SetLastError(ERROR_INVALID_PARAMETER);
6856 return FALSE;
6859 if(dwDeleteFlag)
6861 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6862 SetLastError(ERROR_INVALID_PARAMETER);
6863 return FALSE;
6866 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6868 if(!hkey_drivers)
6870 ERR("Can't open drivers key\n");
6871 return FALSE;
6874 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6875 ret = TRUE;
6877 RegCloseKey(hkey_drivers);
6879 return ret;
6882 /******************************************************************************
6883 * DeletePrinterDriverExA (WINSPOOL.@)
6885 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6886 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6888 UNICODE_STRING NameW, EnvW, DriverW;
6889 BOOL ret;
6891 asciitounicode(&NameW, pName);
6892 asciitounicode(&EnvW, pEnvironment);
6893 asciitounicode(&DriverW, pDriverName);
6895 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6897 RtlFreeUnicodeString(&DriverW);
6898 RtlFreeUnicodeString(&EnvW);
6899 RtlFreeUnicodeString(&NameW);
6901 return ret;
6904 /******************************************************************************
6905 * DeletePrinterDataExW (WINSPOOL.@)
6907 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6908 LPCWSTR pValueName)
6910 FIXME("%p %s %s\n", hPrinter,
6911 debugstr_w(pKeyName), debugstr_w(pValueName));
6912 return ERROR_INVALID_PARAMETER;
6915 /******************************************************************************
6916 * DeletePrinterDataExA (WINSPOOL.@)
6918 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6919 LPCSTR pValueName)
6921 FIXME("%p %s %s\n", hPrinter,
6922 debugstr_a(pKeyName), debugstr_a(pValueName));
6923 return ERROR_INVALID_PARAMETER;
6926 /******************************************************************************
6927 * DeletePrintProcessorA (WINSPOOL.@)
6929 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6931 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6932 debugstr_a(pPrintProcessorName));
6933 return TRUE;
6936 /******************************************************************************
6937 * DeletePrintProcessorW (WINSPOOL.@)
6939 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6941 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6942 debugstr_w(pPrintProcessorName));
6943 return TRUE;
6946 /******************************************************************************
6947 * DeletePrintProvidorA (WINSPOOL.@)
6949 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6951 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6952 debugstr_a(pPrintProviderName));
6953 return TRUE;
6956 /******************************************************************************
6957 * DeletePrintProvidorW (WINSPOOL.@)
6959 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6961 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6962 debugstr_w(pPrintProviderName));
6963 return TRUE;
6966 /******************************************************************************
6967 * EnumFormsA (WINSPOOL.@)
6969 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6970 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6972 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6973 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6974 return FALSE;
6977 /******************************************************************************
6978 * EnumFormsW (WINSPOOL.@)
6980 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6981 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6983 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6984 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6985 return FALSE;
6988 /*****************************************************************************
6989 * EnumMonitorsA [WINSPOOL.@]
6991 * See EnumMonitorsW.
6994 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6995 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6997 BOOL res;
6998 LPBYTE bufferW = NULL;
6999 LPWSTR nameW = NULL;
7000 DWORD needed = 0;
7001 DWORD numentries = 0;
7002 INT len;
7004 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7005 cbBuf, pcbNeeded, pcReturned);
7007 /* convert servername to unicode */
7008 if (pName) {
7009 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7010 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7011 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7013 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7014 needed = cbBuf * sizeof(WCHAR);
7015 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7016 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7018 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7019 if (pcbNeeded) needed = *pcbNeeded;
7020 /* HeapReAlloc return NULL, when bufferW was NULL */
7021 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7022 HeapAlloc(GetProcessHeap(), 0, needed);
7024 /* Try again with the large Buffer */
7025 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7027 numentries = pcReturned ? *pcReturned : 0;
7028 needed = 0;
7030 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7031 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7033 if (res) {
7034 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7035 DWORD entrysize = 0;
7036 DWORD index;
7037 LPSTR ptr;
7038 LPMONITOR_INFO_2W mi2w;
7039 LPMONITOR_INFO_2A mi2a;
7041 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7042 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7044 /* First pass: calculate the size for all Entries */
7045 mi2w = (LPMONITOR_INFO_2W) bufferW;
7046 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7047 index = 0;
7048 while (index < numentries) {
7049 index++;
7050 needed += entrysize; /* MONITOR_INFO_?A */
7051 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7053 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7054 NULL, 0, NULL, NULL);
7055 if (Level > 1) {
7056 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7057 NULL, 0, NULL, NULL);
7058 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7059 NULL, 0, NULL, NULL);
7061 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7062 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7063 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7066 /* check for errors and quit on failure */
7067 if (cbBuf < needed) {
7068 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7069 res = FALSE;
7070 goto emA_cleanup;
7072 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7073 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7074 cbBuf -= len ; /* free Bytes in the user-Buffer */
7075 mi2w = (LPMONITOR_INFO_2W) bufferW;
7076 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7077 index = 0;
7078 /* Second Pass: Fill the User Buffer (if we have one) */
7079 while ((index < numentries) && pMonitors) {
7080 index++;
7081 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7082 mi2a->pName = ptr;
7083 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7084 ptr, cbBuf , NULL, NULL);
7085 ptr += len;
7086 cbBuf -= len;
7087 if (Level > 1) {
7088 mi2a->pEnvironment = ptr;
7089 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7090 ptr, cbBuf, NULL, NULL);
7091 ptr += len;
7092 cbBuf -= len;
7094 mi2a->pDLLName = ptr;
7095 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7096 ptr, cbBuf, NULL, NULL);
7097 ptr += len;
7098 cbBuf -= len;
7100 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7101 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7102 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7105 emA_cleanup:
7106 if (pcbNeeded) *pcbNeeded = needed;
7107 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7109 HeapFree(GetProcessHeap(), 0, nameW);
7110 HeapFree(GetProcessHeap(), 0, bufferW);
7112 TRACE("returning %d with %d (%d byte for %d entries)\n",
7113 (res), GetLastError(), needed, numentries);
7115 return (res);
7119 /*****************************************************************************
7120 * EnumMonitorsW [WINSPOOL.@]
7122 * Enumerate available Port-Monitors
7124 * PARAMS
7125 * pName [I] Servername or NULL (local Computer)
7126 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7127 * pMonitors [O] PTR to Buffer that receives the Result
7128 * cbBuf [I] Size of Buffer at pMonitors
7129 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7130 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7132 * RETURNS
7133 * Success: TRUE
7134 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7137 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7138 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7141 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7142 cbBuf, pcbNeeded, pcReturned);
7144 if ((backend == NULL) && !load_backend()) return FALSE;
7146 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7147 SetLastError(RPC_X_NULL_REF_POINTER);
7148 return FALSE;
7151 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7154 /******************************************************************************
7155 * SpoolerInit (WINSPOOL.@)
7157 * Initialize the Spooler
7159 * RETURNS
7160 * Success: TRUE
7161 * Failure: FALSE
7163 * NOTES
7164 * The function fails on windows, when the spooler service is not running
7167 BOOL WINAPI SpoolerInit(void)
7170 if ((backend == NULL) && !load_backend()) return FALSE;
7171 return TRUE;
7174 /******************************************************************************
7175 * XcvDataW (WINSPOOL.@)
7177 * Execute commands in the Printmonitor DLL
7179 * PARAMS
7180 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7181 * pszDataName [i] Name of the command to execute
7182 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7183 * cbInputData [i] Size in Bytes of Buffer at pInputData
7184 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7185 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7186 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7187 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7189 * RETURNS
7190 * Success: TRUE
7191 * Failure: FALSE
7193 * NOTES
7194 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7195 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7197 * Minimal List of commands, that a Printmonitor DLL should support:
7199 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7200 *| "AddPort" : Add a Port
7201 *| "DeletePort": Delete a Port
7203 * Many Printmonitors support additional commands. Examples for localspl.dll:
7204 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7205 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7208 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7209 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7210 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7212 opened_printer_t *printer;
7214 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7215 pInputData, cbInputData, pOutputData,
7216 cbOutputData, pcbOutputNeeded, pdwStatus);
7218 printer = get_opened_printer(hXcv);
7219 if (!printer || (!printer->hXcv)) {
7220 SetLastError(ERROR_INVALID_HANDLE);
7221 return FALSE;
7224 if (!pcbOutputNeeded) {
7225 SetLastError(ERROR_INVALID_PARAMETER);
7226 return FALSE;
7229 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7230 SetLastError(RPC_X_NULL_REF_POINTER);
7231 return FALSE;
7234 *pcbOutputNeeded = 0;
7236 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7237 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7239 return TRUE;
7242 /*****************************************************************************
7243 * EnumPrinterDataA [WINSPOOL.@]
7246 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7247 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7248 DWORD cbData, LPDWORD pcbData )
7250 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7251 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7252 return ERROR_NO_MORE_ITEMS;
7255 /*****************************************************************************
7256 * EnumPrinterDataW [WINSPOOL.@]
7259 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7260 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7261 DWORD cbData, LPDWORD pcbData )
7263 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7264 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7265 return ERROR_NO_MORE_ITEMS;
7268 /*****************************************************************************
7269 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7272 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7273 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7274 LPDWORD pcbNeeded, LPDWORD pcReturned)
7276 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7277 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7278 pcbNeeded, pcReturned);
7279 return FALSE;
7282 /*****************************************************************************
7283 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7286 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7287 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7288 LPDWORD pcbNeeded, LPDWORD pcReturned)
7290 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7291 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7292 pcbNeeded, pcReturned);
7293 return FALSE;
7296 /*****************************************************************************
7297 * EnumPrintProcessorsA [WINSPOOL.@]
7300 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7301 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7303 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7304 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7305 return FALSE;
7308 /*****************************************************************************
7309 * EnumPrintProcessorsW [WINSPOOL.@]
7312 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7313 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7315 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7316 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7317 cbBuf, pcbNeeded, pcbReturned);
7318 return FALSE;
7321 /*****************************************************************************
7322 * ExtDeviceMode [WINSPOOL.@]
7325 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7326 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7327 DWORD fMode)
7329 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7330 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7331 debugstr_a(pProfile), fMode);
7332 return -1;
7335 /*****************************************************************************
7336 * FindClosePrinterChangeNotification [WINSPOOL.@]
7339 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7341 FIXME("Stub: %p\n", hChange);
7342 return TRUE;
7345 /*****************************************************************************
7346 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7349 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7350 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7352 FIXME("Stub: %p %x %x %p\n",
7353 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7354 return INVALID_HANDLE_VALUE;
7357 /*****************************************************************************
7358 * FindNextPrinterChangeNotification [WINSPOOL.@]
7361 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7362 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7364 FIXME("Stub: %p %p %p %p\n",
7365 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7366 return FALSE;
7369 /*****************************************************************************
7370 * FreePrinterNotifyInfo [WINSPOOL.@]
7373 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7375 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7376 return TRUE;
7379 /*****************************************************************************
7380 * string_to_buf
7382 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7383 * ansi depending on the unicode parameter.
7385 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7387 if(!str)
7389 *size = 0;
7390 return TRUE;
7393 if(unicode)
7395 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7396 if(*size <= cb)
7398 memcpy(ptr, str, *size);
7399 return TRUE;
7401 return FALSE;
7403 else
7405 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7406 if(*size <= cb)
7408 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7409 return TRUE;
7411 return FALSE;
7415 /*****************************************************************************
7416 * get_job_info_1
7418 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7419 LPDWORD pcbNeeded, BOOL unicode)
7421 DWORD size, left = cbBuf;
7422 BOOL space = (cbBuf > 0);
7423 LPBYTE ptr = buf;
7425 *pcbNeeded = 0;
7427 if(space)
7429 ji1->JobId = job->job_id;
7432 string_to_buf(job->document_title, ptr, left, &size, unicode);
7433 if(space && size <= left)
7435 ji1->pDocument = (LPWSTR)ptr;
7436 ptr += size;
7437 left -= size;
7439 else
7440 space = FALSE;
7441 *pcbNeeded += size;
7443 return space;
7446 /*****************************************************************************
7447 * get_job_info_2
7449 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7450 LPDWORD pcbNeeded, BOOL unicode)
7452 DWORD size, left = cbBuf;
7453 BOOL space = (cbBuf > 0);
7454 LPBYTE ptr = buf;
7456 *pcbNeeded = 0;
7458 if(space)
7460 ji2->JobId = job->job_id;
7463 string_to_buf(job->document_title, ptr, left, &size, unicode);
7464 if(space && size <= left)
7466 ji2->pDocument = (LPWSTR)ptr;
7467 ptr += size;
7468 left -= size;
7470 else
7471 space = FALSE;
7472 *pcbNeeded += size;
7474 return space;
7477 /*****************************************************************************
7478 * get_job_info
7480 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7481 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7483 BOOL ret = FALSE;
7484 DWORD needed = 0, size;
7485 job_t *job;
7486 LPBYTE ptr = pJob;
7488 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7490 EnterCriticalSection(&printer_handles_cs);
7491 job = get_job(hPrinter, JobId);
7492 if(!job)
7493 goto end;
7495 switch(Level)
7497 case 1:
7498 size = sizeof(JOB_INFO_1W);
7499 if(cbBuf >= size)
7501 cbBuf -= size;
7502 ptr += size;
7503 memset(pJob, 0, size);
7505 else
7506 cbBuf = 0;
7507 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7508 needed += size;
7509 break;
7511 case 2:
7512 size = sizeof(JOB_INFO_2W);
7513 if(cbBuf >= size)
7515 cbBuf -= size;
7516 ptr += size;
7517 memset(pJob, 0, size);
7519 else
7520 cbBuf = 0;
7521 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7522 needed += size;
7523 break;
7525 case 3:
7526 size = sizeof(JOB_INFO_3);
7527 if(cbBuf >= size)
7529 cbBuf -= size;
7530 memset(pJob, 0, size);
7531 ret = TRUE;
7533 else
7534 cbBuf = 0;
7535 needed = size;
7536 break;
7538 default:
7539 SetLastError(ERROR_INVALID_LEVEL);
7540 goto end;
7542 if(pcbNeeded)
7543 *pcbNeeded = needed;
7544 end:
7545 LeaveCriticalSection(&printer_handles_cs);
7546 return ret;
7549 /*****************************************************************************
7550 * GetJobA [WINSPOOL.@]
7553 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7554 DWORD cbBuf, LPDWORD pcbNeeded)
7556 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7559 /*****************************************************************************
7560 * GetJobW [WINSPOOL.@]
7563 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7564 DWORD cbBuf, LPDWORD pcbNeeded)
7566 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7569 /*****************************************************************************
7570 * schedule_lpr
7572 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7574 char *unixname, *queue, *cmd;
7575 char fmt[] = "lpr -P%s %s";
7576 DWORD len;
7578 if(!(unixname = wine_get_unix_file_name(filename)))
7579 return FALSE;
7581 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7582 queue = HeapAlloc(GetProcessHeap(), 0, len);
7583 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7585 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7586 sprintf(cmd, fmt, queue, unixname);
7588 TRACE("printing with: %s\n", cmd);
7589 system(cmd);
7591 HeapFree(GetProcessHeap(), 0, cmd);
7592 HeapFree(GetProcessHeap(), 0, queue);
7593 HeapFree(GetProcessHeap(), 0, unixname);
7594 return TRUE;
7597 /*****************************************************************************
7598 * schedule_cups
7600 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7602 #ifdef SONAME_LIBCUPS
7603 if(pcupsPrintFile)
7605 char *unixname, *queue, *doc_titleA;
7606 DWORD len;
7607 BOOL ret;
7609 if(!(unixname = wine_get_unix_file_name(filename)))
7610 return FALSE;
7612 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7613 queue = HeapAlloc(GetProcessHeap(), 0, len);
7614 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7616 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7617 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7618 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7620 TRACE("printing via cups\n");
7621 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7622 HeapFree(GetProcessHeap(), 0, doc_titleA);
7623 HeapFree(GetProcessHeap(), 0, queue);
7624 HeapFree(GetProcessHeap(), 0, unixname);
7625 return ret;
7627 else
7628 #endif
7630 return schedule_lpr(printer_name, filename);
7634 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7636 LPWSTR filename;
7638 switch(msg)
7640 case WM_INITDIALOG:
7641 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7642 return TRUE;
7644 case WM_COMMAND:
7645 if(HIWORD(wparam) == BN_CLICKED)
7647 if(LOWORD(wparam) == IDOK)
7649 HANDLE hf;
7650 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7651 LPWSTR *output;
7653 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7654 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7656 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7658 WCHAR caption[200], message[200];
7659 int mb_ret;
7661 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7662 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7663 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7664 if(mb_ret == IDCANCEL)
7666 HeapFree(GetProcessHeap(), 0, filename);
7667 return TRUE;
7670 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7671 if(hf == INVALID_HANDLE_VALUE)
7673 WCHAR caption[200], message[200];
7675 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7676 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7677 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7678 HeapFree(GetProcessHeap(), 0, filename);
7679 return TRUE;
7681 CloseHandle(hf);
7682 DeleteFileW(filename);
7683 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7684 *output = filename;
7685 EndDialog(hwnd, IDOK);
7686 return TRUE;
7688 if(LOWORD(wparam) == IDCANCEL)
7690 EndDialog(hwnd, IDCANCEL);
7691 return TRUE;
7694 return FALSE;
7696 return FALSE;
7699 /*****************************************************************************
7700 * get_filename
7702 static BOOL get_filename(LPWSTR *filename)
7704 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7705 file_dlg_proc, (LPARAM)filename) == IDOK;
7708 /*****************************************************************************
7709 * schedule_file
7711 static BOOL schedule_file(LPCWSTR filename)
7713 LPWSTR output = NULL;
7715 if(get_filename(&output))
7717 TRACE("copy to %s\n", debugstr_w(output));
7718 CopyFileW(filename, output, FALSE);
7719 HeapFree(GetProcessHeap(), 0, output);
7720 return TRUE;
7722 return FALSE;
7725 /*****************************************************************************
7726 * schedule_pipe
7728 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7730 #ifdef HAVE_FORK
7731 char *unixname, *cmdA;
7732 DWORD len;
7733 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7734 BOOL ret = FALSE;
7735 char buf[1024];
7737 if(!(unixname = wine_get_unix_file_name(filename)))
7738 return FALSE;
7740 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7741 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7742 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7744 TRACE("printing with: %s\n", cmdA);
7746 if((file_fd = open(unixname, O_RDONLY)) == -1)
7747 goto end;
7749 if (pipe(fds))
7751 ERR("pipe() failed!\n");
7752 goto end;
7755 if (fork() == 0)
7757 close(0);
7758 dup2(fds[0], 0);
7759 close(fds[1]);
7761 /* reset signals that we previously set to SIG_IGN */
7762 signal(SIGPIPE, SIG_DFL);
7763 signal(SIGCHLD, SIG_DFL);
7765 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7766 _exit(1);
7769 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7770 write(fds[1], buf, no_read);
7772 ret = TRUE;
7774 end:
7775 if(file_fd != -1) close(file_fd);
7776 if(fds[0] != -1) close(fds[0]);
7777 if(fds[1] != -1) close(fds[1]);
7779 HeapFree(GetProcessHeap(), 0, cmdA);
7780 HeapFree(GetProcessHeap(), 0, unixname);
7781 return ret;
7782 #else
7783 return FALSE;
7784 #endif
7787 /*****************************************************************************
7788 * schedule_unixfile
7790 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7792 int in_fd, out_fd, no_read;
7793 char buf[1024];
7794 BOOL ret = FALSE;
7795 char *unixname, *outputA;
7796 DWORD len;
7798 if(!(unixname = wine_get_unix_file_name(filename)))
7799 return FALSE;
7801 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7802 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7803 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7805 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7806 in_fd = open(unixname, O_RDONLY);
7807 if(out_fd == -1 || in_fd == -1)
7808 goto end;
7810 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7811 write(out_fd, buf, no_read);
7813 ret = TRUE;
7814 end:
7815 if(in_fd != -1) close(in_fd);
7816 if(out_fd != -1) close(out_fd);
7817 HeapFree(GetProcessHeap(), 0, outputA);
7818 HeapFree(GetProcessHeap(), 0, unixname);
7819 return ret;
7822 /*****************************************************************************
7823 * ScheduleJob [WINSPOOL.@]
7826 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7828 opened_printer_t *printer;
7829 BOOL ret = FALSE;
7830 struct list *cursor, *cursor2;
7832 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7833 EnterCriticalSection(&printer_handles_cs);
7834 printer = get_opened_printer(hPrinter);
7835 if(!printer)
7836 goto end;
7838 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7840 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7841 HANDLE hf;
7843 if(job->job_id != dwJobID) continue;
7845 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7846 if(hf != INVALID_HANDLE_VALUE)
7848 PRINTER_INFO_5W *pi5;
7849 DWORD needed;
7850 HKEY hkey;
7851 WCHAR output[1024];
7852 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7853 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7855 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7856 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7857 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7858 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7859 debugstr_w(pi5->pPortName));
7861 output[0] = 0;
7863 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7864 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7866 DWORD type, count = sizeof(output);
7867 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7868 RegCloseKey(hkey);
7870 if(output[0] == '|')
7872 schedule_pipe(output + 1, job->filename);
7874 else if(output[0])
7876 schedule_unixfile(output, job->filename);
7878 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7880 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7882 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7884 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7886 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7888 schedule_file(job->filename);
7890 else
7892 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7894 HeapFree(GetProcessHeap(), 0, pi5);
7895 CloseHandle(hf);
7896 DeleteFileW(job->filename);
7898 list_remove(cursor);
7899 HeapFree(GetProcessHeap(), 0, job->document_title);
7900 HeapFree(GetProcessHeap(), 0, job->filename);
7901 HeapFree(GetProcessHeap(), 0, job);
7902 ret = TRUE;
7903 break;
7905 end:
7906 LeaveCriticalSection(&printer_handles_cs);
7907 return ret;
7910 /*****************************************************************************
7911 * StartDocDlgA [WINSPOOL.@]
7913 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7915 UNICODE_STRING usBuffer;
7916 DOCINFOW docW;
7917 LPWSTR retW;
7918 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7919 LPSTR ret = NULL;
7921 docW.cbSize = sizeof(docW);
7922 if (doc->lpszDocName)
7924 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7925 if (!(docW.lpszDocName = docnameW)) return NULL;
7927 if (doc->lpszOutput)
7929 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7930 if (!(docW.lpszOutput = outputW)) return NULL;
7932 if (doc->lpszDatatype)
7934 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7935 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7937 docW.fwType = doc->fwType;
7939 retW = StartDocDlgW(hPrinter, &docW);
7941 if(retW)
7943 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7944 ret = HeapAlloc(GetProcessHeap(), 0, len);
7945 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7946 HeapFree(GetProcessHeap(), 0, retW);
7949 HeapFree(GetProcessHeap(), 0, datatypeW);
7950 HeapFree(GetProcessHeap(), 0, outputW);
7951 HeapFree(GetProcessHeap(), 0, docnameW);
7953 return ret;
7956 /*****************************************************************************
7957 * StartDocDlgW [WINSPOOL.@]
7959 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7960 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7961 * port is "FILE:". Also returns the full path if passed a relative path.
7963 * The caller should free the returned string from the process heap.
7965 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7967 LPWSTR ret = NULL;
7968 DWORD len, attr;
7970 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7972 PRINTER_INFO_5W *pi5;
7973 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7974 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7975 return NULL;
7976 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7977 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7978 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7980 HeapFree(GetProcessHeap(), 0, pi5);
7981 return NULL;
7983 HeapFree(GetProcessHeap(), 0, pi5);
7986 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7988 LPWSTR name;
7990 if (get_filename(&name))
7992 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7994 HeapFree(GetProcessHeap(), 0, name);
7995 return NULL;
7997 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7998 GetFullPathNameW(name, len, ret, NULL);
7999 HeapFree(GetProcessHeap(), 0, name);
8001 return ret;
8004 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8005 return NULL;
8007 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8008 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8010 attr = GetFileAttributesW(ret);
8011 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8013 HeapFree(GetProcessHeap(), 0, ret);
8014 ret = NULL;
8016 return ret;