push 585d938e6dafa7e4b71343fb5b928a9214e5518c
[wine/hacks.git] / dlls / winspool.drv / info.c
blobb7b290f3b9051b7b34f451d4f6393add8dd0135f
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 add_printer_driver(dests[i].name);
528 } else {
529 static CHAR data_type[] = "RAW",
530 print_proc[] = "WinPrint",
531 comment[] = "WINEPS Printer using CUPS",
532 location[] = "<physical location of printer>",
533 params[] = "<parameters?>",
534 share_name[] = "<share name?>",
535 sep_file[] = "<sep file?>";
537 add_printer_driver(dests[i].name);
539 memset(&pinfo2a,0,sizeof(pinfo2a));
540 pinfo2a.pPrinterName = dests[i].name;
541 pinfo2a.pDatatype = data_type;
542 pinfo2a.pPrintProcessor = print_proc;
543 pinfo2a.pDriverName = dests[i].name;
544 pinfo2a.pComment = comment;
545 pinfo2a.pLocation = location;
546 pinfo2a.pPortName = port;
547 pinfo2a.pParameters = params;
548 pinfo2a.pShareName = share_name;
549 pinfo2a.pSepFile = sep_file;
551 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
552 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
553 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
556 HeapFree(GetProcessHeap(),0,port);
558 hadprinter = TRUE;
559 if (dests[i].is_default) {
560 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
561 haddefault = TRUE;
564 if (hadprinter & !haddefault)
565 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
566 RegCloseKey(hkeyPrinters);
567 return hadprinter;
569 #endif
571 static BOOL
572 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
573 PRINTER_INFO_2A pinfo2a;
574 char *e,*s,*name,*prettyname,*devname;
575 BOOL ret = FALSE, set_default = FALSE;
576 char *port = NULL, *devline,*env_default;
577 HKEY hkeyPrinter, hkeyPrinters, hkey;
579 while (isspace(*pent)) pent++;
580 s = strchr(pent,':');
581 if(s) *s='\0';
582 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
583 strcpy(name,pent);
584 if(s) {
585 *s=':';
586 pent = s;
587 } else
588 pent = "";
590 TRACE("name=%s entry=%s\n",name, pent);
592 if(ispunct(*name)) { /* a tc entry, not a real printer */
593 TRACE("skipping tc entry\n");
594 goto end;
597 if(strstr(pent,":server")) { /* server only version so skip */
598 TRACE("skipping server entry\n");
599 goto end;
602 /* Determine whether this is a postscript printer. */
604 ret = TRUE;
605 env_default = getenv("PRINTER");
606 prettyname = name;
607 /* Get longest name, usually the one at the right for later display. */
608 while((s=strchr(prettyname,'|'))) {
609 *s = '\0';
610 e = s;
611 while(isspace(*--e)) *e = '\0';
612 TRACE("\t%s\n", debugstr_a(prettyname));
613 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
614 for(prettyname = s+1; isspace(*prettyname); prettyname++)
617 e = prettyname + strlen(prettyname);
618 while(isspace(*--e)) *e = '\0';
619 TRACE("\t%s\n", debugstr_a(prettyname));
620 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
622 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
623 * if it is too long, we use it as comment below. */
624 devname = prettyname;
625 if (strlen(devname)>=CCHDEVICENAME-1)
626 devname = name;
627 if (strlen(devname)>=CCHDEVICENAME-1) {
628 ret = FALSE;
629 goto end;
632 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
633 sprintf(port,"LPR:%s",name);
635 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
636 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
637 sprintf(devline, "WINEPS.DRV,%s", port);
638 WriteProfileStringA("devices", devname, devline);
639 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
640 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
641 RegCloseKey(hkey);
644 lstrcatA(devline, ",15,45");
645 WriteProfileStringA("PrinterPorts", devname, devline);
646 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
647 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
648 RegCloseKey(hkey);
651 HeapFree(GetProcessHeap(),0,devline);
653 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
654 ERROR_SUCCESS) {
655 ERR("Can't create Printers key\n");
656 ret = FALSE;
657 goto end;
659 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
660 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
661 and continue */
662 TRACE("Printer already exists\n");
663 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
664 RegCloseKey(hkeyPrinter);
665 add_printer_driver(devname);
666 } else {
667 static CHAR data_type[] = "RAW",
668 print_proc[] = "WinPrint",
669 comment[] = "WINEPS Printer using LPR",
670 params[] = "<parameters?>",
671 share_name[] = "<share name?>",
672 sep_file[] = "<sep file?>";
674 add_printer_driver(devname);
676 memset(&pinfo2a,0,sizeof(pinfo2a));
677 pinfo2a.pPrinterName = devname;
678 pinfo2a.pDatatype = data_type;
679 pinfo2a.pPrintProcessor = print_proc;
680 pinfo2a.pDriverName = devname;
681 pinfo2a.pComment = comment;
682 pinfo2a.pLocation = prettyname;
683 pinfo2a.pPortName = port;
684 pinfo2a.pParameters = params;
685 pinfo2a.pShareName = share_name;
686 pinfo2a.pSepFile = sep_file;
688 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
689 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
690 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
693 RegCloseKey(hkeyPrinters);
695 if (isfirst || set_default)
696 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
698 end:
699 HeapFree(GetProcessHeap(), 0, port);
700 HeapFree(GetProcessHeap(), 0, name);
701 return ret;
704 static BOOL
705 PRINTCAP_LoadPrinters(void) {
706 BOOL hadprinter = FALSE;
707 char buf[200];
708 FILE *f;
709 char *pent = NULL;
710 BOOL had_bash = FALSE;
712 f = fopen("/etc/printcap","r");
713 if (!f)
714 return FALSE;
716 while(fgets(buf,sizeof(buf),f)) {
717 char *start, *end;
719 end=strchr(buf,'\n');
720 if (end) *end='\0';
722 start = buf;
723 while(isspace(*start)) start++;
724 if(*start == '#' || *start == '\0')
725 continue;
727 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
728 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
729 HeapFree(GetProcessHeap(),0,pent);
730 pent = NULL;
733 if (end && *--end == '\\') {
734 *end = '\0';
735 had_bash = TRUE;
736 } else
737 had_bash = FALSE;
739 if (pent) {
740 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
741 strcat(pent,start);
742 } else {
743 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
744 strcpy(pent,start);
748 if(pent) {
749 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
750 HeapFree(GetProcessHeap(),0,pent);
752 fclose(f);
753 return hadprinter;
756 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
758 if (value)
759 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
760 (lstrlenW(value) + 1) * sizeof(WCHAR));
761 else
762 return ERROR_FILE_NOT_FOUND;
765 /******************************************************************
766 * monitor_unload [internal]
768 * release a printmonitor and unload it from memory, when needed
771 static void monitor_unload(monitor_t * pm)
773 if (pm == NULL) return;
774 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
776 EnterCriticalSection(&monitor_handles_cs);
778 if (pm->refcount) pm->refcount--;
780 if (pm->refcount == 0) {
781 list_remove(&pm->entry);
782 FreeLibrary(pm->hdll);
783 HeapFree(GetProcessHeap(), 0, pm->name);
784 HeapFree(GetProcessHeap(), 0, pm->dllname);
785 HeapFree(GetProcessHeap(), 0, pm);
787 LeaveCriticalSection(&monitor_handles_cs);
790 /******************************************************************
791 * monitor_unloadall [internal]
793 * release all printmonitors and unload them from memory, when needed
796 static void monitor_unloadall(void)
798 monitor_t * pm;
799 monitor_t * next;
801 EnterCriticalSection(&monitor_handles_cs);
802 /* iterate through the list, with safety against removal */
803 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
805 monitor_unload(pm);
807 LeaveCriticalSection(&monitor_handles_cs);
810 /******************************************************************
811 * monitor_load [internal]
813 * load a printmonitor, get the dllname from the registry, when needed
814 * initialize the monitor and dump found function-pointers
816 * On failure, SetLastError() is called and NULL is returned
819 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
821 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
822 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
823 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
824 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
825 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
827 monitor_t * pm = NULL;
828 monitor_t * cursor;
829 LPWSTR regroot = NULL;
830 LPWSTR driver = dllname;
832 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
833 /* Is the Monitor already loaded? */
834 EnterCriticalSection(&monitor_handles_cs);
836 if (name) {
837 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
839 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
840 pm = cursor;
841 break;
846 if (pm == NULL) {
847 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
848 if (pm == NULL) goto cleanup;
849 list_add_tail(&monitor_handles, &pm->entry);
851 pm->refcount++;
853 if (pm->name == NULL) {
854 /* Load the monitor */
855 LPMONITOREX pmonitorEx;
856 DWORD len;
858 if (name) {
859 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
860 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
863 if (regroot) {
864 lstrcpyW(regroot, MonitorsW);
865 lstrcatW(regroot, name);
866 /* Get the Driver from the Registry */
867 if (driver == NULL) {
868 HKEY hroot;
869 DWORD namesize;
870 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
871 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
872 &namesize) == ERROR_SUCCESS) {
873 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
874 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
876 RegCloseKey(hroot);
881 pm->name = strdupW(name);
882 pm->dllname = strdupW(driver);
884 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
885 monitor_unload(pm);
886 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
887 pm = NULL;
888 goto cleanup;
891 pm->hdll = LoadLibraryW(driver);
892 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
894 if (pm->hdll == NULL) {
895 monitor_unload(pm);
896 SetLastError(ERROR_MOD_NOT_FOUND);
897 pm = NULL;
898 goto cleanup;
901 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
902 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
903 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
904 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
905 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
908 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
909 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
910 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
911 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
912 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
914 if (pInitializePrintMonitorUI != NULL) {
915 pm->monitorUI = pInitializePrintMonitorUI();
916 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
917 if (pm->monitorUI) {
918 TRACE( "0x%08x: dwMonitorSize (%d)\n",
919 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
924 if (pInitializePrintMonitor && regroot) {
925 pmonitorEx = pInitializePrintMonitor(regroot);
926 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
927 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
929 if (pmonitorEx) {
930 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
931 pm->monitor = &(pmonitorEx->Monitor);
935 if (pm->monitor) {
936 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
940 if (!pm->monitor && regroot) {
941 if (pInitializePrintMonitor2 != NULL) {
942 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
944 if (pInitializeMonitorEx != NULL) {
945 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
947 if (pInitializeMonitor != NULL) {
948 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
951 if (!pm->monitor && !pm->monitorUI) {
952 monitor_unload(pm);
953 SetLastError(ERROR_PROC_NOT_FOUND);
954 pm = NULL;
957 cleanup:
958 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
959 pm->refcount++;
960 pm_localport = pm;
962 LeaveCriticalSection(&monitor_handles_cs);
963 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
964 HeapFree(GetProcessHeap(), 0, regroot);
965 TRACE("=> %p\n", pm);
966 return pm;
969 /******************************************************************
970 * monitor_loadall [internal]
972 * Load all registered monitors
975 static DWORD monitor_loadall(void)
977 monitor_t * pm;
978 DWORD registered = 0;
979 DWORD loaded = 0;
980 HKEY hmonitors;
981 WCHAR buffer[MAX_PATH];
982 DWORD id = 0;
984 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
985 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
986 NULL, NULL, NULL, NULL, NULL);
988 TRACE("%d monitors registered\n", registered);
990 EnterCriticalSection(&monitor_handles_cs);
991 while (id < registered) {
992 buffer[0] = '\0';
993 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
994 pm = monitor_load(buffer, NULL);
995 if (pm) loaded++;
996 id++;
998 LeaveCriticalSection(&monitor_handles_cs);
999 RegCloseKey(hmonitors);
1001 TRACE("%d monitors loaded\n", loaded);
1002 return loaded;
1005 /******************************************************************
1006 * monitor_loadui [internal]
1008 * load the userinterface-dll for a given portmonitor
1010 * On failure, NULL is returned
1013 static monitor_t * monitor_loadui(monitor_t * pm)
1015 monitor_t * pui = NULL;
1016 LPWSTR buffer[MAX_PATH];
1017 HANDLE hXcv;
1018 DWORD len;
1019 DWORD res;
1021 if (pm == NULL) return NULL;
1022 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1024 /* Try the Portmonitor first; works for many monitors */
1025 if (pm->monitorUI) {
1026 EnterCriticalSection(&monitor_handles_cs);
1027 pm->refcount++;
1028 LeaveCriticalSection(&monitor_handles_cs);
1029 return pm;
1032 /* query the userinterface-dllname from the Portmonitor */
1033 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1034 /* building (",XcvMonitor %s",pm->name) not needed yet */
1035 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1036 TRACE("got %u with %p\n", res, hXcv);
1037 if (res) {
1038 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1039 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1040 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1041 pm->monitor->pfnXcvClosePort(hXcv);
1044 return pui;
1048 /******************************************************************
1049 * monitor_load_by_port [internal]
1051 * load a printmonitor for a given port
1053 * On failure, NULL is returned
1056 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1058 HKEY hroot;
1059 HKEY hport;
1060 LPWSTR buffer;
1061 monitor_t * pm = NULL;
1062 DWORD registered = 0;
1063 DWORD id = 0;
1064 DWORD len;
1066 TRACE("(%s)\n", debugstr_w(portname));
1068 /* Try the Local Monitor first */
1069 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1070 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1071 /* found the portname */
1072 RegCloseKey(hroot);
1073 return monitor_load(LocalPortW, NULL);
1075 RegCloseKey(hroot);
1078 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1079 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1080 if (buffer == NULL) return NULL;
1082 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1083 EnterCriticalSection(&monitor_handles_cs);
1084 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1086 while ((pm == NULL) && (id < registered)) {
1087 buffer[0] = '\0';
1088 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1089 TRACE("testing %s\n", debugstr_w(buffer));
1090 len = lstrlenW(buffer);
1091 lstrcatW(buffer, bs_Ports_bsW);
1092 lstrcatW(buffer, portname);
1093 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1094 RegCloseKey(hport);
1095 buffer[len] = '\0'; /* use only the Monitor-Name */
1096 pm = monitor_load(buffer, NULL);
1098 id++;
1100 LeaveCriticalSection(&monitor_handles_cs);
1101 RegCloseKey(hroot);
1103 HeapFree(GetProcessHeap(), 0, buffer);
1104 return pm;
1107 /******************************************************************
1108 * enumerate the local Ports from all loaded monitors (internal)
1110 * returns the needed size (in bytes) for pPorts
1111 * and *lpreturned is set to number of entries returned in pPorts
1114 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1116 monitor_t * pm;
1117 LPWSTR ptr;
1118 LPPORT_INFO_2W cache;
1119 LPPORT_INFO_2W out;
1120 LPBYTE pi_buffer = NULL;
1121 DWORD pi_allocated = 0;
1122 DWORD pi_needed;
1123 DWORD pi_index;
1124 DWORD pi_returned;
1125 DWORD res;
1126 DWORD outindex = 0;
1127 DWORD needed;
1128 DWORD numentries;
1129 DWORD entrysize;
1132 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1133 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1135 numentries = *lpreturned; /* this is 0, when we scan the registry */
1136 needed = entrysize * numentries;
1137 ptr = (LPWSTR) &pPorts[needed];
1139 numentries = 0;
1140 needed = 0;
1142 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1144 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1145 pi_needed = 0;
1146 pi_returned = 0;
1147 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1148 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1149 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1150 HeapFree(GetProcessHeap(), 0, pi_buffer);
1151 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1152 pi_allocated = (pi_buffer) ? pi_needed : 0;
1153 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1155 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1156 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1158 numentries += pi_returned;
1159 needed += pi_needed;
1161 /* fill the output-buffer (pPorts), if we have one */
1162 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1163 pi_index = 0;
1164 while (pi_returned > pi_index) {
1165 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1166 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1167 out->pPortName = ptr;
1168 lstrcpyW(ptr, cache->pPortName);
1169 ptr += (lstrlenW(ptr)+1);
1170 if (level > 1) {
1171 out->pMonitorName = ptr;
1172 lstrcpyW(ptr, cache->pMonitorName);
1173 ptr += (lstrlenW(ptr)+1);
1175 out->pDescription = ptr;
1176 lstrcpyW(ptr, cache->pDescription);
1177 ptr += (lstrlenW(ptr)+1);
1178 out->fPortType = cache->fPortType;
1179 out->Reserved = cache->Reserved;
1181 pi_index++;
1182 outindex++;
1187 /* the temporary portinfo-buffer is no longer needed */
1188 HeapFree(GetProcessHeap(), 0, pi_buffer);
1190 *lpreturned = numentries;
1191 TRACE("need %d byte for %d entries\n", needed, numentries);
1192 return needed;
1195 /******************************************************************
1196 * get_servername_from_name (internal)
1198 * for an external server, a copy of the serverpart from the full name is returned
1201 static LPWSTR get_servername_from_name(LPCWSTR name)
1203 LPWSTR server;
1204 LPWSTR ptr;
1205 WCHAR buffer[MAX_PATH];
1206 DWORD len;
1208 if (name == NULL) return NULL;
1209 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1211 server = strdupW(&name[2]); /* skip over both backslash */
1212 if (server == NULL) return NULL;
1214 /* strip '\' and the printername */
1215 ptr = strchrW(server, '\\');
1216 if (ptr) ptr[0] = '\0';
1218 TRACE("found %s\n", debugstr_w(server));
1220 len = sizeof(buffer)/sizeof(buffer[0]);
1221 if (GetComputerNameW(buffer, &len)) {
1222 if (lstrcmpW(buffer, server) == 0) {
1223 /* The requested Servername is our computername */
1224 HeapFree(GetProcessHeap(), 0, server);
1225 return NULL;
1228 return server;
1231 /******************************************************************
1232 * get_basename_from_name (internal)
1234 * skip over the serverpart from the full name
1237 static LPCWSTR get_basename_from_name(LPCWSTR name)
1239 if (name == NULL) return NULL;
1240 if ((name[0] == '\\') && (name[1] == '\\')) {
1241 /* skip over the servername and search for the following '\' */
1242 name = strchrW(&name[2], '\\');
1243 if ((name) && (name[1])) {
1244 /* found a separator ('\') followed by a name:
1245 skip over the separator and return the rest */
1246 name++;
1248 else
1250 /* no basename present (we found only a servername) */
1251 return NULL;
1254 return name;
1257 /******************************************************************
1258 * get_opened_printer_entry
1259 * Get the first place empty in the opened printer table
1261 * ToDo:
1262 * - pDefault is ignored
1264 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1266 UINT_PTR handle = nb_printer_handles, i;
1267 jobqueue_t *queue = NULL;
1268 opened_printer_t *printer = NULL;
1269 LPWSTR servername;
1270 LPCWSTR printername;
1271 HKEY hkeyPrinters;
1272 HKEY hkeyPrinter;
1273 DWORD len;
1275 servername = get_servername_from_name(name);
1276 if (servername) {
1277 FIXME("server %s not supported\n", debugstr_w(servername));
1278 HeapFree(GetProcessHeap(), 0, servername);
1279 SetLastError(ERROR_INVALID_PRINTER_NAME);
1280 return NULL;
1283 printername = get_basename_from_name(name);
1284 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1286 /* an empty printername is invalid */
1287 if (printername && (!printername[0])) {
1288 SetLastError(ERROR_INVALID_PARAMETER);
1289 return NULL;
1292 EnterCriticalSection(&printer_handles_cs);
1294 for (i = 0; i < nb_printer_handles; i++)
1296 if (!printer_handles[i])
1298 if(handle == nb_printer_handles)
1299 handle = i;
1301 else
1303 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1304 queue = printer_handles[i]->queue;
1308 if (handle >= nb_printer_handles)
1310 opened_printer_t **new_array;
1311 if (printer_handles)
1312 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1313 (nb_printer_handles + 16) * sizeof(*new_array) );
1314 else
1315 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1316 (nb_printer_handles + 16) * sizeof(*new_array) );
1318 if (!new_array)
1320 handle = 0;
1321 goto end;
1323 printer_handles = new_array;
1324 nb_printer_handles += 16;
1327 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1329 handle = 0;
1330 goto end;
1334 /* clone the base name. This is NULL for the printserver */
1335 printer->printername = strdupW(printername);
1337 /* clone the full name */
1338 printer->name = strdupW(name);
1339 if (name && (!printer->name)) {
1340 handle = 0;
1341 goto end;
1344 if (printername) {
1345 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1346 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1347 /* OpenPrinter(",XcvMonitor " detected */
1348 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1349 printer->pm = monitor_load(&printername[len], NULL);
1350 if (printer->pm == NULL) {
1351 SetLastError(ERROR_UNKNOWN_PORT);
1352 handle = 0;
1353 goto end;
1356 else
1358 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1359 if (strncmpW( printername, XcvPortW, len) == 0) {
1360 /* OpenPrinter(",XcvPort " detected */
1361 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1362 printer->pm = monitor_load_by_port(&printername[len]);
1363 if (printer->pm == NULL) {
1364 SetLastError(ERROR_UNKNOWN_PORT);
1365 handle = 0;
1366 goto end;
1371 if (printer->pm) {
1372 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1373 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1374 pDefault ? pDefault->DesiredAccess : 0,
1375 &printer->hXcv);
1377 if (printer->hXcv == NULL) {
1378 SetLastError(ERROR_INVALID_PARAMETER);
1379 handle = 0;
1380 goto end;
1383 else
1385 /* Does the Printer exist? */
1386 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1387 ERR("Can't create Printers key\n");
1388 handle = 0;
1389 goto end;
1391 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1392 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1393 RegCloseKey(hkeyPrinters);
1394 SetLastError(ERROR_INVALID_PRINTER_NAME);
1395 handle = 0;
1396 goto end;
1398 RegCloseKey(hkeyPrinter);
1399 RegCloseKey(hkeyPrinters);
1402 else
1404 TRACE("using the local printserver\n");
1407 if(queue)
1408 printer->queue = queue;
1409 else
1411 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1412 if (!printer->queue) {
1413 handle = 0;
1414 goto end;
1416 list_init(&printer->queue->jobs);
1417 printer->queue->ref = 0;
1419 InterlockedIncrement(&printer->queue->ref);
1421 printer_handles[handle] = printer;
1422 handle++;
1423 end:
1424 LeaveCriticalSection(&printer_handles_cs);
1425 if (!handle && printer) {
1426 /* Something failed: Free all resources */
1427 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1428 monitor_unload(printer->pm);
1429 HeapFree(GetProcessHeap(), 0, printer->printername);
1430 HeapFree(GetProcessHeap(), 0, printer->name);
1431 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1432 HeapFree(GetProcessHeap(), 0, printer);
1435 return (HANDLE)handle;
1438 /******************************************************************
1439 * get_opened_printer
1440 * Get the pointer to the opened printer referred by the handle
1442 static opened_printer_t *get_opened_printer(HANDLE hprn)
1444 UINT_PTR idx = (UINT_PTR)hprn;
1445 opened_printer_t *ret = NULL;
1447 EnterCriticalSection(&printer_handles_cs);
1449 if ((idx > 0) && (idx <= nb_printer_handles)) {
1450 ret = printer_handles[idx - 1];
1452 LeaveCriticalSection(&printer_handles_cs);
1453 return ret;
1456 /******************************************************************
1457 * get_opened_printer_name
1458 * Get the pointer to the opened printer name referred by the handle
1460 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1462 opened_printer_t *printer = get_opened_printer(hprn);
1463 if(!printer) return NULL;
1464 return printer->name;
1467 /******************************************************************
1468 * WINSPOOL_GetOpenedPrinterRegKey
1471 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1473 LPCWSTR name = get_opened_printer_name(hPrinter);
1474 DWORD ret;
1475 HKEY hkeyPrinters;
1477 if(!name) return ERROR_INVALID_HANDLE;
1479 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1480 ERROR_SUCCESS)
1481 return ret;
1483 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1485 ERR("Can't find opened printer %s in registry\n",
1486 debugstr_w(name));
1487 RegCloseKey(hkeyPrinters);
1488 return ERROR_INVALID_PRINTER_NAME; /* ? */
1490 RegCloseKey(hkeyPrinters);
1491 return ERROR_SUCCESS;
1494 void WINSPOOL_LoadSystemPrinters(void)
1496 HKEY hkey, hkeyPrinters;
1497 HANDLE hprn;
1498 DWORD needed, num, i;
1499 WCHAR PrinterName[256];
1500 BOOL done = FALSE;
1502 /* This ensures that all printer entries have a valid Name value. If causes
1503 problems later if they don't. If one is found to be missed we create one
1504 and set it equal to the name of the key */
1505 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1506 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1507 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1508 for(i = 0; i < num; i++) {
1509 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1510 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1511 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1512 set_reg_szW(hkey, NameW, PrinterName);
1514 RegCloseKey(hkey);
1519 RegCloseKey(hkeyPrinters);
1522 /* We want to avoid calling AddPrinter on printers as much as
1523 possible, because on cups printers this will (eventually) lead
1524 to a call to cupsGetPPD which takes forever, even with non-cups
1525 printers AddPrinter takes a while. So we'll tag all printers that
1526 were automatically added last time around, if they still exist
1527 we'll leave them be otherwise we'll delete them. */
1528 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1529 if(needed) {
1530 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1531 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1532 for(i = 0; i < num; i++) {
1533 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1534 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1535 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1536 DWORD dw = 1;
1537 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1538 RegCloseKey(hkey);
1540 ClosePrinter(hprn);
1545 HeapFree(GetProcessHeap(), 0, pi);
1549 #ifdef SONAME_LIBCUPS
1550 done = CUPS_LoadPrinters();
1551 #endif
1553 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1554 PRINTCAP_LoadPrinters();
1556 /* Now enumerate the list again and delete any printers that are still tagged */
1557 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1558 if(needed) {
1559 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1560 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1561 for(i = 0; i < num; i++) {
1562 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1563 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1564 BOOL delete_driver = FALSE;
1565 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1566 DWORD dw, type, size = sizeof(dw);
1567 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1568 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1569 DeletePrinter(hprn);
1570 delete_driver = TRUE;
1572 RegCloseKey(hkey);
1574 ClosePrinter(hprn);
1575 if(delete_driver)
1576 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1581 HeapFree(GetProcessHeap(), 0, pi);
1584 return;
1588 /******************************************************************
1589 * get_job
1591 * Get the pointer to the specified job.
1592 * Should hold the printer_handles_cs before calling.
1594 static job_t *get_job(HANDLE hprn, DWORD JobId)
1596 opened_printer_t *printer = get_opened_printer(hprn);
1597 job_t *job;
1599 if(!printer) return NULL;
1600 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1602 if(job->job_id == JobId)
1603 return job;
1605 return NULL;
1608 /***********************************************************
1609 * DEVMODEcpyAtoW
1611 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1613 BOOL Formname;
1614 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1615 DWORD size;
1617 Formname = (dmA->dmSize > off_formname);
1618 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1619 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1620 dmW->dmDeviceName, CCHDEVICENAME);
1621 if(!Formname) {
1622 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1623 dmA->dmSize - CCHDEVICENAME);
1624 } else {
1625 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1626 off_formname - CCHDEVICENAME);
1627 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1628 dmW->dmFormName, CCHFORMNAME);
1629 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1630 (off_formname + CCHFORMNAME));
1632 dmW->dmSize = size;
1633 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1634 dmA->dmDriverExtra);
1635 return dmW;
1638 /***********************************************************
1639 * DEVMODEdupWtoA
1640 * Creates an ansi copy of supplied devmode
1642 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1644 LPDEVMODEA dmA;
1645 DWORD size;
1647 if (!dmW) return NULL;
1648 size = dmW->dmSize - CCHDEVICENAME -
1649 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1651 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1652 if (!dmA) return NULL;
1654 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1655 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1657 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1658 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1659 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1661 else
1663 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1664 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1665 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1666 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1668 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1671 dmA->dmSize = size;
1672 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1673 return dmA;
1676 /******************************************************************
1677 * convert_printerinfo_W_to_A [internal]
1680 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1681 DWORD level, DWORD outlen, DWORD numentries)
1683 DWORD id = 0;
1684 LPSTR ptr;
1685 INT len;
1687 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1689 len = pi_sizeof[level] * numentries;
1690 ptr = (LPSTR) out + len;
1691 outlen -= len;
1693 /* copy the numbers of all PRINTER_INFO_* first */
1694 memcpy(out, pPrintersW, len);
1696 while (id < numentries) {
1697 switch (level) {
1698 case 1:
1700 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1701 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1703 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1704 if (piW->pDescription) {
1705 piA->pDescription = ptr;
1706 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1707 ptr, outlen, NULL, NULL);
1708 ptr += len;
1709 outlen -= len;
1711 if (piW->pName) {
1712 piA->pName = ptr;
1713 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1714 ptr, outlen, NULL, NULL);
1715 ptr += len;
1716 outlen -= len;
1718 if (piW->pComment) {
1719 piA->pComment = ptr;
1720 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1721 ptr, outlen, NULL, NULL);
1722 ptr += len;
1723 outlen -= len;
1725 break;
1728 case 2:
1730 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1731 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1732 LPDEVMODEA dmA;
1734 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1735 if (piW->pServerName) {
1736 piA->pServerName = ptr;
1737 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1738 ptr, outlen, NULL, NULL);
1739 ptr += len;
1740 outlen -= len;
1742 if (piW->pPrinterName) {
1743 piA->pPrinterName = ptr;
1744 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1745 ptr, outlen, NULL, NULL);
1746 ptr += len;
1747 outlen -= len;
1749 if (piW->pShareName) {
1750 piA->pShareName = ptr;
1751 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1752 ptr, outlen, NULL, NULL);
1753 ptr += len;
1754 outlen -= len;
1756 if (piW->pPortName) {
1757 piA->pPortName = ptr;
1758 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1759 ptr, outlen, NULL, NULL);
1760 ptr += len;
1761 outlen -= len;
1763 if (piW->pDriverName) {
1764 piA->pDriverName = ptr;
1765 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1766 ptr, outlen, NULL, NULL);
1767 ptr += len;
1768 outlen -= len;
1770 if (piW->pComment) {
1771 piA->pComment = ptr;
1772 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1773 ptr, outlen, NULL, NULL);
1774 ptr += len;
1775 outlen -= len;
1777 if (piW->pLocation) {
1778 piA->pLocation = ptr;
1779 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1780 ptr, outlen, NULL, NULL);
1781 ptr += len;
1782 outlen -= len;
1785 dmA = DEVMODEdupWtoA(piW->pDevMode);
1786 if (dmA) {
1787 /* align DEVMODEA to a DWORD boundary */
1788 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1789 ptr += len;
1790 outlen -= len;
1792 piA->pDevMode = (LPDEVMODEA) ptr;
1793 len = dmA->dmSize + dmA->dmDriverExtra;
1794 memcpy(ptr, dmA, len);
1795 HeapFree(GetProcessHeap(), 0, dmA);
1797 ptr += len;
1798 outlen -= len;
1801 if (piW->pSepFile) {
1802 piA->pSepFile = ptr;
1803 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1804 ptr, outlen, NULL, NULL);
1805 ptr += len;
1806 outlen -= len;
1808 if (piW->pPrintProcessor) {
1809 piA->pPrintProcessor = ptr;
1810 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1811 ptr, outlen, NULL, NULL);
1812 ptr += len;
1813 outlen -= len;
1815 if (piW->pDatatype) {
1816 piA->pDatatype = ptr;
1817 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1818 ptr, outlen, NULL, NULL);
1819 ptr += len;
1820 outlen -= len;
1822 if (piW->pParameters) {
1823 piA->pParameters = ptr;
1824 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1825 ptr, outlen, NULL, NULL);
1826 ptr += len;
1827 outlen -= len;
1829 if (piW->pSecurityDescriptor) {
1830 piA->pSecurityDescriptor = NULL;
1831 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1833 break;
1836 case 4:
1838 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1839 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1841 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1843 if (piW->pPrinterName) {
1844 piA->pPrinterName = ptr;
1845 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1846 ptr, outlen, NULL, NULL);
1847 ptr += len;
1848 outlen -= len;
1850 if (piW->pServerName) {
1851 piA->pServerName = ptr;
1852 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1853 ptr, outlen, NULL, NULL);
1854 ptr += len;
1855 outlen -= len;
1857 break;
1860 case 5:
1862 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1863 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1865 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1867 if (piW->pPrinterName) {
1868 piA->pPrinterName = ptr;
1869 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1870 ptr, outlen, NULL, NULL);
1871 ptr += len;
1872 outlen -= len;
1874 if (piW->pPortName) {
1875 piA->pPortName = ptr;
1876 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1877 ptr, outlen, NULL, NULL);
1878 ptr += len;
1879 outlen -= len;
1881 break;
1884 default:
1885 FIXME("for level %u\n", level);
1887 pPrintersW += pi_sizeof[level];
1888 out += pi_sizeof[level];
1889 id++;
1893 /***********************************************************
1894 * PRINTER_INFO_2AtoW
1895 * Creates a unicode copy of PRINTER_INFO_2A on heap
1897 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1899 LPPRINTER_INFO_2W piW;
1900 UNICODE_STRING usBuffer;
1902 if(!piA) return NULL;
1903 piW = HeapAlloc(heap, 0, sizeof(*piW));
1904 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1906 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1907 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1908 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1909 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1910 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1911 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1912 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1913 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1914 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1915 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1916 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1917 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1918 return piW;
1921 /***********************************************************
1922 * FREE_PRINTER_INFO_2W
1923 * Free PRINTER_INFO_2W and all strings
1925 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1927 if(!piW) return;
1929 HeapFree(heap,0,piW->pServerName);
1930 HeapFree(heap,0,piW->pPrinterName);
1931 HeapFree(heap,0,piW->pShareName);
1932 HeapFree(heap,0,piW->pPortName);
1933 HeapFree(heap,0,piW->pDriverName);
1934 HeapFree(heap,0,piW->pComment);
1935 HeapFree(heap,0,piW->pLocation);
1936 HeapFree(heap,0,piW->pDevMode);
1937 HeapFree(heap,0,piW->pSepFile);
1938 HeapFree(heap,0,piW->pPrintProcessor);
1939 HeapFree(heap,0,piW->pDatatype);
1940 HeapFree(heap,0,piW->pParameters);
1941 HeapFree(heap,0,piW);
1942 return;
1945 /******************************************************************
1946 * DeviceCapabilities [WINSPOOL.@]
1947 * DeviceCapabilitiesA [WINSPOOL.@]
1950 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1951 LPSTR pOutput, LPDEVMODEA lpdm)
1953 INT ret;
1955 if (!GDI_CallDeviceCapabilities16)
1957 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1958 (LPCSTR)104 );
1959 if (!GDI_CallDeviceCapabilities16) return -1;
1961 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1963 /* If DC_PAPERSIZE map POINT16s to POINTs */
1964 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1965 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1966 POINT *pt = (POINT *)pOutput;
1967 INT i;
1968 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1969 for(i = 0; i < ret; i++, pt++)
1971 pt->x = tmp[i].x;
1972 pt->y = tmp[i].y;
1974 HeapFree( GetProcessHeap(), 0, tmp );
1976 return ret;
1980 /*****************************************************************************
1981 * DeviceCapabilitiesW [WINSPOOL.@]
1983 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1986 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1987 WORD fwCapability, LPWSTR pOutput,
1988 const DEVMODEW *pDevMode)
1990 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1991 LPSTR pDeviceA = strdupWtoA(pDevice);
1992 LPSTR pPortA = strdupWtoA(pPort);
1993 INT ret;
1995 if(pOutput && (fwCapability == DC_BINNAMES ||
1996 fwCapability == DC_FILEDEPENDENCIES ||
1997 fwCapability == DC_PAPERNAMES)) {
1998 /* These need A -> W translation */
1999 INT size = 0, i;
2000 LPSTR pOutputA;
2001 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2002 dmA);
2003 if(ret == -1)
2004 return ret;
2005 switch(fwCapability) {
2006 case DC_BINNAMES:
2007 size = 24;
2008 break;
2009 case DC_PAPERNAMES:
2010 case DC_FILEDEPENDENCIES:
2011 size = 64;
2012 break;
2014 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2015 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2016 dmA);
2017 for(i = 0; i < ret; i++)
2018 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2019 pOutput + (i * size), size);
2020 HeapFree(GetProcessHeap(), 0, pOutputA);
2021 } else {
2022 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2023 (LPSTR)pOutput, dmA);
2025 HeapFree(GetProcessHeap(),0,pPortA);
2026 HeapFree(GetProcessHeap(),0,pDeviceA);
2027 HeapFree(GetProcessHeap(),0,dmA);
2028 return ret;
2031 /******************************************************************
2032 * DocumentPropertiesA [WINSPOOL.@]
2034 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2036 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2037 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2038 LPDEVMODEA pDevModeInput,DWORD fMode )
2040 LPSTR lpName = pDeviceName;
2041 static CHAR port[] = "LPT1:";
2042 LONG ret;
2044 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2045 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2048 if(!pDeviceName) {
2049 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2050 if(!lpNameW) {
2051 ERR("no name from hPrinter?\n");
2052 SetLastError(ERROR_INVALID_HANDLE);
2053 return -1;
2055 lpName = strdupWtoA(lpNameW);
2058 if (!GDI_CallExtDeviceMode16)
2060 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2061 (LPCSTR)102 );
2062 if (!GDI_CallExtDeviceMode16) {
2063 ERR("No CallExtDeviceMode16?\n");
2064 return -1;
2067 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2068 pDevModeInput, NULL, fMode);
2070 if(!pDeviceName)
2071 HeapFree(GetProcessHeap(),0,lpName);
2072 return ret;
2076 /*****************************************************************************
2077 * DocumentPropertiesW (WINSPOOL.@)
2079 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2081 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2082 LPWSTR pDeviceName,
2083 LPDEVMODEW pDevModeOutput,
2084 LPDEVMODEW pDevModeInput, DWORD fMode)
2087 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2088 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2089 LPDEVMODEA pDevModeOutputA = NULL;
2090 LONG ret;
2092 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2093 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2094 fMode);
2095 if(pDevModeOutput) {
2096 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2097 if(ret < 0) return ret;
2098 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2100 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2101 pDevModeInputA, fMode);
2102 if(pDevModeOutput) {
2103 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2104 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2106 if(fMode == 0 && ret > 0)
2107 ret += (CCHDEVICENAME + CCHFORMNAME);
2108 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2109 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2110 return ret;
2113 /******************************************************************
2114 * OpenPrinterA [WINSPOOL.@]
2116 * See OpenPrinterW.
2119 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2120 LPPRINTER_DEFAULTSA pDefault)
2122 UNICODE_STRING lpPrinterNameW;
2123 UNICODE_STRING usBuffer;
2124 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2125 PWSTR pwstrPrinterNameW;
2126 BOOL ret;
2128 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2130 if(pDefault) {
2131 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2132 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2133 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2134 pDefaultW = &DefaultW;
2136 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2137 if(pDefault) {
2138 RtlFreeUnicodeString(&usBuffer);
2139 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2141 RtlFreeUnicodeString(&lpPrinterNameW);
2142 return ret;
2145 /******************************************************************
2146 * OpenPrinterW [WINSPOOL.@]
2148 * Open a Printer / Printserver or a Printer-Object
2150 * PARAMS
2151 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2152 * phPrinter [O] The resulting Handle is stored here
2153 * pDefault [I] PTR to Default Printer Settings or NULL
2155 * RETURNS
2156 * Success: TRUE
2157 * Failure: FALSE
2159 * NOTES
2160 * lpPrinterName is one of:
2161 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2162 *| Printer: "PrinterName"
2163 *| Printer-Object: "PrinterName,Job xxx"
2164 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2165 *| XcvPort: "Servername,XcvPort PortName"
2167 * BUGS
2168 *| Printer-Object not supported
2169 *| pDefaults is ignored
2172 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2175 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2176 if (pDefault) {
2177 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2178 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2181 if(!phPrinter) {
2182 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2183 SetLastError(ERROR_INVALID_PARAMETER);
2184 return FALSE;
2187 /* Get the unique handle of the printer or Printserver */
2188 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2189 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2190 return (*phPrinter != 0);
2193 /******************************************************************
2194 * AddMonitorA [WINSPOOL.@]
2196 * See AddMonitorW.
2199 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2201 LPWSTR nameW = NULL;
2202 INT len;
2203 BOOL res;
2204 LPMONITOR_INFO_2A mi2a;
2205 MONITOR_INFO_2W mi2w;
2207 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2208 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2209 debugstr_a(mi2a ? mi2a->pName : NULL),
2210 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2211 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2213 if (Level != 2) {
2214 SetLastError(ERROR_INVALID_LEVEL);
2215 return FALSE;
2218 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2219 if (mi2a == NULL) {
2220 return FALSE;
2223 if (pName) {
2224 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2225 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2226 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2229 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2230 if (mi2a->pName) {
2231 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2232 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2233 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2235 if (mi2a->pEnvironment) {
2236 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2237 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2238 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2240 if (mi2a->pDLLName) {
2241 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2242 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2243 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2246 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2248 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2249 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2250 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2252 HeapFree(GetProcessHeap(), 0, nameW);
2253 return (res);
2256 /******************************************************************************
2257 * AddMonitorW [WINSPOOL.@]
2259 * Install a Printmonitor
2261 * PARAMS
2262 * pName [I] Servername or NULL (local Computer)
2263 * Level [I] Structure-Level (Must be 2)
2264 * pMonitors [I] PTR to MONITOR_INFO_2
2266 * RETURNS
2267 * Success: TRUE
2268 * Failure: FALSE
2270 * NOTES
2271 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2274 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2276 monitor_t * pm = NULL;
2277 LPMONITOR_INFO_2W mi2w;
2278 HKEY hroot = NULL;
2279 HKEY hentry = NULL;
2280 DWORD disposition;
2281 BOOL res = FALSE;
2283 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2284 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2285 debugstr_w(mi2w ? mi2w->pName : NULL),
2286 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2287 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2289 if (Level != 2) {
2290 SetLastError(ERROR_INVALID_LEVEL);
2291 return FALSE;
2294 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2295 if (mi2w == NULL) {
2296 return FALSE;
2299 if (pName && (pName[0])) {
2300 FIXME("for server %s not implemented\n", debugstr_w(pName));
2301 SetLastError(ERROR_ACCESS_DENIED);
2302 return FALSE;
2306 if (!mi2w->pName || (! mi2w->pName[0])) {
2307 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2308 SetLastError(ERROR_INVALID_PARAMETER);
2309 return FALSE;
2311 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2312 WARN("Environment %s requested (we support only %s)\n",
2313 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2314 SetLastError(ERROR_INVALID_ENVIRONMENT);
2315 return FALSE;
2318 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2319 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2320 SetLastError(ERROR_INVALID_PARAMETER);
2321 return FALSE;
2324 /* Load and initialize the monitor. SetLastError() is called on failure */
2325 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2326 return FALSE;
2328 monitor_unload(pm);
2330 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2331 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2332 return FALSE;
2335 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2336 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2337 &disposition) == ERROR_SUCCESS) {
2339 /* Some installers set options for the port before calling AddMonitor.
2340 We query the "Driver" entry to verify that the monitor is installed,
2341 before we return an error.
2342 When a user installs two print monitors at the same time with the
2343 same name but with a different driver DLL and a task switch comes
2344 between RegQueryValueExW and RegSetValueExW, a race condition
2345 is possible but silently ignored. */
2347 DWORD namesize = 0;
2349 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2350 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2351 &namesize) == ERROR_SUCCESS)) {
2352 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2353 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2354 9x: ERROR_ALREADY_EXISTS (183) */
2355 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2357 else
2359 INT len;
2360 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2361 res = (RegSetValueExW(hentry, DriverW, 0,
2362 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2364 RegCloseKey(hentry);
2367 RegCloseKey(hroot);
2368 return (res);
2371 /******************************************************************
2372 * DeletePrinterDriverA [WINSPOOL.@]
2375 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2377 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2380 /******************************************************************
2381 * DeletePrinterDriverW [WINSPOOL.@]
2384 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2386 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2389 /******************************************************************
2390 * DeleteMonitorA [WINSPOOL.@]
2392 * See DeleteMonitorW.
2395 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2397 LPWSTR nameW = NULL;
2398 LPWSTR EnvironmentW = NULL;
2399 LPWSTR MonitorNameW = NULL;
2400 BOOL res;
2401 INT len;
2403 if (pName) {
2404 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2405 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2406 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2409 if (pEnvironment) {
2410 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2411 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2412 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2414 if (pMonitorName) {
2415 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2416 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2417 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2420 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2422 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2423 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2424 HeapFree(GetProcessHeap(), 0, nameW);
2425 return (res);
2428 /******************************************************************
2429 * DeleteMonitorW [WINSPOOL.@]
2431 * Delete a specific Printmonitor from a Printing-Environment
2433 * PARAMS
2434 * pName [I] Servername or NULL (local Computer)
2435 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2436 * pMonitorName [I] Name of the Monitor, that should be deleted
2438 * RETURNS
2439 * Success: TRUE
2440 * Failure: FALSE
2442 * NOTES
2443 * pEnvironment is ignored in Windows for the local Computer.
2447 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2449 HKEY hroot = NULL;
2451 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2452 debugstr_w(pMonitorName));
2454 if (pName && (pName[0])) {
2455 FIXME("for server %s not implemented\n", debugstr_w(pName));
2456 SetLastError(ERROR_ACCESS_DENIED);
2457 return FALSE;
2460 /* pEnvironment is ignored in Windows for the local Computer */
2462 if (!pMonitorName || !pMonitorName[0]) {
2463 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2464 SetLastError(ERROR_INVALID_PARAMETER);
2465 return FALSE;
2468 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2469 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2470 return FALSE;
2473 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2474 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2475 RegCloseKey(hroot);
2476 return TRUE;
2479 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2480 RegCloseKey(hroot);
2482 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2483 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2484 return (FALSE);
2487 /******************************************************************
2488 * DeletePortA [WINSPOOL.@]
2490 * See DeletePortW.
2493 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2495 LPWSTR nameW = NULL;
2496 LPWSTR portW = NULL;
2497 INT len;
2498 DWORD res;
2500 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2502 /* convert servername to unicode */
2503 if (pName) {
2504 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2505 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2506 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2509 /* convert portname to unicode */
2510 if (pPortName) {
2511 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2512 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2513 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2516 res = DeletePortW(nameW, hWnd, portW);
2517 HeapFree(GetProcessHeap(), 0, nameW);
2518 HeapFree(GetProcessHeap(), 0, portW);
2519 return res;
2522 /******************************************************************
2523 * DeletePortW [WINSPOOL.@]
2525 * Delete a specific Port
2527 * PARAMS
2528 * pName [I] Servername or NULL (local Computer)
2529 * hWnd [I] Handle to parent Window for the Dialog-Box
2530 * pPortName [I] Name of the Port, that should be deleted
2532 * RETURNS
2533 * Success: TRUE
2534 * Failure: FALSE
2537 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2539 monitor_t * pm;
2540 monitor_t * pui;
2541 DWORD res;
2543 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2545 if (pName && pName[0]) {
2546 SetLastError(ERROR_INVALID_PARAMETER);
2547 return FALSE;
2550 if (!pPortName) {
2551 SetLastError(RPC_X_NULL_REF_POINTER);
2552 return FALSE;
2555 /* an empty Portname is Invalid */
2556 if (!pPortName[0]) {
2557 SetLastError(ERROR_NOT_SUPPORTED);
2558 return FALSE;
2561 pm = monitor_load_by_port(pPortName);
2562 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2563 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2564 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2565 TRACE("got %d with %u\n", res, GetLastError());
2567 else
2569 pui = monitor_loadui(pm);
2570 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2571 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2572 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2573 TRACE("got %d with %u\n", res, GetLastError());
2575 else
2577 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2578 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2580 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2581 SetLastError(ERROR_NOT_SUPPORTED);
2582 res = FALSE;
2584 monitor_unload(pui);
2586 monitor_unload(pm);
2588 TRACE("returning %d with %u\n", res, GetLastError());
2589 return res;
2592 /******************************************************************************
2593 * SetPrinterW [WINSPOOL.@]
2595 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2597 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2598 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2599 return FALSE;
2602 /******************************************************************************
2603 * WritePrinter [WINSPOOL.@]
2605 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2607 opened_printer_t *printer;
2608 BOOL ret = FALSE;
2610 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2612 EnterCriticalSection(&printer_handles_cs);
2613 printer = get_opened_printer(hPrinter);
2614 if(!printer)
2616 SetLastError(ERROR_INVALID_HANDLE);
2617 goto end;
2620 if(!printer->doc)
2622 SetLastError(ERROR_SPL_NO_STARTDOC);
2623 goto end;
2626 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2627 end:
2628 LeaveCriticalSection(&printer_handles_cs);
2629 return ret;
2632 /*****************************************************************************
2633 * AddFormA [WINSPOOL.@]
2635 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2637 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2638 return 1;
2641 /*****************************************************************************
2642 * AddFormW [WINSPOOL.@]
2644 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2646 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2647 return 1;
2650 /*****************************************************************************
2651 * AddJobA [WINSPOOL.@]
2653 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2655 BOOL ret;
2656 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2657 DWORD needed;
2659 if(Level != 1) {
2660 SetLastError(ERROR_INVALID_LEVEL);
2661 return FALSE;
2664 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2666 if(ret) {
2667 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2668 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2669 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2670 if(*pcbNeeded > cbBuf) {
2671 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2672 ret = FALSE;
2673 } else {
2674 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2675 addjobA->JobId = addjobW->JobId;
2676 addjobA->Path = (char *)(addjobA + 1);
2677 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2680 return ret;
2683 /*****************************************************************************
2684 * AddJobW [WINSPOOL.@]
2686 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2688 opened_printer_t *printer;
2689 job_t *job;
2690 BOOL ret = FALSE;
2691 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2692 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2693 WCHAR path[MAX_PATH], filename[MAX_PATH];
2694 DWORD len;
2695 ADDJOB_INFO_1W *addjob;
2697 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2699 EnterCriticalSection(&printer_handles_cs);
2701 printer = get_opened_printer(hPrinter);
2703 if(!printer) {
2704 SetLastError(ERROR_INVALID_HANDLE);
2705 goto end;
2708 if(Level != 1) {
2709 SetLastError(ERROR_INVALID_LEVEL);
2710 goto end;
2713 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2714 if(!job)
2715 goto end;
2717 job->job_id = InterlockedIncrement(&next_job_id);
2719 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2720 if(path[len - 1] != '\\')
2721 path[len++] = '\\';
2722 memcpy(path + len, spool_path, sizeof(spool_path));
2723 sprintfW(filename, fmtW, path, job->job_id);
2725 len = strlenW(filename);
2726 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2727 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2728 job->document_title = strdupW(default_doc_title);
2729 list_add_tail(&printer->queue->jobs, &job->entry);
2731 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2732 if(*pcbNeeded <= cbBuf) {
2733 addjob = (ADDJOB_INFO_1W*)pData;
2734 addjob->JobId = job->job_id;
2735 addjob->Path = (WCHAR *)(addjob + 1);
2736 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2737 ret = TRUE;
2738 } else
2739 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2741 end:
2742 LeaveCriticalSection(&printer_handles_cs);
2743 return ret;
2746 /*****************************************************************************
2747 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2749 * Return the PATH for the Print-Processors
2751 * See GetPrintProcessorDirectoryW.
2755 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2756 DWORD level, LPBYTE Info,
2757 DWORD cbBuf, LPDWORD pcbNeeded)
2759 LPWSTR serverW = NULL;
2760 LPWSTR envW = NULL;
2761 BOOL ret;
2762 INT len;
2764 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2765 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2768 if (server) {
2769 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2770 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2771 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2774 if (env) {
2775 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2776 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2777 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2780 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2781 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2783 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2784 cbBuf, pcbNeeded);
2786 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2787 cbBuf, NULL, NULL) > 0;
2790 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2791 HeapFree(GetProcessHeap(), 0, envW);
2792 HeapFree(GetProcessHeap(), 0, serverW);
2793 return ret;
2796 /*****************************************************************************
2797 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2799 * Return the PATH for the Print-Processors
2801 * PARAMS
2802 * server [I] Servername (NT only) or NULL (local Computer)
2803 * env [I] Printing-Environment (see below) or NULL (Default)
2804 * level [I] Structure-Level (must be 1)
2805 * Info [O] PTR to Buffer that receives the Result
2806 * cbBuf [I] Size of Buffer at "Info"
2807 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2808 * required for the Buffer at "Info"
2810 * RETURNS
2811 * Success: TRUE and in pcbNeeded the Bytes used in Info
2812 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2813 * if cbBuf is too small
2815 * Native Values returned in Info on Success:
2816 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2817 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2818 *| win9x(Windows 4.0): "%winsysdir%"
2820 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2822 * BUGS
2823 * Only NULL or "" is supported for server
2826 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2827 DWORD level, LPBYTE Info,
2828 DWORD cbBuf, LPDWORD pcbNeeded)
2830 DWORD needed;
2831 const printenv_t * env_t;
2833 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2834 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2836 if(server != NULL && server[0]) {
2837 FIXME("server not supported: %s\n", debugstr_w(server));
2838 SetLastError(ERROR_INVALID_PARAMETER);
2839 return FALSE;
2842 env_t = validate_envW(env);
2843 if(!env_t) return FALSE; /* environment invalid or unsupported */
2845 if(level != 1) {
2846 WARN("(Level: %d) is ignored in win9x\n", level);
2847 SetLastError(ERROR_INVALID_LEVEL);
2848 return FALSE;
2851 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2852 needed = GetSystemDirectoryW(NULL, 0);
2853 /* add the Size for the Subdirectories */
2854 needed += lstrlenW(spoolprtprocsW);
2855 needed += lstrlenW(env_t->subdir);
2856 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2858 if(pcbNeeded) *pcbNeeded = needed;
2859 TRACE ("required: 0x%x/%d\n", needed, needed);
2860 if (needed > cbBuf) {
2861 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2862 return FALSE;
2864 if(pcbNeeded == NULL) {
2865 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2866 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2867 SetLastError(RPC_X_NULL_REF_POINTER);
2868 return FALSE;
2870 if(Info == NULL) {
2871 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2872 SetLastError(RPC_X_NULL_REF_POINTER);
2873 return FALSE;
2876 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2877 /* add the Subdirectories */
2878 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2879 lstrcatW((LPWSTR) Info, env_t->subdir);
2880 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2881 return TRUE;
2884 /*****************************************************************************
2885 * WINSPOOL_OpenDriverReg [internal]
2887 * opens the registry for the printer drivers depending on the given input
2888 * variable pEnvironment
2890 * RETURNS:
2891 * the opened hkey on success
2892 * NULL on error
2894 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2896 HKEY retval = NULL;
2897 LPWSTR buffer;
2898 const printenv_t * env;
2900 TRACE("(%s, %d)\n",
2901 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2903 if (!pEnvironment || unicode) {
2904 /* pEnvironment was NULL or an Unicode-String: use it direct */
2905 env = validate_envW(pEnvironment);
2907 else
2909 /* pEnvironment was an ANSI-String: convert to unicode first */
2910 LPWSTR buffer;
2911 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2912 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2913 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2914 env = validate_envW(buffer);
2915 HeapFree(GetProcessHeap(), 0, buffer);
2917 if (!env) return NULL;
2919 buffer = HeapAlloc( GetProcessHeap(), 0,
2920 (strlenW(DriversW) + strlenW(env->envname) +
2921 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2922 if(buffer) {
2923 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2924 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2925 HeapFree(GetProcessHeap(), 0, buffer);
2927 return retval;
2930 /*****************************************************************************
2931 * AddPrinterW [WINSPOOL.@]
2933 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2935 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2936 LPDEVMODEA dmA;
2937 LPDEVMODEW dmW;
2938 HANDLE retval;
2939 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2940 LONG size;
2941 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2942 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2943 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2944 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2945 statusW[] = {'S','t','a','t','u','s',0},
2946 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2948 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2950 if(pName != NULL) {
2951 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2952 SetLastError(ERROR_INVALID_PARAMETER);
2953 return 0;
2955 if(Level != 2) {
2956 ERR("Level = %d, unsupported!\n", Level);
2957 SetLastError(ERROR_INVALID_LEVEL);
2958 return 0;
2960 if(!pPrinter) {
2961 SetLastError(ERROR_INVALID_PARAMETER);
2962 return 0;
2964 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2965 ERROR_SUCCESS) {
2966 ERR("Can't create Printers key\n");
2967 return 0;
2969 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2970 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2971 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2972 RegCloseKey(hkeyPrinter);
2973 RegCloseKey(hkeyPrinters);
2974 return 0;
2976 RegCloseKey(hkeyPrinter);
2978 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2979 if(!hkeyDrivers) {
2980 ERR("Can't create Drivers key\n");
2981 RegCloseKey(hkeyPrinters);
2982 return 0;
2984 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2985 ERROR_SUCCESS) {
2986 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2987 RegCloseKey(hkeyPrinters);
2988 RegCloseKey(hkeyDrivers);
2989 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2990 return 0;
2992 RegCloseKey(hkeyDriver);
2993 RegCloseKey(hkeyDrivers);
2995 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2996 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2997 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2998 RegCloseKey(hkeyPrinters);
2999 return 0;
3002 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3003 ERROR_SUCCESS) {
3004 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3005 SetLastError(ERROR_INVALID_PRINTER_NAME);
3006 RegCloseKey(hkeyPrinters);
3007 return 0;
3009 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
3010 (LPBYTE)&pi->Attributes, sizeof(DWORD));
3011 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3013 /* See if we can load the driver. We may need the devmode structure anyway
3015 * FIXME:
3016 * Note that DocumentPropertiesW will briefly try to open the printer we
3017 * just create to find a DEVMODEA struct (it will use the WINEPS default
3018 * one in case it is not there, so we are ok).
3020 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3022 if(size < 0) {
3023 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3024 size = sizeof(DEVMODEW);
3026 if(pi->pDevMode)
3027 dmW = pi->pDevMode;
3028 else
3030 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3031 dmW->dmSize = size;
3032 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
3034 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3035 HeapFree(GetProcessHeap(),0,dmW);
3036 dmW=NULL;
3038 else
3040 /* set devmode to printer name */
3041 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
3045 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3046 and we support these drivers. NT writes DEVMODEW so somehow
3047 we'll need to distinguish between these when we support NT
3048 drivers */
3049 if (dmW)
3051 dmA = DEVMODEdupWtoA(dmW);
3052 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
3053 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3054 HeapFree(GetProcessHeap(), 0, dmA);
3055 if(!pi->pDevMode)
3056 HeapFree(GetProcessHeap(), 0, dmW);
3058 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3059 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3060 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3061 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3063 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3064 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3065 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3066 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3067 (LPBYTE)&pi->Priority, sizeof(DWORD));
3068 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3069 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3070 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3071 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3072 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3073 (LPBYTE)&pi->Status, sizeof(DWORD));
3074 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3075 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
3077 RegCloseKey(hkeyPrinter);
3078 RegCloseKey(hkeyPrinters);
3079 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3080 ERR("OpenPrinter failing\n");
3081 return 0;
3083 return retval;
3086 /*****************************************************************************
3087 * AddPrinterA [WINSPOOL.@]
3089 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3091 UNICODE_STRING pNameW;
3092 PWSTR pwstrNameW;
3093 PRINTER_INFO_2W *piW;
3094 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3095 HANDLE ret;
3097 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
3098 if(Level != 2) {
3099 ERR("Level = %d, unsupported!\n", Level);
3100 SetLastError(ERROR_INVALID_LEVEL);
3101 return 0;
3103 pwstrNameW = asciitounicode(&pNameW,pName);
3104 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3106 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3108 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3109 RtlFreeUnicodeString(&pNameW);
3110 return ret;
3114 /*****************************************************************************
3115 * ClosePrinter [WINSPOOL.@]
3117 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3119 UINT_PTR i = (UINT_PTR)hPrinter;
3120 opened_printer_t *printer = NULL;
3121 BOOL ret = FALSE;
3123 TRACE("(%p)\n", hPrinter);
3125 EnterCriticalSection(&printer_handles_cs);
3127 if ((i > 0) && (i <= nb_printer_handles))
3128 printer = printer_handles[i - 1];
3131 if(printer)
3133 struct list *cursor, *cursor2;
3135 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3136 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3137 printer->hXcv, debugstr_w(printer->name), printer->doc );
3139 if(printer->doc)
3140 EndDocPrinter(hPrinter);
3142 if(InterlockedDecrement(&printer->queue->ref) == 0)
3144 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3146 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3147 ScheduleJob(hPrinter, job->job_id);
3149 HeapFree(GetProcessHeap(), 0, printer->queue);
3151 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3152 monitor_unload(printer->pm);
3153 HeapFree(GetProcessHeap(), 0, printer->printername);
3154 HeapFree(GetProcessHeap(), 0, printer->name);
3155 HeapFree(GetProcessHeap(), 0, printer);
3156 printer_handles[i - 1] = NULL;
3157 ret = TRUE;
3159 LeaveCriticalSection(&printer_handles_cs);
3160 return ret;
3163 /*****************************************************************************
3164 * DeleteFormA [WINSPOOL.@]
3166 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3168 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3169 return 1;
3172 /*****************************************************************************
3173 * DeleteFormW [WINSPOOL.@]
3175 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3177 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3178 return 1;
3181 /*****************************************************************************
3182 * DeletePrinter [WINSPOOL.@]
3184 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3186 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3187 HKEY hkeyPrinters, hkey;
3189 if(!lpNameW) {
3190 SetLastError(ERROR_INVALID_HANDLE);
3191 return FALSE;
3193 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3194 RegDeleteTreeW(hkeyPrinters, lpNameW);
3195 RegCloseKey(hkeyPrinters);
3197 WriteProfileStringW(devicesW, lpNameW, NULL);
3198 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3200 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3201 RegDeleteValueW(hkey, lpNameW);
3202 RegCloseKey(hkey);
3205 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3206 RegDeleteValueW(hkey, lpNameW);
3207 RegCloseKey(hkey);
3209 return TRUE;
3212 /*****************************************************************************
3213 * SetPrinterA [WINSPOOL.@]
3215 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3216 DWORD Command)
3218 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3219 return FALSE;
3222 /*****************************************************************************
3223 * SetJobA [WINSPOOL.@]
3225 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3226 LPBYTE pJob, DWORD Command)
3228 BOOL ret;
3229 LPBYTE JobW;
3230 UNICODE_STRING usBuffer;
3232 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3234 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3235 are all ignored by SetJob, so we don't bother copying them */
3236 switch(Level)
3238 case 0:
3239 JobW = NULL;
3240 break;
3241 case 1:
3243 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3244 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3246 JobW = (LPBYTE)info1W;
3247 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3248 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3249 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3250 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3251 info1W->Status = info1A->Status;
3252 info1W->Priority = info1A->Priority;
3253 info1W->Position = info1A->Position;
3254 info1W->PagesPrinted = info1A->PagesPrinted;
3255 break;
3257 case 2:
3259 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3260 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3262 JobW = (LPBYTE)info2W;
3263 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3264 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3265 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3266 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3267 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3268 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3269 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3270 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3271 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3272 info2W->Status = info2A->Status;
3273 info2W->Priority = info2A->Priority;
3274 info2W->Position = info2A->Position;
3275 info2W->StartTime = info2A->StartTime;
3276 info2W->UntilTime = info2A->UntilTime;
3277 info2W->PagesPrinted = info2A->PagesPrinted;
3278 break;
3280 case 3:
3281 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3282 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3283 break;
3284 default:
3285 SetLastError(ERROR_INVALID_LEVEL);
3286 return FALSE;
3289 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3291 switch(Level)
3293 case 1:
3295 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3296 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3297 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3298 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3299 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3300 break;
3302 case 2:
3304 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3305 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3306 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3307 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3308 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3309 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3310 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3311 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3312 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3313 break;
3316 HeapFree(GetProcessHeap(), 0, JobW);
3318 return ret;
3321 /*****************************************************************************
3322 * SetJobW [WINSPOOL.@]
3324 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3325 LPBYTE pJob, DWORD Command)
3327 BOOL ret = FALSE;
3328 job_t *job;
3330 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3331 FIXME("Ignoring everything other than document title\n");
3333 EnterCriticalSection(&printer_handles_cs);
3334 job = get_job(hPrinter, JobId);
3335 if(!job)
3336 goto end;
3338 switch(Level)
3340 case 0:
3341 break;
3342 case 1:
3344 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3345 HeapFree(GetProcessHeap(), 0, job->document_title);
3346 job->document_title = strdupW(info1->pDocument);
3347 break;
3349 case 2:
3351 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3352 HeapFree(GetProcessHeap(), 0, job->document_title);
3353 job->document_title = strdupW(info2->pDocument);
3354 break;
3356 case 3:
3357 break;
3358 default:
3359 SetLastError(ERROR_INVALID_LEVEL);
3360 goto end;
3362 ret = TRUE;
3363 end:
3364 LeaveCriticalSection(&printer_handles_cs);
3365 return ret;
3368 /*****************************************************************************
3369 * EndDocPrinter [WINSPOOL.@]
3371 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3373 opened_printer_t *printer;
3374 BOOL ret = FALSE;
3375 TRACE("(%p)\n", hPrinter);
3377 EnterCriticalSection(&printer_handles_cs);
3379 printer = get_opened_printer(hPrinter);
3380 if(!printer)
3382 SetLastError(ERROR_INVALID_HANDLE);
3383 goto end;
3386 if(!printer->doc)
3388 SetLastError(ERROR_SPL_NO_STARTDOC);
3389 goto end;
3392 CloseHandle(printer->doc->hf);
3393 ScheduleJob(hPrinter, printer->doc->job_id);
3394 HeapFree(GetProcessHeap(), 0, printer->doc);
3395 printer->doc = NULL;
3396 ret = TRUE;
3397 end:
3398 LeaveCriticalSection(&printer_handles_cs);
3399 return ret;
3402 /*****************************************************************************
3403 * EndPagePrinter [WINSPOOL.@]
3405 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3407 FIXME("(%p): stub\n", hPrinter);
3408 return TRUE;
3411 /*****************************************************************************
3412 * StartDocPrinterA [WINSPOOL.@]
3414 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3416 UNICODE_STRING usBuffer;
3417 DOC_INFO_2W doc2W;
3418 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3419 DWORD ret;
3421 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3422 or one (DOC_INFO_3) extra DWORDs */
3424 switch(Level) {
3425 case 2:
3426 doc2W.JobId = doc2->JobId;
3427 /* fall through */
3428 case 3:
3429 doc2W.dwMode = doc2->dwMode;
3430 /* fall through */
3431 case 1:
3432 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3433 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3434 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3435 break;
3437 default:
3438 SetLastError(ERROR_INVALID_LEVEL);
3439 return FALSE;
3442 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3444 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3445 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3446 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3448 return ret;
3451 /*****************************************************************************
3452 * StartDocPrinterW [WINSPOOL.@]
3454 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3456 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3457 opened_printer_t *printer;
3458 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3459 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3460 JOB_INFO_1W job_info;
3461 DWORD needed, ret = 0;
3462 HANDLE hf;
3463 WCHAR *filename;
3465 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3466 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3467 debugstr_w(doc->pDatatype));
3469 if(Level < 1 || Level > 3)
3471 SetLastError(ERROR_INVALID_LEVEL);
3472 return 0;
3475 EnterCriticalSection(&printer_handles_cs);
3476 printer = get_opened_printer(hPrinter);
3477 if(!printer)
3479 SetLastError(ERROR_INVALID_HANDLE);
3480 goto end;
3483 if(printer->doc)
3485 SetLastError(ERROR_INVALID_PRINTER_STATE);
3486 goto end;
3489 /* Even if we're printing to a file we still add a print job, we'll
3490 just ignore the spool file name */
3492 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3494 ERR("AddJob failed gle %u\n", GetLastError());
3495 goto end;
3498 if(doc->pOutputFile)
3499 filename = doc->pOutputFile;
3500 else
3501 filename = addjob->Path;
3503 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3504 if(hf == INVALID_HANDLE_VALUE)
3505 goto end;
3507 memset(&job_info, 0, sizeof(job_info));
3508 job_info.pDocument = doc->pDocName;
3509 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3511 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3512 printer->doc->hf = hf;
3513 ret = printer->doc->job_id = addjob->JobId;
3514 end:
3515 LeaveCriticalSection(&printer_handles_cs);
3517 return ret;
3520 /*****************************************************************************
3521 * StartPagePrinter [WINSPOOL.@]
3523 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3525 FIXME("(%p): stub\n", hPrinter);
3526 return TRUE;
3529 /*****************************************************************************
3530 * GetFormA [WINSPOOL.@]
3532 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3533 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3535 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3536 Level,pForm,cbBuf,pcbNeeded);
3537 return FALSE;
3540 /*****************************************************************************
3541 * GetFormW [WINSPOOL.@]
3543 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3544 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3546 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3547 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3548 return FALSE;
3551 /*****************************************************************************
3552 * SetFormA [WINSPOOL.@]
3554 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3555 LPBYTE pForm)
3557 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3558 return FALSE;
3561 /*****************************************************************************
3562 * SetFormW [WINSPOOL.@]
3564 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3565 LPBYTE pForm)
3567 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3568 return FALSE;
3571 /*****************************************************************************
3572 * ReadPrinter [WINSPOOL.@]
3574 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3575 LPDWORD pNoBytesRead)
3577 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3578 return FALSE;
3581 /*****************************************************************************
3582 * ResetPrinterA [WINSPOOL.@]
3584 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3586 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3587 return FALSE;
3590 /*****************************************************************************
3591 * ResetPrinterW [WINSPOOL.@]
3593 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3595 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3596 return FALSE;
3599 /*****************************************************************************
3600 * WINSPOOL_GetDWORDFromReg
3602 * Return DWORD associated with ValueName from hkey.
3604 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3606 DWORD sz = sizeof(DWORD), type, value = 0;
3607 LONG ret;
3609 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3611 if(ret != ERROR_SUCCESS) {
3612 WARN("Got ret = %d on name %s\n", ret, ValueName);
3613 return 0;
3615 if(type != REG_DWORD) {
3616 ERR("Got type %d\n", type);
3617 return 0;
3619 return value;
3623 /*****************************************************************************
3624 * get_filename_from_reg [internal]
3626 * Get ValueName from hkey storing result in out
3627 * when the Value in the registry has only a filename, use driverdir as prefix
3628 * outlen is space left in out
3629 * String is stored either as unicode or ascii
3633 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3634 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3636 WCHAR filename[MAX_PATH];
3637 DWORD size;
3638 DWORD type;
3639 LONG ret;
3640 LPWSTR buffer = filename;
3641 LPWSTR ptr;
3643 *needed = 0;
3644 size = sizeof(filename);
3645 buffer[0] = '\0';
3646 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3647 if (ret == ERROR_MORE_DATA) {
3648 TRACE("need dynamic buffer: %u\n", size);
3649 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3650 if (!buffer) {
3651 /* No Memory is bad */
3652 return FALSE;
3654 buffer[0] = '\0';
3655 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3658 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3659 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3660 return FALSE;
3663 ptr = buffer;
3664 while (ptr) {
3665 /* do we have a full path ? */
3666 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3667 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3669 if (!ret) {
3670 /* we must build the full Path */
3671 *needed += dirlen;
3672 if ((out) && (outlen > dirlen)) {
3673 if (unicode) {
3674 lstrcpyW((LPWSTR)out, driverdir);
3676 else
3678 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3680 out += dirlen;
3681 outlen -= dirlen;
3683 else
3684 out = NULL;
3687 /* write the filename */
3688 if (unicode) {
3689 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3690 if ((out) && (outlen >= size)) {
3691 lstrcpyW((LPWSTR)out, ptr);
3692 out += size;
3693 outlen -= size;
3695 else
3696 out = NULL;
3698 else
3700 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3701 if ((out) && (outlen >= size)) {
3702 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3703 out += size;
3704 outlen -= size;
3706 else
3707 out = NULL;
3709 *needed += size;
3710 ptr += lstrlenW(ptr)+1;
3711 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3714 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3716 /* write the multisz-termination */
3717 if (type == REG_MULTI_SZ) {
3718 size = (unicode) ? sizeof(WCHAR) : 1;
3720 *needed += size;
3721 if (out && (outlen >= size)) {
3722 memset (out, 0, size);
3725 return TRUE;
3728 /*****************************************************************************
3729 * WINSPOOL_GetStringFromReg
3731 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3732 * String is stored either as unicode or ascii.
3733 * Bit of a hack here to get the ValueName if we want ascii.
3735 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3736 DWORD buflen, DWORD *needed,
3737 BOOL unicode)
3739 DWORD sz = buflen, type;
3740 LONG ret;
3742 if(unicode)
3743 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3744 else {
3745 LPSTR ValueNameA = strdupWtoA(ValueName);
3746 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3747 HeapFree(GetProcessHeap(),0,ValueNameA);
3749 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3750 WARN("Got ret = %d\n", ret);
3751 *needed = 0;
3752 return FALSE;
3754 /* add space for terminating '\0' */
3755 sz += unicode ? sizeof(WCHAR) : 1;
3756 *needed = sz;
3758 if (ptr)
3759 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3761 return TRUE;
3764 /*****************************************************************************
3765 * WINSPOOL_GetDefaultDevMode
3767 * Get a default DevMode values for wineps.
3768 * FIXME - use ppd.
3771 static void WINSPOOL_GetDefaultDevMode(
3772 LPBYTE ptr,
3773 DWORD buflen, DWORD *needed,
3774 BOOL unicode)
3776 DEVMODEA dm;
3777 static const char szwps[] = "wineps.drv";
3779 /* fill default DEVMODE - should be read from ppd... */
3780 ZeroMemory( &dm, sizeof(dm) );
3781 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3782 dm.dmSpecVersion = DM_SPECVERSION;
3783 dm.dmDriverVersion = 1;
3784 dm.dmSize = sizeof(DEVMODEA);
3785 dm.dmDriverExtra = 0;
3786 dm.dmFields =
3787 DM_ORIENTATION | DM_PAPERSIZE |
3788 DM_PAPERLENGTH | DM_PAPERWIDTH |
3789 DM_SCALE |
3790 DM_COPIES |
3791 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3792 DM_YRESOLUTION | DM_TTOPTION;
3794 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3795 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3796 dm.u1.s1.dmPaperLength = 2970;
3797 dm.u1.s1.dmPaperWidth = 2100;
3799 dm.u1.s1.dmScale = 100;
3800 dm.u1.s1.dmCopies = 1;
3801 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3802 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3803 /* dm.dmColor */
3804 /* dm.dmDuplex */
3805 dm.dmYResolution = 300; /* 300dpi */
3806 dm.dmTTOption = DMTT_BITMAP;
3807 /* dm.dmCollate */
3808 /* dm.dmFormName */
3809 /* dm.dmLogPixels */
3810 /* dm.dmBitsPerPel */
3811 /* dm.dmPelsWidth */
3812 /* dm.dmPelsHeight */
3813 /* dm.u2.dmDisplayFlags */
3814 /* dm.dmDisplayFrequency */
3815 /* dm.dmICMMethod */
3816 /* dm.dmICMIntent */
3817 /* dm.dmMediaType */
3818 /* dm.dmDitherType */
3819 /* dm.dmReserved1 */
3820 /* dm.dmReserved2 */
3821 /* dm.dmPanningWidth */
3822 /* dm.dmPanningHeight */
3824 if(unicode) {
3825 if(buflen >= sizeof(DEVMODEW)) {
3826 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3827 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3828 HeapFree(GetProcessHeap(),0,pdmW);
3830 *needed = sizeof(DEVMODEW);
3832 else
3834 if(buflen >= sizeof(DEVMODEA)) {
3835 memcpy(ptr, &dm, sizeof(DEVMODEA));
3837 *needed = sizeof(DEVMODEA);
3841 /*****************************************************************************
3842 * WINSPOOL_GetDevModeFromReg
3844 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3845 * DevMode is stored either as unicode or ascii.
3847 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3848 LPBYTE ptr,
3849 DWORD buflen, DWORD *needed,
3850 BOOL unicode)
3852 DWORD sz = buflen, type;
3853 LONG ret;
3855 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3856 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3857 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3858 if (sz < sizeof(DEVMODEA))
3860 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3861 return FALSE;
3863 /* ensures that dmSize is not erratically bogus if registry is invalid */
3864 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3865 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3866 if(unicode) {
3867 sz += (CCHDEVICENAME + CCHFORMNAME);
3868 if(buflen >= sz) {
3869 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3870 memcpy(ptr, dmW, sz);
3871 HeapFree(GetProcessHeap(),0,dmW);
3874 *needed = sz;
3875 return TRUE;
3878 /*********************************************************************
3879 * WINSPOOL_GetPrinter_1
3881 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3882 * The strings are either stored as unicode or ascii.
3884 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3885 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3886 BOOL unicode)
3888 DWORD size, left = cbBuf;
3889 BOOL space = (cbBuf > 0);
3890 LPBYTE ptr = buf;
3892 *pcbNeeded = 0;
3894 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3895 unicode)) {
3896 if(space && size <= left) {
3897 pi1->pName = (LPWSTR)ptr;
3898 ptr += size;
3899 left -= size;
3900 } else
3901 space = FALSE;
3902 *pcbNeeded += size;
3905 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3906 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3907 unicode)) {
3908 if(space && size <= left) {
3909 pi1->pDescription = (LPWSTR)ptr;
3910 ptr += size;
3911 left -= size;
3912 } else
3913 space = FALSE;
3914 *pcbNeeded += size;
3917 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3918 unicode)) {
3919 if(space && size <= left) {
3920 pi1->pComment = (LPWSTR)ptr;
3921 ptr += size;
3922 left -= size;
3923 } else
3924 space = FALSE;
3925 *pcbNeeded += size;
3928 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3930 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3931 memset(pi1, 0, sizeof(*pi1));
3933 return space;
3935 /*********************************************************************
3936 * WINSPOOL_GetPrinter_2
3938 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3939 * The strings are either stored as unicode or ascii.
3941 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3942 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3943 BOOL unicode)
3945 DWORD size, left = cbBuf;
3946 BOOL space = (cbBuf > 0);
3947 LPBYTE ptr = buf;
3949 *pcbNeeded = 0;
3951 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3952 unicode)) {
3953 if(space && size <= left) {
3954 pi2->pPrinterName = (LPWSTR)ptr;
3955 ptr += size;
3956 left -= size;
3957 } else
3958 space = FALSE;
3959 *pcbNeeded += size;
3961 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3962 unicode)) {
3963 if(space && size <= left) {
3964 pi2->pShareName = (LPWSTR)ptr;
3965 ptr += size;
3966 left -= size;
3967 } else
3968 space = FALSE;
3969 *pcbNeeded += size;
3971 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3972 unicode)) {
3973 if(space && size <= left) {
3974 pi2->pPortName = (LPWSTR)ptr;
3975 ptr += size;
3976 left -= size;
3977 } else
3978 space = FALSE;
3979 *pcbNeeded += size;
3981 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3982 &size, unicode)) {
3983 if(space && size <= left) {
3984 pi2->pDriverName = (LPWSTR)ptr;
3985 ptr += size;
3986 left -= size;
3987 } else
3988 space = FALSE;
3989 *pcbNeeded += size;
3991 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3992 unicode)) {
3993 if(space && size <= left) {
3994 pi2->pComment = (LPWSTR)ptr;
3995 ptr += size;
3996 left -= size;
3997 } else
3998 space = FALSE;
3999 *pcbNeeded += size;
4001 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
4002 unicode)) {
4003 if(space && size <= left) {
4004 pi2->pLocation = (LPWSTR)ptr;
4005 ptr += size;
4006 left -= size;
4007 } else
4008 space = FALSE;
4009 *pcbNeeded += size;
4011 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
4012 &size, unicode)) {
4013 if(space && size <= left) {
4014 pi2->pDevMode = (LPDEVMODEW)ptr;
4015 ptr += size;
4016 left -= size;
4017 } else
4018 space = FALSE;
4019 *pcbNeeded += size;
4021 else
4023 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
4024 if(space && size <= left) {
4025 pi2->pDevMode = (LPDEVMODEW)ptr;
4026 ptr += size;
4027 left -= size;
4028 } else
4029 space = FALSE;
4030 *pcbNeeded += size;
4032 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
4033 &size, unicode)) {
4034 if(space && size <= left) {
4035 pi2->pSepFile = (LPWSTR)ptr;
4036 ptr += size;
4037 left -= size;
4038 } else
4039 space = FALSE;
4040 *pcbNeeded += size;
4042 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
4043 &size, unicode)) {
4044 if(space && size <= left) {
4045 pi2->pPrintProcessor = (LPWSTR)ptr;
4046 ptr += size;
4047 left -= size;
4048 } else
4049 space = FALSE;
4050 *pcbNeeded += size;
4052 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
4053 &size, unicode)) {
4054 if(space && size <= left) {
4055 pi2->pDatatype = (LPWSTR)ptr;
4056 ptr += size;
4057 left -= size;
4058 } else
4059 space = FALSE;
4060 *pcbNeeded += size;
4062 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
4063 &size, unicode)) {
4064 if(space && size <= left) {
4065 pi2->pParameters = (LPWSTR)ptr;
4066 ptr += size;
4067 left -= size;
4068 } else
4069 space = FALSE;
4070 *pcbNeeded += size;
4072 if(pi2) {
4073 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4074 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
4075 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4076 "Default Priority");
4077 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
4078 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
4081 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4082 memset(pi2, 0, sizeof(*pi2));
4084 return space;
4087 /*********************************************************************
4088 * WINSPOOL_GetPrinter_4
4090 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4092 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4093 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4094 BOOL unicode)
4096 DWORD size, left = cbBuf;
4097 BOOL space = (cbBuf > 0);
4098 LPBYTE ptr = buf;
4100 *pcbNeeded = 0;
4102 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4103 unicode)) {
4104 if(space && size <= left) {
4105 pi4->pPrinterName = (LPWSTR)ptr;
4106 ptr += size;
4107 left -= size;
4108 } else
4109 space = FALSE;
4110 *pcbNeeded += size;
4112 if(pi4) {
4113 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4116 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4117 memset(pi4, 0, sizeof(*pi4));
4119 return space;
4122 /*********************************************************************
4123 * WINSPOOL_GetPrinter_5
4125 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4127 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4128 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4129 BOOL unicode)
4131 DWORD size, left = cbBuf;
4132 BOOL space = (cbBuf > 0);
4133 LPBYTE ptr = buf;
4135 *pcbNeeded = 0;
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4138 unicode)) {
4139 if(space && size <= left) {
4140 pi5->pPrinterName = (LPWSTR)ptr;
4141 ptr += size;
4142 left -= size;
4143 } else
4144 space = FALSE;
4145 *pcbNeeded += size;
4147 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4148 unicode)) {
4149 if(space && size <= left) {
4150 pi5->pPortName = (LPWSTR)ptr;
4151 ptr += size;
4152 left -= size;
4153 } else
4154 space = FALSE;
4155 *pcbNeeded += size;
4157 if(pi5) {
4158 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4159 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4160 "dnsTimeout");
4161 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4162 "txTimeout");
4165 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4166 memset(pi5, 0, sizeof(*pi5));
4168 return space;
4171 /*********************************************************************
4172 * WINSPOOL_GetPrinter_7
4174 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4176 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4177 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4179 DWORD size, left = cbBuf;
4180 BOOL space = (cbBuf > 0);
4181 LPBYTE ptr = buf;
4183 *pcbNeeded = 0;
4185 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4187 if (space && size <= left) {
4188 pi7->pszObjectGUID = (LPWSTR)ptr;
4189 ptr += size;
4190 left -= size;
4191 } else
4192 space = FALSE;
4193 *pcbNeeded += size;
4195 if (pi7) {
4196 /* We do not have a Directory Service */
4197 pi7->dwAction = DSPRINT_UNPUBLISH;
4200 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4201 memset(pi7, 0, sizeof(*pi7));
4203 return space;
4206 /*********************************************************************
4207 * WINSPOOL_GetPrinter_9
4209 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4210 * The strings are either stored as unicode or ascii.
4212 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4213 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4215 DWORD size;
4216 BOOL space = (cbBuf > 0);
4218 *pcbNeeded = 0;
4220 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4221 if(space && size <= cbBuf) {
4222 pi9->pDevMode = (LPDEVMODEW)buf;
4223 } else
4224 space = FALSE;
4225 *pcbNeeded += size;
4227 else
4229 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4230 if(space && size <= cbBuf) {
4231 pi9->pDevMode = (LPDEVMODEW)buf;
4232 } else
4233 space = FALSE;
4234 *pcbNeeded += size;
4237 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4238 memset(pi9, 0, sizeof(*pi9));
4240 return space;
4243 /*****************************************************************************
4244 * WINSPOOL_GetPrinter
4246 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4247 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4248 * just a collection of pointers to strings.
4250 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4251 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4253 LPCWSTR name;
4254 DWORD size, needed = 0;
4255 LPBYTE ptr = NULL;
4256 HKEY hkeyPrinter, hkeyPrinters;
4257 BOOL ret;
4259 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4261 if (!(name = get_opened_printer_name(hPrinter))) {
4262 SetLastError(ERROR_INVALID_HANDLE);
4263 return FALSE;
4266 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4267 ERROR_SUCCESS) {
4268 ERR("Can't create Printers key\n");
4269 return FALSE;
4271 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4273 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4274 RegCloseKey(hkeyPrinters);
4275 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4276 return FALSE;
4279 switch(Level) {
4280 case 2:
4282 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4284 size = sizeof(PRINTER_INFO_2W);
4285 if(size <= cbBuf) {
4286 ptr = pPrinter + size;
4287 cbBuf -= size;
4288 memset(pPrinter, 0, size);
4289 } else {
4290 pi2 = NULL;
4291 cbBuf = 0;
4293 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4294 unicode);
4295 needed += size;
4296 break;
4299 case 4:
4301 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4303 size = sizeof(PRINTER_INFO_4W);
4304 if(size <= cbBuf) {
4305 ptr = pPrinter + size;
4306 cbBuf -= size;
4307 memset(pPrinter, 0, size);
4308 } else {
4309 pi4 = NULL;
4310 cbBuf = 0;
4312 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4313 unicode);
4314 needed += size;
4315 break;
4319 case 5:
4321 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4323 size = sizeof(PRINTER_INFO_5W);
4324 if(size <= cbBuf) {
4325 ptr = pPrinter + size;
4326 cbBuf -= size;
4327 memset(pPrinter, 0, size);
4328 } else {
4329 pi5 = NULL;
4330 cbBuf = 0;
4333 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4334 unicode);
4335 needed += size;
4336 break;
4340 case 6:
4342 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4344 size = sizeof(PRINTER_INFO_6);
4345 if (size <= cbBuf) {
4346 /* FIXME: We do not update the status yet */
4347 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4348 ret = TRUE;
4349 } else {
4350 ret = FALSE;
4353 needed += size;
4354 break;
4357 case 7:
4359 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4361 size = sizeof(PRINTER_INFO_7W);
4362 if (size <= cbBuf) {
4363 ptr = pPrinter + size;
4364 cbBuf -= size;
4365 memset(pPrinter, 0, size);
4366 } else {
4367 pi7 = NULL;
4368 cbBuf = 0;
4371 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4372 needed += size;
4373 break;
4377 case 9:
4379 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4381 size = sizeof(PRINTER_INFO_9W);
4382 if(size <= cbBuf) {
4383 ptr = pPrinter + size;
4384 cbBuf -= size;
4385 memset(pPrinter, 0, size);
4386 } else {
4387 pi9 = NULL;
4388 cbBuf = 0;
4391 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4392 needed += size;
4393 break;
4397 default:
4398 FIXME("Unimplemented level %d\n", Level);
4399 SetLastError(ERROR_INVALID_LEVEL);
4400 RegCloseKey(hkeyPrinters);
4401 RegCloseKey(hkeyPrinter);
4402 return FALSE;
4405 RegCloseKey(hkeyPrinter);
4406 RegCloseKey(hkeyPrinters);
4408 TRACE("returning %d needed = %d\n", ret, needed);
4409 if(pcbNeeded) *pcbNeeded = needed;
4410 if(!ret)
4411 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4412 return ret;
4415 /*****************************************************************************
4416 * GetPrinterW [WINSPOOL.@]
4418 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4419 DWORD cbBuf, LPDWORD pcbNeeded)
4421 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4422 TRUE);
4425 /*****************************************************************************
4426 * GetPrinterA [WINSPOOL.@]
4428 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4429 DWORD cbBuf, LPDWORD pcbNeeded)
4431 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4432 FALSE);
4435 /*****************************************************************************
4436 * WINSPOOL_EnumPrinters
4438 * Implementation of EnumPrintersA|W
4440 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4441 DWORD dwLevel, LPBYTE lpbPrinters,
4442 DWORD cbBuf, LPDWORD lpdwNeeded,
4443 LPDWORD lpdwReturned, BOOL unicode)
4446 HKEY hkeyPrinters, hkeyPrinter;
4447 WCHAR PrinterName[255];
4448 DWORD needed = 0, number = 0;
4449 DWORD used, i, left;
4450 PBYTE pi, buf;
4452 if(lpbPrinters)
4453 memset(lpbPrinters, 0, cbBuf);
4454 if(lpdwReturned)
4455 *lpdwReturned = 0;
4456 if(lpdwNeeded)
4457 *lpdwNeeded = 0;
4459 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4460 if(dwType == PRINTER_ENUM_DEFAULT)
4461 return TRUE;
4463 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4464 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4465 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4466 if (!dwType) {
4467 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4468 *lpdwNeeded = 0;
4469 *lpdwReturned = 0;
4470 return TRUE;
4475 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4476 FIXME("dwType = %08x\n", dwType);
4477 SetLastError(ERROR_INVALID_FLAGS);
4478 return FALSE;
4481 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4482 ERROR_SUCCESS) {
4483 ERR("Can't create Printers key\n");
4484 return FALSE;
4487 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4488 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4489 RegCloseKey(hkeyPrinters);
4490 ERR("Can't query Printers key\n");
4491 return FALSE;
4493 TRACE("Found %d printers\n", number);
4495 switch(dwLevel) {
4496 case 1:
4497 used = number * sizeof(PRINTER_INFO_1W);
4498 break;
4499 case 2:
4500 used = number * sizeof(PRINTER_INFO_2W);
4501 break;
4502 case 4:
4503 used = number * sizeof(PRINTER_INFO_4W);
4504 break;
4505 case 5:
4506 used = number * sizeof(PRINTER_INFO_5W);
4507 break;
4509 default:
4510 SetLastError(ERROR_INVALID_LEVEL);
4511 RegCloseKey(hkeyPrinters);
4512 return FALSE;
4514 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4516 for(i = 0; i < number; i++) {
4517 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4518 ERROR_SUCCESS) {
4519 ERR("Can't enum key number %d\n", i);
4520 RegCloseKey(hkeyPrinters);
4521 return FALSE;
4523 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4524 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4525 ERROR_SUCCESS) {
4526 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4527 RegCloseKey(hkeyPrinters);
4528 return FALSE;
4531 if(cbBuf > used) {
4532 buf = lpbPrinters + used;
4533 left = cbBuf - used;
4534 } else {
4535 buf = NULL;
4536 left = 0;
4539 switch(dwLevel) {
4540 case 1:
4541 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4542 left, &needed, unicode);
4543 used += needed;
4544 if(pi) pi += sizeof(PRINTER_INFO_1W);
4545 break;
4546 case 2:
4547 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4548 left, &needed, unicode);
4549 used += needed;
4550 if(pi) pi += sizeof(PRINTER_INFO_2W);
4551 break;
4552 case 4:
4553 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4554 left, &needed, unicode);
4555 used += needed;
4556 if(pi) pi += sizeof(PRINTER_INFO_4W);
4557 break;
4558 case 5:
4559 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4560 left, &needed, unicode);
4561 used += needed;
4562 if(pi) pi += sizeof(PRINTER_INFO_5W);
4563 break;
4564 default:
4565 ERR("Shouldn't be here!\n");
4566 RegCloseKey(hkeyPrinter);
4567 RegCloseKey(hkeyPrinters);
4568 return FALSE;
4570 RegCloseKey(hkeyPrinter);
4572 RegCloseKey(hkeyPrinters);
4574 if(lpdwNeeded)
4575 *lpdwNeeded = used;
4577 if(used > cbBuf) {
4578 if(lpbPrinters)
4579 memset(lpbPrinters, 0, cbBuf);
4580 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4581 return FALSE;
4583 if(lpdwReturned)
4584 *lpdwReturned = number;
4585 SetLastError(ERROR_SUCCESS);
4586 return TRUE;
4590 /******************************************************************
4591 * EnumPrintersW [WINSPOOL.@]
4593 * Enumerates the available printers, print servers and print
4594 * providers, depending on the specified flags, name and level.
4596 * RETURNS:
4598 * If level is set to 1:
4599 * Returns an array of PRINTER_INFO_1 data structures in the
4600 * lpbPrinters buffer.
4602 * If level is set to 2:
4603 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4604 * Returns an array of PRINTER_INFO_2 data structures in the
4605 * lpbPrinters buffer. Note that according to MSDN also an
4606 * OpenPrinter should be performed on every remote printer.
4608 * If level is set to 4 (officially WinNT only):
4609 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4610 * Fast: Only the registry is queried to retrieve printer names,
4611 * no connection to the driver is made.
4612 * Returns an array of PRINTER_INFO_4 data structures in the
4613 * lpbPrinters buffer.
4615 * If level is set to 5 (officially WinNT4/Win9x only):
4616 * Fast: Only the registry is queried to retrieve printer names,
4617 * no connection to the driver is made.
4618 * Returns an array of PRINTER_INFO_5 data structures in the
4619 * lpbPrinters buffer.
4621 * If level set to 3 or 6+:
4622 * returns zero (failure!)
4624 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4625 * for information.
4627 * BUGS:
4628 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4629 * - Only levels 2, 4 and 5 are implemented at the moment.
4630 * - 16-bit printer drivers are not enumerated.
4631 * - Returned amount of bytes used/needed does not match the real Windoze
4632 * implementation (as in this implementation, all strings are part
4633 * of the buffer, whereas Win32 keeps them somewhere else)
4634 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4636 * NOTE:
4637 * - In a regular Wine installation, no registry settings for printers
4638 * exist, which makes this function return an empty list.
4640 BOOL WINAPI EnumPrintersW(
4641 DWORD dwType, /* [in] Types of print objects to enumerate */
4642 LPWSTR lpszName, /* [in] name of objects to enumerate */
4643 DWORD dwLevel, /* [in] type of printer info structure */
4644 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4645 DWORD cbBuf, /* [in] max size of buffer in bytes */
4646 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4647 LPDWORD lpdwReturned /* [out] number of entries returned */
4650 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4651 lpdwNeeded, lpdwReturned, TRUE);
4654 /******************************************************************
4655 * EnumPrintersA [WINSPOOL.@]
4657 * See EnumPrintersW
4660 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4661 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4663 BOOL ret;
4664 UNICODE_STRING pNameU;
4665 LPWSTR pNameW;
4666 LPBYTE pPrintersW;
4668 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4669 pPrinters, cbBuf, pcbNeeded, pcReturned);
4671 pNameW = asciitounicode(&pNameU, pName);
4673 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4674 MS Office need this */
4675 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4677 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4679 RtlFreeUnicodeString(&pNameU);
4680 if (ret) {
4681 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4683 HeapFree(GetProcessHeap(), 0, pPrintersW);
4684 return ret;
4687 /*****************************************************************************
4688 * WINSPOOL_GetDriverInfoFromReg [internal]
4690 * Enters the information from the registry into the DRIVER_INFO struct
4692 * RETURNS
4693 * zero if the printer driver does not exist in the registry
4694 * (only if Level > 1) otherwise nonzero
4696 static BOOL WINSPOOL_GetDriverInfoFromReg(
4697 HKEY hkeyDrivers,
4698 LPWSTR DriverName,
4699 const printenv_t * env,
4700 DWORD Level,
4701 LPBYTE ptr, /* DRIVER_INFO */
4702 LPBYTE pDriverStrings, /* strings buffer */
4703 DWORD cbBuf, /* size of string buffer */
4704 LPDWORD pcbNeeded, /* space needed for str. */
4705 BOOL unicode) /* type of strings */
4707 DWORD size, tmp;
4708 HKEY hkeyDriver;
4709 WCHAR driverdir[MAX_PATH];
4710 DWORD dirlen;
4711 LPBYTE strPtr = pDriverStrings;
4712 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4714 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4715 debugstr_w(DriverName), env,
4716 Level, di, pDriverStrings, cbBuf, unicode);
4718 if (di) ZeroMemory(di, di_sizeof[Level]);
4720 if (unicode) {
4721 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4722 if (*pcbNeeded <= cbBuf)
4723 strcpyW((LPWSTR)strPtr, DriverName);
4725 else
4727 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4728 if (*pcbNeeded <= cbBuf)
4729 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4732 /* pName for level 1 has a different offset! */
4733 if (Level == 1) {
4734 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4735 return TRUE;
4738 /* .cVersion and .pName for level > 1 */
4739 if (di) {
4740 di->cVersion = env->driverversion;
4741 di->pName = (LPWSTR) strPtr;
4742 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4745 /* Reserve Space for the largest subdir and a Backslash*/
4746 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4747 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4748 /* Should never Fail */
4749 return FALSE;
4751 lstrcatW(driverdir, env->versionsubdir);
4752 lstrcatW(driverdir, backslashW);
4754 /* dirlen must not include the terminating zero */
4755 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4756 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4758 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4759 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4760 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4761 return FALSE;
4764 /* pEnvironment */
4765 if (unicode)
4766 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4767 else
4768 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4770 *pcbNeeded += size;
4771 if (*pcbNeeded <= cbBuf) {
4772 if (unicode) {
4773 lstrcpyW((LPWSTR)strPtr, env->envname);
4775 else
4777 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4779 if (di) di->pEnvironment = (LPWSTR)strPtr;
4780 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4783 /* .pDriverPath is the Graphics rendering engine.
4784 The full Path is required to avoid a crash in some apps */
4785 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4786 *pcbNeeded += size;
4787 if (*pcbNeeded <= cbBuf)
4788 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4790 if (di) di->pDriverPath = (LPWSTR)strPtr;
4791 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4794 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4795 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4796 *pcbNeeded += size;
4797 if (*pcbNeeded <= cbBuf)
4798 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4800 if (di) di->pDataFile = (LPWSTR)strPtr;
4801 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4804 /* .pConfigFile is the Driver user Interface */
4805 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4806 *pcbNeeded += size;
4807 if (*pcbNeeded <= cbBuf)
4808 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4810 if (di) di->pConfigFile = (LPWSTR)strPtr;
4811 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4814 if (Level == 2 ) {
4815 RegCloseKey(hkeyDriver);
4816 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4817 return TRUE;
4820 if (Level == 5 ) {
4821 RegCloseKey(hkeyDriver);
4822 FIXME("level 5: incomplete\n");
4823 return TRUE;
4826 /* .pHelpFile */
4827 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4828 *pcbNeeded += size;
4829 if (*pcbNeeded <= cbBuf)
4830 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4832 if (di) di->pHelpFile = (LPWSTR)strPtr;
4833 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4836 /* .pDependentFiles */
4837 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4838 *pcbNeeded += size;
4839 if (*pcbNeeded <= cbBuf)
4840 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4842 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4843 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4845 else if (GetVersion() & 0x80000000) {
4846 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4847 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4848 *pcbNeeded += size;
4849 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4851 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4852 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4855 /* .pMonitorName is the optional Language Monitor */
4856 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4857 *pcbNeeded += size;
4858 if (*pcbNeeded <= cbBuf)
4859 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4861 if (di) di->pMonitorName = (LPWSTR)strPtr;
4862 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4865 /* .pDefaultDataType */
4866 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4867 *pcbNeeded += size;
4868 if(*pcbNeeded <= cbBuf)
4869 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4871 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4872 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4875 if (Level == 3 ) {
4876 RegCloseKey(hkeyDriver);
4877 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4878 return TRUE;
4881 /* .pszzPreviousNames */
4882 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4883 *pcbNeeded += size;
4884 if(*pcbNeeded <= cbBuf)
4885 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4887 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4888 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4891 if (Level == 4 ) {
4892 RegCloseKey(hkeyDriver);
4893 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4894 return TRUE;
4897 /* support is missing, but not important enough for a FIXME */
4898 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4900 /* .pszMfgName */
4901 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4902 *pcbNeeded += size;
4903 if(*pcbNeeded <= cbBuf)
4904 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4906 if (di) di->pszMfgName = (LPWSTR)strPtr;
4907 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4910 /* .pszOEMUrl */
4911 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4912 *pcbNeeded += size;
4913 if(*pcbNeeded <= cbBuf)
4914 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4916 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4917 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4920 /* .pszHardwareID */
4921 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4922 *pcbNeeded += size;
4923 if(*pcbNeeded <= cbBuf)
4924 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4926 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4927 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4930 /* .pszProvider */
4931 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4932 *pcbNeeded += size;
4933 if(*pcbNeeded <= cbBuf)
4934 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4936 if (di) di->pszProvider = (LPWSTR)strPtr;
4937 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4940 if (Level == 6 ) {
4941 RegCloseKey(hkeyDriver);
4942 return TRUE;
4945 /* support is missing, but not important enough for a FIXME */
4946 TRACE("level 8: incomplete\n");
4948 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4949 RegCloseKey(hkeyDriver);
4950 return TRUE;
4953 /*****************************************************************************
4954 * WINSPOOL_GetPrinterDriver
4956 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4957 DWORD Level, LPBYTE pDriverInfo,
4958 DWORD cbBuf, LPDWORD pcbNeeded,
4959 BOOL unicode)
4961 LPCWSTR name;
4962 WCHAR DriverName[100];
4963 DWORD ret, type, size, needed = 0;
4964 LPBYTE ptr = NULL;
4965 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4966 const printenv_t * env;
4968 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4969 Level,pDriverInfo,cbBuf, pcbNeeded);
4972 if (!(name = get_opened_printer_name(hPrinter))) {
4973 SetLastError(ERROR_INVALID_HANDLE);
4974 return FALSE;
4977 if (Level < 1 || Level == 7 || Level > 8) {
4978 SetLastError(ERROR_INVALID_LEVEL);
4979 return FALSE;
4982 env = validate_envW(pEnvironment);
4983 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4985 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4986 ERROR_SUCCESS) {
4987 ERR("Can't create Printers key\n");
4988 return FALSE;
4990 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4991 != ERROR_SUCCESS) {
4992 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4993 RegCloseKey(hkeyPrinters);
4994 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4995 return FALSE;
4997 size = sizeof(DriverName);
4998 DriverName[0] = 0;
4999 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5000 (LPBYTE)DriverName, &size);
5001 RegCloseKey(hkeyPrinter);
5002 RegCloseKey(hkeyPrinters);
5003 if(ret != ERROR_SUCCESS) {
5004 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5005 return FALSE;
5008 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
5009 if(!hkeyDrivers) {
5010 ERR("Can't create Drivers key\n");
5011 return FALSE;
5014 size = di_sizeof[Level];
5015 if ((size <= cbBuf) && pDriverInfo)
5016 ptr = pDriverInfo + size;
5018 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5019 env, Level, pDriverInfo, ptr,
5020 (cbBuf < size) ? 0 : cbBuf - size,
5021 &needed, unicode)) {
5022 RegCloseKey(hkeyDrivers);
5023 return FALSE;
5026 RegCloseKey(hkeyDrivers);
5028 if(pcbNeeded) *pcbNeeded = size + needed;
5029 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5030 if(cbBuf >= needed) return TRUE;
5031 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5032 return FALSE;
5035 /*****************************************************************************
5036 * GetPrinterDriverA [WINSPOOL.@]
5038 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5039 DWORD Level, LPBYTE pDriverInfo,
5040 DWORD cbBuf, LPDWORD pcbNeeded)
5042 BOOL ret;
5043 UNICODE_STRING pEnvW;
5044 PWSTR pwstrEnvW;
5046 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5047 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
5048 cbBuf, pcbNeeded, FALSE);
5049 RtlFreeUnicodeString(&pEnvW);
5050 return ret;
5052 /*****************************************************************************
5053 * GetPrinterDriverW [WINSPOOL.@]
5055 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5056 DWORD Level, LPBYTE pDriverInfo,
5057 DWORD cbBuf, LPDWORD pcbNeeded)
5059 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
5060 pDriverInfo, cbBuf, pcbNeeded, TRUE);
5063 /*****************************************************************************
5064 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5066 * Return the PATH for the Printer-Drivers (UNICODE)
5068 * PARAMS
5069 * pName [I] Servername (NT only) or NULL (local Computer)
5070 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5071 * Level [I] Structure-Level (must be 1)
5072 * pDriverDirectory [O] PTR to Buffer that receives the Result
5073 * cbBuf [I] Size of Buffer at pDriverDirectory
5074 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5075 * required for pDriverDirectory
5077 * RETURNS
5078 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5079 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5080 * if cbBuf is too small
5082 * Native Values returned in pDriverDirectory on Success:
5083 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5084 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5085 *| win9x(Windows 4.0): "%winsysdir%"
5087 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5089 * FIXME
5090 *- Only NULL or "" is supported for pName
5093 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5094 DWORD Level, LPBYTE pDriverDirectory,
5095 DWORD cbBuf, LPDWORD pcbNeeded)
5097 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5098 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5100 if ((backend == NULL) && !load_backend()) return FALSE;
5102 if (Level != 1) {
5103 /* (Level != 1) is ignored in win9x */
5104 SetLastError(ERROR_INVALID_LEVEL);
5105 return FALSE;
5107 if (pcbNeeded == NULL) {
5108 /* (pcbNeeded == NULL) is ignored in win9x */
5109 SetLastError(RPC_X_NULL_REF_POINTER);
5110 return FALSE;
5113 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5114 pDriverDirectory, cbBuf, pcbNeeded);
5119 /*****************************************************************************
5120 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5122 * Return the PATH for the Printer-Drivers (ANSI)
5124 * See GetPrinterDriverDirectoryW.
5126 * NOTES
5127 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5130 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5131 DWORD Level, LPBYTE pDriverDirectory,
5132 DWORD cbBuf, LPDWORD pcbNeeded)
5134 UNICODE_STRING nameW, environmentW;
5135 BOOL ret;
5136 DWORD pcbNeededW;
5137 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5138 WCHAR *driverDirectoryW = NULL;
5140 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5141 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5143 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5145 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5146 else nameW.Buffer = NULL;
5147 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5148 else environmentW.Buffer = NULL;
5150 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5151 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5152 if (ret) {
5153 DWORD needed;
5154 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5155 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5156 if(pcbNeeded)
5157 *pcbNeeded = needed;
5158 ret = (needed <= cbBuf) ? TRUE : FALSE;
5159 } else
5160 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5162 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5164 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5165 RtlFreeUnicodeString(&environmentW);
5166 RtlFreeUnicodeString(&nameW);
5168 return ret;
5171 /*****************************************************************************
5172 * AddPrinterDriverA [WINSPOOL.@]
5174 * See AddPrinterDriverW.
5177 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5179 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5180 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5183 /******************************************************************************
5184 * AddPrinterDriverW (WINSPOOL.@)
5186 * Install a Printer Driver
5188 * PARAMS
5189 * pName [I] Servername or NULL (local Computer)
5190 * level [I] Level for the supplied DRIVER_INFO_*W struct
5191 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5193 * RESULTS
5194 * Success: TRUE
5195 * Failure: FALSE
5198 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5200 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5201 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5204 /*****************************************************************************
5205 * AddPrintProcessorA [WINSPOOL.@]
5207 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5208 LPSTR pPrintProcessorName)
5210 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5211 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5212 return FALSE;
5215 /*****************************************************************************
5216 * AddPrintProcessorW [WINSPOOL.@]
5218 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5219 LPWSTR pPrintProcessorName)
5221 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5222 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5223 return FALSE;
5226 /*****************************************************************************
5227 * AddPrintProvidorA [WINSPOOL.@]
5229 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5231 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5232 return FALSE;
5235 /*****************************************************************************
5236 * AddPrintProvidorW [WINSPOOL.@]
5238 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5240 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5241 return FALSE;
5244 /*****************************************************************************
5245 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5247 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5248 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5250 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5251 pDevModeOutput, pDevModeInput);
5252 return 0;
5255 /*****************************************************************************
5256 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5258 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5259 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5261 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5262 pDevModeOutput, pDevModeInput);
5263 return 0;
5266 /*****************************************************************************
5267 * PrinterProperties [WINSPOOL.@]
5269 * Displays a dialog to set the properties of the printer.
5271 * RETURNS
5272 * nonzero on success or zero on failure
5274 * BUGS
5275 * implemented as stub only
5277 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5278 HANDLE hPrinter /* [in] handle to printer object */
5280 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5281 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5282 return FALSE;
5285 /*****************************************************************************
5286 * EnumJobsA [WINSPOOL.@]
5289 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5290 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5291 LPDWORD pcReturned)
5293 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5294 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5296 if(pcbNeeded) *pcbNeeded = 0;
5297 if(pcReturned) *pcReturned = 0;
5298 return FALSE;
5302 /*****************************************************************************
5303 * EnumJobsW [WINSPOOL.@]
5306 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5307 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5308 LPDWORD pcReturned)
5310 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5311 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5313 if(pcbNeeded) *pcbNeeded = 0;
5314 if(pcReturned) *pcReturned = 0;
5315 return FALSE;
5318 /*****************************************************************************
5319 * WINSPOOL_EnumPrinterDrivers [internal]
5321 * Delivers information about all printer drivers installed on the
5322 * localhost or a given server
5324 * RETURNS
5325 * nonzero on success or zero on failure. If the buffer for the returned
5326 * information is too small the function will return an error
5328 * BUGS
5329 * - only implemented for localhost, foreign hosts will return an error
5331 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5332 DWORD Level, LPBYTE pDriverInfo,
5333 DWORD cbBuf, LPDWORD pcbNeeded,
5334 LPDWORD pcReturned, BOOL unicode)
5336 { HKEY hkeyDrivers;
5337 DWORD i, needed, number = 0, size = 0;
5338 WCHAR DriverNameW[255];
5339 PBYTE ptr;
5340 const printenv_t * env;
5342 TRACE("%s,%s,%d,%p,%d,%d\n",
5343 debugstr_w(pName), debugstr_w(pEnvironment),
5344 Level, pDriverInfo, cbBuf, unicode);
5346 /* check for local drivers */
5347 if((pName) && (pName[0])) {
5348 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5349 SetLastError(ERROR_ACCESS_DENIED);
5350 return FALSE;
5353 env = validate_envW(pEnvironment);
5354 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5356 /* check input parameter */
5357 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5358 SetLastError(ERROR_INVALID_LEVEL);
5359 return FALSE;
5362 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5363 SetLastError(RPC_X_NULL_REF_POINTER);
5364 return FALSE;
5367 /* initialize return values */
5368 if(pDriverInfo)
5369 memset( pDriverInfo, 0, cbBuf);
5370 *pcbNeeded = 0;
5371 *pcReturned = 0;
5373 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5374 if(!hkeyDrivers) {
5375 ERR("Can't open Drivers key\n");
5376 return FALSE;
5379 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5380 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5381 RegCloseKey(hkeyDrivers);
5382 ERR("Can't query Drivers key\n");
5383 return FALSE;
5385 TRACE("Found %d Drivers\n", number);
5387 /* get size of single struct
5388 * unicode and ascii structure have the same size
5390 size = di_sizeof[Level];
5392 /* calculate required buffer size */
5393 *pcbNeeded = size * number;
5395 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5396 i < number;
5397 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5398 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5399 != ERROR_SUCCESS) {
5400 ERR("Can't enum key number %d\n", i);
5401 RegCloseKey(hkeyDrivers);
5402 return FALSE;
5404 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5405 env, Level, ptr,
5406 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5407 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5408 &needed, unicode)) {
5409 RegCloseKey(hkeyDrivers);
5410 return FALSE;
5412 (*pcbNeeded) += needed;
5415 RegCloseKey(hkeyDrivers);
5417 if(cbBuf < *pcbNeeded){
5418 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5419 return FALSE;
5422 *pcReturned = number;
5423 return TRUE;
5426 /*****************************************************************************
5427 * EnumPrinterDriversW [WINSPOOL.@]
5429 * see function EnumPrinterDrivers for RETURNS, BUGS
5431 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5432 LPBYTE pDriverInfo, DWORD cbBuf,
5433 LPDWORD pcbNeeded, LPDWORD pcReturned)
5435 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5436 cbBuf, pcbNeeded, pcReturned, TRUE);
5439 /*****************************************************************************
5440 * EnumPrinterDriversA [WINSPOOL.@]
5442 * see function EnumPrinterDrivers for RETURNS, BUGS
5444 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5445 LPBYTE pDriverInfo, DWORD cbBuf,
5446 LPDWORD pcbNeeded, LPDWORD pcReturned)
5447 { BOOL ret;
5448 UNICODE_STRING pNameW, pEnvironmentW;
5449 PWSTR pwstrNameW, pwstrEnvironmentW;
5451 pwstrNameW = asciitounicode(&pNameW, pName);
5452 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5454 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5455 Level, pDriverInfo, cbBuf, pcbNeeded,
5456 pcReturned, FALSE);
5457 RtlFreeUnicodeString(&pNameW);
5458 RtlFreeUnicodeString(&pEnvironmentW);
5460 return ret;
5463 /******************************************************************************
5464 * EnumPortsA (WINSPOOL.@)
5466 * See EnumPortsW.
5469 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5470 LPDWORD pcbNeeded, LPDWORD pcReturned)
5472 BOOL res;
5473 LPBYTE bufferW = NULL;
5474 LPWSTR nameW = NULL;
5475 DWORD needed = 0;
5476 DWORD numentries = 0;
5477 INT len;
5479 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5480 cbBuf, pcbNeeded, pcReturned);
5482 /* convert servername to unicode */
5483 if (pName) {
5484 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5485 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5486 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5488 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5489 needed = cbBuf * sizeof(WCHAR);
5490 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5491 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5493 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5494 if (pcbNeeded) needed = *pcbNeeded;
5495 /* HeapReAlloc return NULL, when bufferW was NULL */
5496 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5497 HeapAlloc(GetProcessHeap(), 0, needed);
5499 /* Try again with the large Buffer */
5500 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5502 needed = pcbNeeded ? *pcbNeeded : 0;
5503 numentries = pcReturned ? *pcReturned : 0;
5506 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5507 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5509 if (res) {
5510 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5511 DWORD entrysize = 0;
5512 DWORD index;
5513 LPSTR ptr;
5514 LPPORT_INFO_2W pi2w;
5515 LPPORT_INFO_2A pi2a;
5517 needed = 0;
5518 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5520 /* First pass: calculate the size for all Entries */
5521 pi2w = (LPPORT_INFO_2W) bufferW;
5522 pi2a = (LPPORT_INFO_2A) pPorts;
5523 index = 0;
5524 while (index < numentries) {
5525 index++;
5526 needed += entrysize; /* PORT_INFO_?A */
5527 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5529 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5530 NULL, 0, NULL, NULL);
5531 if (Level > 1) {
5532 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5533 NULL, 0, NULL, NULL);
5534 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5535 NULL, 0, NULL, NULL);
5537 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5538 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5539 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5542 /* check for errors and quit on failure */
5543 if (cbBuf < needed) {
5544 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5545 res = FALSE;
5546 goto cleanup;
5548 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5549 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5550 cbBuf -= len ; /* free Bytes in the user-Buffer */
5551 pi2w = (LPPORT_INFO_2W) bufferW;
5552 pi2a = (LPPORT_INFO_2A) pPorts;
5553 index = 0;
5554 /* Second Pass: Fill the User Buffer (if we have one) */
5555 while ((index < numentries) && pPorts) {
5556 index++;
5557 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5558 pi2a->pPortName = ptr;
5559 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5560 ptr, cbBuf , NULL, NULL);
5561 ptr += len;
5562 cbBuf -= len;
5563 if (Level > 1) {
5564 pi2a->pMonitorName = ptr;
5565 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5566 ptr, cbBuf, NULL, NULL);
5567 ptr += len;
5568 cbBuf -= len;
5570 pi2a->pDescription = ptr;
5571 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5572 ptr, cbBuf, NULL, NULL);
5573 ptr += len;
5574 cbBuf -= len;
5576 pi2a->fPortType = pi2w->fPortType;
5577 pi2a->Reserved = 0; /* documented: "must be zero" */
5580 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5581 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5582 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5586 cleanup:
5587 if (pcbNeeded) *pcbNeeded = needed;
5588 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5590 HeapFree(GetProcessHeap(), 0, nameW);
5591 HeapFree(GetProcessHeap(), 0, bufferW);
5593 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5594 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5596 return (res);
5600 /******************************************************************************
5601 * EnumPortsW (WINSPOOL.@)
5603 * Enumerate available Ports
5605 * PARAMS
5606 * name [I] Servername or NULL (local Computer)
5607 * level [I] Structure-Level (1 or 2)
5608 * buffer [O] PTR to Buffer that receives the Result
5609 * bufsize [I] Size of Buffer at buffer
5610 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5611 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5613 * RETURNS
5614 * Success: TRUE
5615 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5619 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5621 DWORD needed = 0;
5622 DWORD numentries = 0;
5623 BOOL res = FALSE;
5625 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5626 cbBuf, pcbNeeded, pcReturned);
5628 if (pName && (pName[0])) {
5629 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5630 SetLastError(ERROR_ACCESS_DENIED);
5631 goto emP_cleanup;
5634 /* Level is not checked in win9x */
5635 if (!Level || (Level > 2)) {
5636 WARN("level (%d) is ignored in win9x\n", Level);
5637 SetLastError(ERROR_INVALID_LEVEL);
5638 goto emP_cleanup;
5640 if (!pcbNeeded) {
5641 SetLastError(RPC_X_NULL_REF_POINTER);
5642 goto emP_cleanup;
5645 EnterCriticalSection(&monitor_handles_cs);
5646 monitor_loadall();
5648 /* Scan all local Ports */
5649 numentries = 0;
5650 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5652 /* we calculated the needed buffersize. now do the error-checks */
5653 if (cbBuf < needed) {
5654 monitor_unloadall();
5655 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5656 goto emP_cleanup_cs;
5658 else if (!pPorts || !pcReturned) {
5659 monitor_unloadall();
5660 SetLastError(RPC_X_NULL_REF_POINTER);
5661 goto emP_cleanup_cs;
5664 /* Fill the Buffer */
5665 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5666 res = TRUE;
5667 monitor_unloadall();
5669 emP_cleanup_cs:
5670 LeaveCriticalSection(&monitor_handles_cs);
5672 emP_cleanup:
5673 if (pcbNeeded) *pcbNeeded = needed;
5674 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5676 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5677 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5679 return (res);
5682 /******************************************************************************
5683 * GetDefaultPrinterW (WINSPOOL.@)
5685 * FIXME
5686 * This function must read the value from data 'device' of key
5687 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5689 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5691 BOOL retval = TRUE;
5692 DWORD insize, len;
5693 WCHAR *buffer, *ptr;
5695 if (!namesize)
5697 SetLastError(ERROR_INVALID_PARAMETER);
5698 return FALSE;
5701 /* make the buffer big enough for the stuff from the profile/registry,
5702 * the content must fit into the local buffer to compute the correct
5703 * size even if the extern buffer is too small or not given.
5704 * (20 for ,driver,port) */
5705 insize = *namesize;
5706 len = max(100, (insize + 20));
5707 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5709 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5711 SetLastError (ERROR_FILE_NOT_FOUND);
5712 retval = FALSE;
5713 goto end;
5715 TRACE("%s\n", debugstr_w(buffer));
5717 if ((ptr = strchrW(buffer, ',')) == NULL)
5719 SetLastError(ERROR_INVALID_NAME);
5720 retval = FALSE;
5721 goto end;
5724 *ptr = 0;
5725 *namesize = strlenW(buffer) + 1;
5726 if(!name || (*namesize > insize))
5728 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5729 retval = FALSE;
5730 goto end;
5732 strcpyW(name, buffer);
5734 end:
5735 HeapFree( GetProcessHeap(), 0, buffer);
5736 return retval;
5740 /******************************************************************************
5741 * GetDefaultPrinterA (WINSPOOL.@)
5743 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5745 BOOL retval = TRUE;
5746 DWORD insize = 0;
5747 WCHAR *bufferW = NULL;
5749 if (!namesize)
5751 SetLastError(ERROR_INVALID_PARAMETER);
5752 return FALSE;
5755 if(name && *namesize) {
5756 insize = *namesize;
5757 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5760 if(!GetDefaultPrinterW( bufferW, namesize)) {
5761 retval = FALSE;
5762 goto end;
5765 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5766 NULL, NULL);
5767 if (!*namesize)
5769 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5770 retval = FALSE;
5772 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5774 end:
5775 HeapFree( GetProcessHeap(), 0, bufferW);
5776 return retval;
5780 /******************************************************************************
5781 * SetDefaultPrinterW (WINSPOOL.204)
5783 * Set the Name of the Default Printer
5785 * PARAMS
5786 * pszPrinter [I] Name of the Printer or NULL
5788 * RETURNS
5789 * Success: True
5790 * Failure: FALSE
5792 * NOTES
5793 * When the Parameter is NULL or points to an Empty String and
5794 * a Default Printer was already present, then this Function changes nothing.
5795 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5796 * the First enumerated local Printer is used.
5799 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5802 TRACE("(%s)\n", debugstr_w(pszPrinter));
5804 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5805 return FALSE;
5808 /******************************************************************************
5809 * SetDefaultPrinterA (WINSPOOL.202)
5811 * See SetDefaultPrinterW.
5814 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5817 TRACE("(%s)\n", debugstr_a(pszPrinter));
5819 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5820 return FALSE;
5824 /******************************************************************************
5825 * SetPrinterDataExA (WINSPOOL.@)
5827 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5828 LPCSTR pValueName, DWORD Type,
5829 LPBYTE pData, DWORD cbData)
5831 HKEY hkeyPrinter, hkeySubkey;
5832 DWORD ret;
5834 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5835 debugstr_a(pValueName), Type, pData, cbData);
5837 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5838 != ERROR_SUCCESS)
5839 return ret;
5841 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5842 != ERROR_SUCCESS) {
5843 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5844 RegCloseKey(hkeyPrinter);
5845 return ret;
5847 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5848 RegCloseKey(hkeySubkey);
5849 RegCloseKey(hkeyPrinter);
5850 return ret;
5853 /******************************************************************************
5854 * SetPrinterDataExW (WINSPOOL.@)
5856 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5857 LPCWSTR pValueName, DWORD Type,
5858 LPBYTE pData, DWORD cbData)
5860 HKEY hkeyPrinter, hkeySubkey;
5861 DWORD ret;
5863 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5864 debugstr_w(pValueName), Type, pData, cbData);
5866 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5867 != ERROR_SUCCESS)
5868 return ret;
5870 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5871 != ERROR_SUCCESS) {
5872 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5873 RegCloseKey(hkeyPrinter);
5874 return ret;
5876 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5877 RegCloseKey(hkeySubkey);
5878 RegCloseKey(hkeyPrinter);
5879 return ret;
5882 /******************************************************************************
5883 * SetPrinterDataA (WINSPOOL.@)
5885 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5886 LPBYTE pData, DWORD cbData)
5888 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5889 pData, cbData);
5892 /******************************************************************************
5893 * SetPrinterDataW (WINSPOOL.@)
5895 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5896 LPBYTE pData, DWORD cbData)
5898 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5899 pData, cbData);
5902 /******************************************************************************
5903 * GetPrinterDataExA (WINSPOOL.@)
5905 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5906 LPCSTR pValueName, LPDWORD pType,
5907 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5909 HKEY hkeyPrinter, hkeySubkey;
5910 DWORD ret;
5912 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5913 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5914 pcbNeeded);
5916 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5917 != ERROR_SUCCESS)
5918 return ret;
5920 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5921 != ERROR_SUCCESS) {
5922 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5923 RegCloseKey(hkeyPrinter);
5924 return ret;
5926 *pcbNeeded = nSize;
5927 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5928 RegCloseKey(hkeySubkey);
5929 RegCloseKey(hkeyPrinter);
5930 return ret;
5933 /******************************************************************************
5934 * GetPrinterDataExW (WINSPOOL.@)
5936 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5937 LPCWSTR pValueName, LPDWORD pType,
5938 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5940 HKEY hkeyPrinter, hkeySubkey;
5941 DWORD ret;
5943 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5944 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5945 pcbNeeded);
5947 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5948 != ERROR_SUCCESS)
5949 return ret;
5951 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5952 != ERROR_SUCCESS) {
5953 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5954 RegCloseKey(hkeyPrinter);
5955 return ret;
5957 *pcbNeeded = nSize;
5958 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5959 RegCloseKey(hkeySubkey);
5960 RegCloseKey(hkeyPrinter);
5961 return ret;
5964 /******************************************************************************
5965 * GetPrinterDataA (WINSPOOL.@)
5967 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5968 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5970 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5971 pData, nSize, pcbNeeded);
5974 /******************************************************************************
5975 * GetPrinterDataW (WINSPOOL.@)
5977 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5978 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5980 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5981 pData, nSize, pcbNeeded);
5984 /*******************************************************************************
5985 * EnumPrinterDataExW [WINSPOOL.@]
5987 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5988 LPBYTE pEnumValues, DWORD cbEnumValues,
5989 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5991 HKEY hkPrinter, hkSubKey;
5992 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5993 cbValueNameLen, cbMaxValueLen, cbValueLen,
5994 cbBufSize, dwType;
5995 LPWSTR lpValueName;
5996 HANDLE hHeap;
5997 PBYTE lpValue;
5998 PPRINTER_ENUM_VALUESW ppev;
6000 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6002 if (pKeyName == NULL || *pKeyName == 0)
6003 return ERROR_INVALID_PARAMETER;
6005 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6006 if (ret != ERROR_SUCCESS)
6008 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6009 hPrinter, ret);
6010 return ret;
6013 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6014 if (ret != ERROR_SUCCESS)
6016 r = RegCloseKey (hkPrinter);
6017 if (r != ERROR_SUCCESS)
6018 WARN ("RegCloseKey returned %i\n", r);
6019 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6020 debugstr_w (pKeyName), ret);
6021 return ret;
6024 ret = RegCloseKey (hkPrinter);
6025 if (ret != ERROR_SUCCESS)
6027 ERR ("RegCloseKey returned %i\n", ret);
6028 r = RegCloseKey (hkSubKey);
6029 if (r != ERROR_SUCCESS)
6030 WARN ("RegCloseKey returned %i\n", r);
6031 return ret;
6034 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6035 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6036 if (ret != ERROR_SUCCESS)
6038 r = RegCloseKey (hkSubKey);
6039 if (r != ERROR_SUCCESS)
6040 WARN ("RegCloseKey returned %i\n", r);
6041 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6042 return ret;
6045 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6046 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6048 if (cValues == 0) /* empty key */
6050 r = RegCloseKey (hkSubKey);
6051 if (r != ERROR_SUCCESS)
6052 WARN ("RegCloseKey returned %i\n", r);
6053 *pcbEnumValues = *pnEnumValues = 0;
6054 return ERROR_SUCCESS;
6057 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6059 hHeap = GetProcessHeap ();
6060 if (hHeap == NULL)
6062 ERR ("GetProcessHeap failed\n");
6063 r = RegCloseKey (hkSubKey);
6064 if (r != ERROR_SUCCESS)
6065 WARN ("RegCloseKey returned %i\n", r);
6066 return ERROR_OUTOFMEMORY;
6069 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6070 if (lpValueName == NULL)
6072 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6073 r = RegCloseKey (hkSubKey);
6074 if (r != ERROR_SUCCESS)
6075 WARN ("RegCloseKey returned %i\n", r);
6076 return ERROR_OUTOFMEMORY;
6079 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6080 if (lpValue == NULL)
6082 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6083 if (HeapFree (hHeap, 0, lpValueName) == 0)
6084 WARN ("HeapFree failed with code %i\n", GetLastError ());
6085 r = RegCloseKey (hkSubKey);
6086 if (r != ERROR_SUCCESS)
6087 WARN ("RegCloseKey returned %i\n", r);
6088 return ERROR_OUTOFMEMORY;
6091 TRACE ("pass 1: calculating buffer required for all names and values\n");
6093 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6095 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6097 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6099 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6100 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6101 NULL, NULL, lpValue, &cbValueLen);
6102 if (ret != ERROR_SUCCESS)
6104 if (HeapFree (hHeap, 0, lpValue) == 0)
6105 WARN ("HeapFree failed with code %i\n", GetLastError ());
6106 if (HeapFree (hHeap, 0, lpValueName) == 0)
6107 WARN ("HeapFree failed with code %i\n", GetLastError ());
6108 r = RegCloseKey (hkSubKey);
6109 if (r != ERROR_SUCCESS)
6110 WARN ("RegCloseKey returned %i\n", r);
6111 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6112 return ret;
6115 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6116 debugstr_w (lpValueName), dwIndex,
6117 cbValueNameLen + 1, cbValueLen);
6119 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6120 cbBufSize += cbValueLen;
6123 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6125 *pcbEnumValues = cbBufSize;
6126 *pnEnumValues = cValues;
6128 if (cbEnumValues < cbBufSize) /* buffer too small */
6130 if (HeapFree (hHeap, 0, lpValue) == 0)
6131 WARN ("HeapFree failed with code %i\n", GetLastError ());
6132 if (HeapFree (hHeap, 0, lpValueName) == 0)
6133 WARN ("HeapFree failed with code %i\n", GetLastError ());
6134 r = RegCloseKey (hkSubKey);
6135 if (r != ERROR_SUCCESS)
6136 WARN ("RegCloseKey returned %i\n", r);
6137 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6138 return ERROR_MORE_DATA;
6141 TRACE ("pass 2: copying all names and values to buffer\n");
6143 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6144 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6146 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6148 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6149 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6150 NULL, &dwType, lpValue, &cbValueLen);
6151 if (ret != ERROR_SUCCESS)
6153 if (HeapFree (hHeap, 0, lpValue) == 0)
6154 WARN ("HeapFree failed with code %i\n", GetLastError ());
6155 if (HeapFree (hHeap, 0, lpValueName) == 0)
6156 WARN ("HeapFree failed with code %i\n", GetLastError ());
6157 r = RegCloseKey (hkSubKey);
6158 if (r != ERROR_SUCCESS)
6159 WARN ("RegCloseKey returned %i\n", r);
6160 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6161 return ret;
6164 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6165 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6166 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6167 pEnumValues += cbValueNameLen;
6169 /* return # of *bytes* (including trailing \0), not # of chars */
6170 ppev[dwIndex].cbValueName = cbValueNameLen;
6172 ppev[dwIndex].dwType = dwType;
6174 memcpy (pEnumValues, lpValue, cbValueLen);
6175 ppev[dwIndex].pData = pEnumValues;
6176 pEnumValues += cbValueLen;
6178 ppev[dwIndex].cbData = cbValueLen;
6180 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6181 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6184 if (HeapFree (hHeap, 0, lpValue) == 0)
6186 ret = GetLastError ();
6187 ERR ("HeapFree failed with code %i\n", ret);
6188 if (HeapFree (hHeap, 0, lpValueName) == 0)
6189 WARN ("HeapFree failed with code %i\n", GetLastError ());
6190 r = RegCloseKey (hkSubKey);
6191 if (r != ERROR_SUCCESS)
6192 WARN ("RegCloseKey returned %i\n", r);
6193 return ret;
6196 if (HeapFree (hHeap, 0, lpValueName) == 0)
6198 ret = GetLastError ();
6199 ERR ("HeapFree failed with code %i\n", ret);
6200 r = RegCloseKey (hkSubKey);
6201 if (r != ERROR_SUCCESS)
6202 WARN ("RegCloseKey returned %i\n", r);
6203 return ret;
6206 ret = RegCloseKey (hkSubKey);
6207 if (ret != ERROR_SUCCESS)
6209 ERR ("RegCloseKey returned %i\n", ret);
6210 return ret;
6213 return ERROR_SUCCESS;
6216 /*******************************************************************************
6217 * EnumPrinterDataExA [WINSPOOL.@]
6219 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6220 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6221 * what Windows 2000 SP1 does.
6224 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6225 LPBYTE pEnumValues, DWORD cbEnumValues,
6226 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6228 INT len;
6229 LPWSTR pKeyNameW;
6230 DWORD ret, dwIndex, dwBufSize;
6231 HANDLE hHeap;
6232 LPSTR pBuffer;
6234 TRACE ("%p %s\n", hPrinter, pKeyName);
6236 if (pKeyName == NULL || *pKeyName == 0)
6237 return ERROR_INVALID_PARAMETER;
6239 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6240 if (len == 0)
6242 ret = GetLastError ();
6243 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6244 return ret;
6247 hHeap = GetProcessHeap ();
6248 if (hHeap == NULL)
6250 ERR ("GetProcessHeap failed\n");
6251 return ERROR_OUTOFMEMORY;
6254 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6255 if (pKeyNameW == NULL)
6257 ERR ("Failed to allocate %i bytes from process heap\n",
6258 (LONG)(len * sizeof (WCHAR)));
6259 return ERROR_OUTOFMEMORY;
6262 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6264 ret = GetLastError ();
6265 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6266 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6267 WARN ("HeapFree failed with code %i\n", GetLastError ());
6268 return ret;
6271 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6272 pcbEnumValues, pnEnumValues);
6273 if (ret != ERROR_SUCCESS)
6275 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6276 WARN ("HeapFree failed with code %i\n", GetLastError ());
6277 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6278 return ret;
6281 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6283 ret = GetLastError ();
6284 ERR ("HeapFree failed with code %i\n", ret);
6285 return ret;
6288 if (*pnEnumValues == 0) /* empty key */
6289 return ERROR_SUCCESS;
6291 dwBufSize = 0;
6292 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6294 PPRINTER_ENUM_VALUESW ppev =
6295 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6297 if (dwBufSize < ppev->cbValueName)
6298 dwBufSize = ppev->cbValueName;
6300 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6301 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6302 dwBufSize = ppev->cbData;
6305 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6307 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6308 if (pBuffer == NULL)
6310 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6311 return ERROR_OUTOFMEMORY;
6314 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6316 PPRINTER_ENUM_VALUESW ppev =
6317 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6319 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6320 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6321 NULL);
6322 if (len == 0)
6324 ret = GetLastError ();
6325 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6326 if (HeapFree (hHeap, 0, pBuffer) == 0)
6327 WARN ("HeapFree failed with code %i\n", GetLastError ());
6328 return ret;
6331 memcpy (ppev->pValueName, pBuffer, len);
6333 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6335 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6336 ppev->dwType != REG_MULTI_SZ)
6337 continue;
6339 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6340 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6341 if (len == 0)
6343 ret = GetLastError ();
6344 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6345 if (HeapFree (hHeap, 0, pBuffer) == 0)
6346 WARN ("HeapFree failed with code %i\n", GetLastError ());
6347 return ret;
6350 memcpy (ppev->pData, pBuffer, len);
6352 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6353 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6356 if (HeapFree (hHeap, 0, pBuffer) == 0)
6358 ret = GetLastError ();
6359 ERR ("HeapFree failed with code %i\n", ret);
6360 return ret;
6363 return ERROR_SUCCESS;
6366 /******************************************************************************
6367 * AbortPrinter (WINSPOOL.@)
6369 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6371 FIXME("(%p), stub!\n", hPrinter);
6372 return TRUE;
6375 /******************************************************************************
6376 * AddPortA (WINSPOOL.@)
6378 * See AddPortW.
6381 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6383 LPWSTR nameW = NULL;
6384 LPWSTR monitorW = NULL;
6385 DWORD len;
6386 BOOL res;
6388 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6390 if (pName) {
6391 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6392 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6393 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6396 if (pMonitorName) {
6397 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6398 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6399 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6401 res = AddPortW(nameW, hWnd, monitorW);
6402 HeapFree(GetProcessHeap(), 0, nameW);
6403 HeapFree(GetProcessHeap(), 0, monitorW);
6404 return res;
6407 /******************************************************************************
6408 * AddPortW (WINSPOOL.@)
6410 * Add a Port for a specific Monitor
6412 * PARAMS
6413 * pName [I] Servername or NULL (local Computer)
6414 * hWnd [I] Handle to parent Window for the Dialog-Box
6415 * pMonitorName [I] Name of the Monitor that manage the Port
6417 * RETURNS
6418 * Success: TRUE
6419 * Failure: FALSE
6422 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6424 monitor_t * pm;
6425 monitor_t * pui;
6426 DWORD res;
6428 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6430 if (pName && pName[0]) {
6431 SetLastError(ERROR_INVALID_PARAMETER);
6432 return FALSE;
6435 if (!pMonitorName) {
6436 SetLastError(RPC_X_NULL_REF_POINTER);
6437 return FALSE;
6440 /* an empty Monitorname is Invalid */
6441 if (!pMonitorName[0]) {
6442 SetLastError(ERROR_NOT_SUPPORTED);
6443 return FALSE;
6446 pm = monitor_load(pMonitorName, NULL);
6447 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6448 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6449 TRACE("got %d with %u\n", res, GetLastError());
6450 res = TRUE;
6452 else
6454 pui = monitor_loadui(pm);
6455 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6456 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6457 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6458 TRACE("got %d with %u\n", res, GetLastError());
6459 res = TRUE;
6461 else
6463 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6464 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6466 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6467 SetLastError(ERROR_NOT_SUPPORTED);
6468 res = FALSE;
6470 monitor_unload(pui);
6472 monitor_unload(pm);
6473 TRACE("returning %d with %u\n", res, GetLastError());
6474 return res;
6477 /******************************************************************************
6478 * AddPortExA (WINSPOOL.@)
6480 * See AddPortExW.
6483 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6485 PORT_INFO_2W pi2W;
6486 PORT_INFO_2A * pi2A;
6487 LPWSTR nameW = NULL;
6488 LPWSTR monitorW = NULL;
6489 DWORD len;
6490 BOOL res;
6492 pi2A = (PORT_INFO_2A *) pBuffer;
6494 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6495 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6497 if ((level < 1) || (level > 2)) {
6498 SetLastError(ERROR_INVALID_LEVEL);
6499 return FALSE;
6502 if (!pi2A) {
6503 SetLastError(ERROR_INVALID_PARAMETER);
6504 return FALSE;
6507 if (pName) {
6508 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6509 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6510 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6513 if (pMonitorName) {
6514 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6515 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6516 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6519 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6521 if (pi2A->pPortName) {
6522 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6523 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6524 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6527 if (level > 1) {
6528 if (pi2A->pMonitorName) {
6529 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6530 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6531 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6534 if (pi2A->pDescription) {
6535 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6536 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6537 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6539 pi2W.fPortType = pi2A->fPortType;
6540 pi2W.Reserved = pi2A->Reserved;
6543 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6545 HeapFree(GetProcessHeap(), 0, nameW);
6546 HeapFree(GetProcessHeap(), 0, monitorW);
6547 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6548 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6549 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6550 return res;
6554 /******************************************************************************
6555 * AddPortExW (WINSPOOL.@)
6557 * Add a Port for a specific Monitor, without presenting a user interface
6559 * PARAMS
6560 * pName [I] Servername or NULL (local Computer)
6561 * level [I] Structure-Level (1 or 2) for pBuffer
6562 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6563 * pMonitorName [I] Name of the Monitor that manage the Port
6565 * RETURNS
6566 * Success: TRUE
6567 * Failure: FALSE
6570 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6572 PORT_INFO_2W * pi2;
6573 monitor_t * pm;
6574 DWORD res = FALSE;
6576 pi2 = (PORT_INFO_2W *) pBuffer;
6578 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6579 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6580 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6581 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6584 if ((level < 1) || (level > 2)) {
6585 SetLastError(ERROR_INVALID_LEVEL);
6586 return FALSE;
6589 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6590 SetLastError(ERROR_INVALID_PARAMETER);
6591 return FALSE;
6594 /* load the Monitor */
6595 pm = monitor_load(pMonitorName, NULL);
6596 if (!pm) {
6597 SetLastError(ERROR_INVALID_PARAMETER);
6598 return FALSE;
6601 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6602 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6603 TRACE("got %u with %u\n", res, GetLastError());
6605 else
6607 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6609 monitor_unload(pm);
6610 return res;
6613 /******************************************************************************
6614 * AddPrinterConnectionA (WINSPOOL.@)
6616 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6618 FIXME("%s\n", debugstr_a(pName));
6619 return FALSE;
6622 /******************************************************************************
6623 * AddPrinterConnectionW (WINSPOOL.@)
6625 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6627 FIXME("%s\n", debugstr_w(pName));
6628 return FALSE;
6631 /******************************************************************************
6632 * AddPrinterDriverExW (WINSPOOL.@)
6634 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6636 * PARAMS
6637 * pName [I] Servername or NULL (local Computer)
6638 * level [I] Level for the supplied DRIVER_INFO_*W struct
6639 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6640 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6642 * RESULTS
6643 * Success: TRUE
6644 * Failure: FALSE
6647 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6649 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6651 if ((backend == NULL) && !load_backend()) return FALSE;
6653 if (level < 2 || level == 5 || level == 7 || level > 8) {
6654 SetLastError(ERROR_INVALID_LEVEL);
6655 return FALSE;
6658 if (!pDriverInfo) {
6659 SetLastError(ERROR_INVALID_PARAMETER);
6660 return FALSE;
6663 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6666 /******************************************************************************
6667 * AddPrinterDriverExA (WINSPOOL.@)
6669 * See AddPrinterDriverExW.
6672 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6674 DRIVER_INFO_8A *diA;
6675 DRIVER_INFO_8W diW;
6676 LPWSTR nameW = NULL;
6677 DWORD lenA;
6678 DWORD len;
6679 DWORD res = FALSE;
6681 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6683 diA = (DRIVER_INFO_8A *) pDriverInfo;
6684 ZeroMemory(&diW, sizeof(diW));
6686 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6687 SetLastError(ERROR_INVALID_LEVEL);
6688 return FALSE;
6691 if (diA == NULL) {
6692 SetLastError(ERROR_INVALID_PARAMETER);
6693 return FALSE;
6696 /* convert servername to unicode */
6697 if (pName) {
6698 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6699 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6700 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6703 /* common fields */
6704 diW.cVersion = diA->cVersion;
6706 if (diA->pName) {
6707 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6708 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6709 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6712 if (diA->pEnvironment) {
6713 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6714 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6715 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6718 if (diA->pDriverPath) {
6719 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6720 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6721 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6724 if (diA->pDataFile) {
6725 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6726 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6727 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6730 if (diA->pConfigFile) {
6731 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6732 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6733 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6736 if ((Level > 2) && diA->pDependentFiles) {
6737 lenA = multi_sz_lenA(diA->pDependentFiles);
6738 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6739 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6740 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6743 if ((Level > 2) && diA->pMonitorName) {
6744 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6745 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6746 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6749 if ((Level > 3) && diA->pDefaultDataType) {
6750 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6751 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6755 if ((Level > 3) && diA->pszzPreviousNames) {
6756 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6757 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6758 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6759 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6762 if ((Level > 5) && diA->pszMfgName) {
6763 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6764 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6765 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6768 if ((Level > 5) && diA->pszOEMUrl) {
6769 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6770 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6771 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6774 if ((Level > 5) && diA->pszHardwareID) {
6775 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6776 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6777 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6780 if ((Level > 5) && diA->pszProvider) {
6781 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6782 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6783 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6786 if (Level > 7) {
6787 FIXME("level %u is incomplete\n", Level);
6790 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6791 TRACE("got %u with %u\n", res, GetLastError());
6792 HeapFree(GetProcessHeap(), 0, nameW);
6793 HeapFree(GetProcessHeap(), 0, diW.pName);
6794 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6795 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6796 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6797 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6798 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6799 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6800 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6801 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6802 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6803 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6804 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6805 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6807 TRACE("=> %u with %u\n", res, GetLastError());
6808 return res;
6811 /******************************************************************************
6812 * ConfigurePortA (WINSPOOL.@)
6814 * See ConfigurePortW.
6817 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6819 LPWSTR nameW = NULL;
6820 LPWSTR portW = NULL;
6821 INT len;
6822 DWORD res;
6824 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6826 /* convert servername to unicode */
6827 if (pName) {
6828 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6829 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6830 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6833 /* convert portname to unicode */
6834 if (pPortName) {
6835 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6836 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6837 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6840 res = ConfigurePortW(nameW, hWnd, portW);
6841 HeapFree(GetProcessHeap(), 0, nameW);
6842 HeapFree(GetProcessHeap(), 0, portW);
6843 return res;
6846 /******************************************************************************
6847 * ConfigurePortW (WINSPOOL.@)
6849 * Display the Configuration-Dialog for a specific Port
6851 * PARAMS
6852 * pName [I] Servername or NULL (local Computer)
6853 * hWnd [I] Handle to parent Window for the Dialog-Box
6854 * pPortName [I] Name of the Port, that should be configured
6856 * RETURNS
6857 * Success: TRUE
6858 * Failure: FALSE
6861 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6863 monitor_t * pm;
6864 monitor_t * pui;
6865 DWORD res;
6867 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6869 if (pName && pName[0]) {
6870 SetLastError(ERROR_INVALID_PARAMETER);
6871 return FALSE;
6874 if (!pPortName) {
6875 SetLastError(RPC_X_NULL_REF_POINTER);
6876 return FALSE;
6879 /* an empty Portname is Invalid, but can popup a Dialog */
6880 if (!pPortName[0]) {
6881 SetLastError(ERROR_NOT_SUPPORTED);
6882 return FALSE;
6885 pm = monitor_load_by_port(pPortName);
6886 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6887 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6888 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6889 TRACE("got %d with %u\n", res, GetLastError());
6891 else
6893 pui = monitor_loadui(pm);
6894 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6895 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6896 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6897 TRACE("got %d with %u\n", res, GetLastError());
6899 else
6901 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6902 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6904 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6905 SetLastError(ERROR_NOT_SUPPORTED);
6906 res = FALSE;
6908 monitor_unload(pui);
6910 monitor_unload(pm);
6912 TRACE("returning %d with %u\n", res, GetLastError());
6913 return res;
6916 /******************************************************************************
6917 * ConnectToPrinterDlg (WINSPOOL.@)
6919 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6921 FIXME("%p %x\n", hWnd, Flags);
6922 return NULL;
6925 /******************************************************************************
6926 * DeletePrinterConnectionA (WINSPOOL.@)
6928 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6930 FIXME("%s\n", debugstr_a(pName));
6931 return TRUE;
6934 /******************************************************************************
6935 * DeletePrinterConnectionW (WINSPOOL.@)
6937 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6939 FIXME("%s\n", debugstr_w(pName));
6940 return TRUE;
6943 /******************************************************************************
6944 * DeletePrinterDriverExW (WINSPOOL.@)
6946 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6947 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6949 HKEY hkey_drivers;
6950 BOOL ret = FALSE;
6952 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6953 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6955 if(pName && pName[0])
6957 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6958 SetLastError(ERROR_INVALID_PARAMETER);
6959 return FALSE;
6962 if(dwDeleteFlag)
6964 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6965 SetLastError(ERROR_INVALID_PARAMETER);
6966 return FALSE;
6969 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6971 if(!hkey_drivers)
6973 ERR("Can't open drivers key\n");
6974 return FALSE;
6977 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6978 ret = TRUE;
6980 RegCloseKey(hkey_drivers);
6982 return ret;
6985 /******************************************************************************
6986 * DeletePrinterDriverExA (WINSPOOL.@)
6988 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6989 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6991 UNICODE_STRING NameW, EnvW, DriverW;
6992 BOOL ret;
6994 asciitounicode(&NameW, pName);
6995 asciitounicode(&EnvW, pEnvironment);
6996 asciitounicode(&DriverW, pDriverName);
6998 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7000 RtlFreeUnicodeString(&DriverW);
7001 RtlFreeUnicodeString(&EnvW);
7002 RtlFreeUnicodeString(&NameW);
7004 return ret;
7007 /******************************************************************************
7008 * DeletePrinterDataExW (WINSPOOL.@)
7010 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7011 LPCWSTR pValueName)
7013 FIXME("%p %s %s\n", hPrinter,
7014 debugstr_w(pKeyName), debugstr_w(pValueName));
7015 return ERROR_INVALID_PARAMETER;
7018 /******************************************************************************
7019 * DeletePrinterDataExA (WINSPOOL.@)
7021 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7022 LPCSTR pValueName)
7024 FIXME("%p %s %s\n", hPrinter,
7025 debugstr_a(pKeyName), debugstr_a(pValueName));
7026 return ERROR_INVALID_PARAMETER;
7029 /******************************************************************************
7030 * DeletePrintProcessorA (WINSPOOL.@)
7032 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7034 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7035 debugstr_a(pPrintProcessorName));
7036 return TRUE;
7039 /******************************************************************************
7040 * DeletePrintProcessorW (WINSPOOL.@)
7042 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7044 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7045 debugstr_w(pPrintProcessorName));
7046 return TRUE;
7049 /******************************************************************************
7050 * DeletePrintProvidorA (WINSPOOL.@)
7052 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7054 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7055 debugstr_a(pPrintProviderName));
7056 return TRUE;
7059 /******************************************************************************
7060 * DeletePrintProvidorW (WINSPOOL.@)
7062 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7064 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7065 debugstr_w(pPrintProviderName));
7066 return TRUE;
7069 /******************************************************************************
7070 * EnumFormsA (WINSPOOL.@)
7072 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7073 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7075 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7076 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7077 return FALSE;
7080 /******************************************************************************
7081 * EnumFormsW (WINSPOOL.@)
7083 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7084 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7086 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7087 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7088 return FALSE;
7091 /*****************************************************************************
7092 * EnumMonitorsA [WINSPOOL.@]
7094 * See EnumMonitorsW.
7097 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7098 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7100 BOOL res;
7101 LPBYTE bufferW = NULL;
7102 LPWSTR nameW = NULL;
7103 DWORD needed = 0;
7104 DWORD numentries = 0;
7105 INT len;
7107 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7108 cbBuf, pcbNeeded, pcReturned);
7110 /* convert servername to unicode */
7111 if (pName) {
7112 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7113 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7114 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7116 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7117 needed = cbBuf * sizeof(WCHAR);
7118 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7119 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7121 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7122 if (pcbNeeded) needed = *pcbNeeded;
7123 /* HeapReAlloc return NULL, when bufferW was NULL */
7124 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7125 HeapAlloc(GetProcessHeap(), 0, needed);
7127 /* Try again with the large Buffer */
7128 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7130 numentries = pcReturned ? *pcReturned : 0;
7131 needed = 0;
7133 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7134 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7136 if (res) {
7137 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7138 DWORD entrysize = 0;
7139 DWORD index;
7140 LPSTR ptr;
7141 LPMONITOR_INFO_2W mi2w;
7142 LPMONITOR_INFO_2A mi2a;
7144 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7145 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7147 /* First pass: calculate the size for all Entries */
7148 mi2w = (LPMONITOR_INFO_2W) bufferW;
7149 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7150 index = 0;
7151 while (index < numentries) {
7152 index++;
7153 needed += entrysize; /* MONITOR_INFO_?A */
7154 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7156 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7157 NULL, 0, NULL, NULL);
7158 if (Level > 1) {
7159 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7160 NULL, 0, NULL, NULL);
7161 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7162 NULL, 0, NULL, NULL);
7164 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7165 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7166 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7169 /* check for errors and quit on failure */
7170 if (cbBuf < needed) {
7171 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7172 res = FALSE;
7173 goto emA_cleanup;
7175 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7176 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7177 cbBuf -= len ; /* free Bytes in the user-Buffer */
7178 mi2w = (LPMONITOR_INFO_2W) bufferW;
7179 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7180 index = 0;
7181 /* Second Pass: Fill the User Buffer (if we have one) */
7182 while ((index < numentries) && pMonitors) {
7183 index++;
7184 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7185 mi2a->pName = ptr;
7186 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7187 ptr, cbBuf , NULL, NULL);
7188 ptr += len;
7189 cbBuf -= len;
7190 if (Level > 1) {
7191 mi2a->pEnvironment = ptr;
7192 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7193 ptr, cbBuf, NULL, NULL);
7194 ptr += len;
7195 cbBuf -= len;
7197 mi2a->pDLLName = ptr;
7198 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7199 ptr, cbBuf, NULL, NULL);
7200 ptr += len;
7201 cbBuf -= len;
7203 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7204 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7205 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7208 emA_cleanup:
7209 if (pcbNeeded) *pcbNeeded = needed;
7210 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7212 HeapFree(GetProcessHeap(), 0, nameW);
7213 HeapFree(GetProcessHeap(), 0, bufferW);
7215 TRACE("returning %d with %d (%d byte for %d entries)\n",
7216 (res), GetLastError(), needed, numentries);
7218 return (res);
7222 /*****************************************************************************
7223 * EnumMonitorsW [WINSPOOL.@]
7225 * Enumerate available Port-Monitors
7227 * PARAMS
7228 * pName [I] Servername or NULL (local Computer)
7229 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7230 * pMonitors [O] PTR to Buffer that receives the Result
7231 * cbBuf [I] Size of Buffer at pMonitors
7232 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7233 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7235 * RETURNS
7236 * Success: TRUE
7237 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7240 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7241 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7244 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7245 cbBuf, pcbNeeded, pcReturned);
7247 if ((backend == NULL) && !load_backend()) return FALSE;
7249 /* Level is not checked in win9x */
7250 if (!Level || (Level > 2)) {
7251 WARN("level (%d) is ignored in win9x\n", Level);
7252 SetLastError(ERROR_INVALID_LEVEL);
7253 return FALSE;
7255 if (!pcbNeeded) {
7256 SetLastError(RPC_X_NULL_REF_POINTER);
7257 return FALSE;
7260 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7263 /******************************************************************************
7264 * SpoolerInit (WINSPOOL.@)
7266 * Initialize the Spooler
7268 * RETURNS
7269 * Success: TRUE
7270 * Failure: FALSE
7272 * NOTES
7273 * The function fails on windows, when the spooler service is not running
7276 BOOL WINAPI SpoolerInit(void)
7279 if ((backend == NULL) && !load_backend()) return FALSE;
7280 return TRUE;
7283 /******************************************************************************
7284 * XcvDataW (WINSPOOL.@)
7286 * Execute commands in the Printmonitor DLL
7288 * PARAMS
7289 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7290 * pszDataName [i] Name of the command to execute
7291 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7292 * cbInputData [i] Size in Bytes of Buffer at pInputData
7293 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7294 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7295 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7296 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7298 * RETURNS
7299 * Success: TRUE
7300 * Failure: FALSE
7302 * NOTES
7303 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7304 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7306 * Minimal List of commands, that a Printmonitor DLL should support:
7308 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7309 *| "AddPort" : Add a Port
7310 *| "DeletePort": Delete a Port
7312 * Many Printmonitors support additional commands. Examples for localspl.dll:
7313 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7314 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7317 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7318 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7319 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7321 opened_printer_t *printer;
7323 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7324 pInputData, cbInputData, pOutputData,
7325 cbOutputData, pcbOutputNeeded, pdwStatus);
7327 printer = get_opened_printer(hXcv);
7328 if (!printer || (!printer->hXcv)) {
7329 SetLastError(ERROR_INVALID_HANDLE);
7330 return FALSE;
7333 if (!pcbOutputNeeded) {
7334 SetLastError(ERROR_INVALID_PARAMETER);
7335 return FALSE;
7338 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7339 SetLastError(RPC_X_NULL_REF_POINTER);
7340 return FALSE;
7343 *pcbOutputNeeded = 0;
7345 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7346 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7348 return TRUE;
7351 /*****************************************************************************
7352 * EnumPrinterDataA [WINSPOOL.@]
7355 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7356 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7357 DWORD cbData, LPDWORD pcbData )
7359 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7360 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7361 return ERROR_NO_MORE_ITEMS;
7364 /*****************************************************************************
7365 * EnumPrinterDataW [WINSPOOL.@]
7368 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7369 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7370 DWORD cbData, LPDWORD pcbData )
7372 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7373 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7374 return ERROR_NO_MORE_ITEMS;
7377 /*****************************************************************************
7378 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7381 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7382 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7383 LPDWORD pcbNeeded, LPDWORD pcReturned)
7385 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7386 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7387 pcbNeeded, pcReturned);
7388 return FALSE;
7391 /*****************************************************************************
7392 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7395 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7396 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7397 LPDWORD pcbNeeded, LPDWORD pcReturned)
7399 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7400 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7401 pcbNeeded, pcReturned);
7402 return FALSE;
7405 /*****************************************************************************
7406 * EnumPrintProcessorsA [WINSPOOL.@]
7409 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7410 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7412 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7413 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7414 return FALSE;
7417 /*****************************************************************************
7418 * EnumPrintProcessorsW [WINSPOOL.@]
7421 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7422 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7424 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7425 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7426 cbBuf, pcbNeeded, pcbReturned);
7427 return FALSE;
7430 /*****************************************************************************
7431 * ExtDeviceMode [WINSPOOL.@]
7434 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7435 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7436 DWORD fMode)
7438 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7439 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7440 debugstr_a(pProfile), fMode);
7441 return -1;
7444 /*****************************************************************************
7445 * FindClosePrinterChangeNotification [WINSPOOL.@]
7448 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7450 FIXME("Stub: %p\n", hChange);
7451 return TRUE;
7454 /*****************************************************************************
7455 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7458 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7459 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7461 FIXME("Stub: %p %x %x %p\n",
7462 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7463 return INVALID_HANDLE_VALUE;
7466 /*****************************************************************************
7467 * FindNextPrinterChangeNotification [WINSPOOL.@]
7470 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7471 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7473 FIXME("Stub: %p %p %p %p\n",
7474 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7475 return FALSE;
7478 /*****************************************************************************
7479 * FreePrinterNotifyInfo [WINSPOOL.@]
7482 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7484 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7485 return TRUE;
7488 /*****************************************************************************
7489 * string_to_buf
7491 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7492 * ansi depending on the unicode parameter.
7494 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7496 if(!str)
7498 *size = 0;
7499 return TRUE;
7502 if(unicode)
7504 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7505 if(*size <= cb)
7507 memcpy(ptr, str, *size);
7508 return TRUE;
7510 return FALSE;
7512 else
7514 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7515 if(*size <= cb)
7517 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7518 return TRUE;
7520 return FALSE;
7524 /*****************************************************************************
7525 * get_job_info_1
7527 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7528 LPDWORD pcbNeeded, BOOL unicode)
7530 DWORD size, left = cbBuf;
7531 BOOL space = (cbBuf > 0);
7532 LPBYTE ptr = buf;
7534 *pcbNeeded = 0;
7536 if(space)
7538 ji1->JobId = job->job_id;
7541 string_to_buf(job->document_title, ptr, left, &size, unicode);
7542 if(space && size <= left)
7544 ji1->pDocument = (LPWSTR)ptr;
7545 ptr += size;
7546 left -= size;
7548 else
7549 space = FALSE;
7550 *pcbNeeded += size;
7552 return space;
7555 /*****************************************************************************
7556 * get_job_info_2
7558 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7559 LPDWORD pcbNeeded, BOOL unicode)
7561 DWORD size, left = cbBuf;
7562 BOOL space = (cbBuf > 0);
7563 LPBYTE ptr = buf;
7565 *pcbNeeded = 0;
7567 if(space)
7569 ji2->JobId = job->job_id;
7572 string_to_buf(job->document_title, ptr, left, &size, unicode);
7573 if(space && size <= left)
7575 ji2->pDocument = (LPWSTR)ptr;
7576 ptr += size;
7577 left -= size;
7579 else
7580 space = FALSE;
7581 *pcbNeeded += size;
7583 return space;
7586 /*****************************************************************************
7587 * get_job_info
7589 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7590 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7592 BOOL ret = FALSE;
7593 DWORD needed = 0, size;
7594 job_t *job;
7595 LPBYTE ptr = pJob;
7597 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7599 EnterCriticalSection(&printer_handles_cs);
7600 job = get_job(hPrinter, JobId);
7601 if(!job)
7602 goto end;
7604 switch(Level)
7606 case 1:
7607 size = sizeof(JOB_INFO_1W);
7608 if(cbBuf >= size)
7610 cbBuf -= size;
7611 ptr += size;
7612 memset(pJob, 0, size);
7614 else
7615 cbBuf = 0;
7616 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7617 needed += size;
7618 break;
7620 case 2:
7621 size = sizeof(JOB_INFO_2W);
7622 if(cbBuf >= size)
7624 cbBuf -= size;
7625 ptr += size;
7626 memset(pJob, 0, size);
7628 else
7629 cbBuf = 0;
7630 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7631 needed += size;
7632 break;
7634 case 3:
7635 size = sizeof(JOB_INFO_3);
7636 if(cbBuf >= size)
7638 cbBuf -= size;
7639 memset(pJob, 0, size);
7640 ret = TRUE;
7642 else
7643 cbBuf = 0;
7644 needed = size;
7645 break;
7647 default:
7648 SetLastError(ERROR_INVALID_LEVEL);
7649 goto end;
7651 if(pcbNeeded)
7652 *pcbNeeded = needed;
7653 end:
7654 LeaveCriticalSection(&printer_handles_cs);
7655 return ret;
7658 /*****************************************************************************
7659 * GetJobA [WINSPOOL.@]
7662 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7663 DWORD cbBuf, LPDWORD pcbNeeded)
7665 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7668 /*****************************************************************************
7669 * GetJobW [WINSPOOL.@]
7672 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7673 DWORD cbBuf, LPDWORD pcbNeeded)
7675 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7678 /*****************************************************************************
7679 * schedule_lpr
7681 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7683 char *unixname, *queue, *cmd;
7684 char fmt[] = "lpr -P%s %s";
7685 DWORD len;
7687 if(!(unixname = wine_get_unix_file_name(filename)))
7688 return FALSE;
7690 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7691 queue = HeapAlloc(GetProcessHeap(), 0, len);
7692 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7694 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7695 sprintf(cmd, fmt, queue, unixname);
7697 TRACE("printing with: %s\n", cmd);
7698 system(cmd);
7700 HeapFree(GetProcessHeap(), 0, cmd);
7701 HeapFree(GetProcessHeap(), 0, queue);
7702 HeapFree(GetProcessHeap(), 0, unixname);
7703 return TRUE;
7706 /*****************************************************************************
7707 * schedule_cups
7709 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7711 #ifdef SONAME_LIBCUPS
7712 if(pcupsPrintFile)
7714 char *unixname, *queue, *doc_titleA;
7715 DWORD len;
7716 BOOL ret;
7718 if(!(unixname = wine_get_unix_file_name(filename)))
7719 return FALSE;
7721 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7722 queue = HeapAlloc(GetProcessHeap(), 0, len);
7723 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7725 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7726 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7727 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7729 TRACE("printing via cups\n");
7730 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7731 HeapFree(GetProcessHeap(), 0, doc_titleA);
7732 HeapFree(GetProcessHeap(), 0, queue);
7733 HeapFree(GetProcessHeap(), 0, unixname);
7734 return ret;
7736 else
7737 #endif
7739 return schedule_lpr(printer_name, filename);
7743 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7745 LPWSTR filename;
7747 switch(msg)
7749 case WM_INITDIALOG:
7750 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7751 return TRUE;
7753 case WM_COMMAND:
7754 if(HIWORD(wparam) == BN_CLICKED)
7756 if(LOWORD(wparam) == IDOK)
7758 HANDLE hf;
7759 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7760 LPWSTR *output;
7762 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7763 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7765 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7767 WCHAR caption[200], message[200];
7768 int mb_ret;
7770 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7771 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7772 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7773 if(mb_ret == IDCANCEL)
7775 HeapFree(GetProcessHeap(), 0, filename);
7776 return TRUE;
7779 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7780 if(hf == INVALID_HANDLE_VALUE)
7782 WCHAR caption[200], message[200];
7784 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7785 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7786 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7787 HeapFree(GetProcessHeap(), 0, filename);
7788 return TRUE;
7790 CloseHandle(hf);
7791 DeleteFileW(filename);
7792 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7793 *output = filename;
7794 EndDialog(hwnd, IDOK);
7795 return TRUE;
7797 if(LOWORD(wparam) == IDCANCEL)
7799 EndDialog(hwnd, IDCANCEL);
7800 return TRUE;
7803 return FALSE;
7805 return FALSE;
7808 /*****************************************************************************
7809 * get_filename
7811 static BOOL get_filename(LPWSTR *filename)
7813 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7814 file_dlg_proc, (LPARAM)filename) == IDOK;
7817 /*****************************************************************************
7818 * schedule_file
7820 static BOOL schedule_file(LPCWSTR filename)
7822 LPWSTR output = NULL;
7824 if(get_filename(&output))
7826 TRACE("copy to %s\n", debugstr_w(output));
7827 CopyFileW(filename, output, FALSE);
7828 HeapFree(GetProcessHeap(), 0, output);
7829 return TRUE;
7831 return FALSE;
7834 /*****************************************************************************
7835 * schedule_pipe
7837 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7839 #ifdef HAVE_FORK
7840 char *unixname, *cmdA;
7841 DWORD len;
7842 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7843 BOOL ret = FALSE;
7844 char buf[1024];
7846 if(!(unixname = wine_get_unix_file_name(filename)))
7847 return FALSE;
7849 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7850 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7851 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7853 TRACE("printing with: %s\n", cmdA);
7855 if((file_fd = open(unixname, O_RDONLY)) == -1)
7856 goto end;
7858 if (pipe(fds))
7860 ERR("pipe() failed!\n");
7861 goto end;
7864 if (fork() == 0)
7866 close(0);
7867 dup2(fds[0], 0);
7868 close(fds[1]);
7870 /* reset signals that we previously set to SIG_IGN */
7871 signal(SIGPIPE, SIG_DFL);
7872 signal(SIGCHLD, SIG_DFL);
7874 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7875 _exit(1);
7878 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7879 write(fds[1], buf, no_read);
7881 ret = TRUE;
7883 end:
7884 if(file_fd != -1) close(file_fd);
7885 if(fds[0] != -1) close(fds[0]);
7886 if(fds[1] != -1) close(fds[1]);
7888 HeapFree(GetProcessHeap(), 0, cmdA);
7889 HeapFree(GetProcessHeap(), 0, unixname);
7890 return ret;
7891 #else
7892 return FALSE;
7893 #endif
7896 /*****************************************************************************
7897 * schedule_unixfile
7899 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7901 int in_fd, out_fd, no_read;
7902 char buf[1024];
7903 BOOL ret = FALSE;
7904 char *unixname, *outputA;
7905 DWORD len;
7907 if(!(unixname = wine_get_unix_file_name(filename)))
7908 return FALSE;
7910 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7911 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7912 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7914 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7915 in_fd = open(unixname, O_RDONLY);
7916 if(out_fd == -1 || in_fd == -1)
7917 goto end;
7919 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7920 write(out_fd, buf, no_read);
7922 ret = TRUE;
7923 end:
7924 if(in_fd != -1) close(in_fd);
7925 if(out_fd != -1) close(out_fd);
7926 HeapFree(GetProcessHeap(), 0, outputA);
7927 HeapFree(GetProcessHeap(), 0, unixname);
7928 return ret;
7931 /*****************************************************************************
7932 * ScheduleJob [WINSPOOL.@]
7935 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7937 opened_printer_t *printer;
7938 BOOL ret = FALSE;
7939 struct list *cursor, *cursor2;
7941 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7942 EnterCriticalSection(&printer_handles_cs);
7943 printer = get_opened_printer(hPrinter);
7944 if(!printer)
7945 goto end;
7947 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7949 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7950 HANDLE hf;
7952 if(job->job_id != dwJobID) continue;
7954 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7955 if(hf != INVALID_HANDLE_VALUE)
7957 PRINTER_INFO_5W *pi5;
7958 DWORD needed;
7959 HKEY hkey;
7960 WCHAR output[1024];
7961 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7962 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7964 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7965 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7966 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7967 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7968 debugstr_w(pi5->pPortName));
7970 output[0] = 0;
7972 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7973 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7975 DWORD type, count = sizeof(output);
7976 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7977 RegCloseKey(hkey);
7979 if(output[0] == '|')
7981 schedule_pipe(output + 1, job->filename);
7983 else if(output[0])
7985 schedule_unixfile(output, job->filename);
7987 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7989 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7991 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7993 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7995 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7997 schedule_file(job->filename);
7999 else
8001 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
8003 HeapFree(GetProcessHeap(), 0, pi5);
8004 CloseHandle(hf);
8005 DeleteFileW(job->filename);
8007 list_remove(cursor);
8008 HeapFree(GetProcessHeap(), 0, job->document_title);
8009 HeapFree(GetProcessHeap(), 0, job->filename);
8010 HeapFree(GetProcessHeap(), 0, job);
8011 ret = TRUE;
8012 break;
8014 end:
8015 LeaveCriticalSection(&printer_handles_cs);
8016 return ret;
8019 /*****************************************************************************
8020 * StartDocDlgA [WINSPOOL.@]
8022 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8024 UNICODE_STRING usBuffer;
8025 DOCINFOW docW;
8026 LPWSTR retW;
8027 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8028 LPSTR ret = NULL;
8030 docW.cbSize = sizeof(docW);
8031 if (doc->lpszDocName)
8033 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8034 if (!(docW.lpszDocName = docnameW)) return NULL;
8036 if (doc->lpszOutput)
8038 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8039 if (!(docW.lpszOutput = outputW)) return NULL;
8041 if (doc->lpszDatatype)
8043 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8044 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8046 docW.fwType = doc->fwType;
8048 retW = StartDocDlgW(hPrinter, &docW);
8050 if(retW)
8052 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8053 ret = HeapAlloc(GetProcessHeap(), 0, len);
8054 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8055 HeapFree(GetProcessHeap(), 0, retW);
8058 HeapFree(GetProcessHeap(), 0, datatypeW);
8059 HeapFree(GetProcessHeap(), 0, outputW);
8060 HeapFree(GetProcessHeap(), 0, docnameW);
8062 return ret;
8065 /*****************************************************************************
8066 * StartDocDlgW [WINSPOOL.@]
8068 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8069 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8070 * port is "FILE:". Also returns the full path if passed a relative path.
8072 * The caller should free the returned string from the process heap.
8074 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8076 LPWSTR ret = NULL;
8077 DWORD len, attr;
8079 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8081 PRINTER_INFO_5W *pi5;
8082 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8083 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8084 return NULL;
8085 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8086 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8087 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8089 HeapFree(GetProcessHeap(), 0, pi5);
8090 return NULL;
8092 HeapFree(GetProcessHeap(), 0, pi5);
8095 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8097 LPWSTR name;
8099 if (get_filename(&name))
8101 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8103 HeapFree(GetProcessHeap(), 0, name);
8104 return NULL;
8106 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8107 GetFullPathNameW(name, len, ret, NULL);
8108 HeapFree(GetProcessHeap(), 0, name);
8110 return ret;
8113 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8114 return NULL;
8116 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8117 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8119 attr = GetFileAttributesW(ret);
8120 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8122 HeapFree(GetProcessHeap(), 0, ret);
8123 ret = NULL;
8125 return ret;