push 43f03fe87c2254c6df67b2de3c08b5b20fd64327
[wine/hacks.git] / dlls / winspool.drv / info.c
blob92bbc94428dc7a0f0621b5847dacaaade510a9bc
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2009 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
199 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
200 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
201 static const WCHAR subdir_x64W[] = {'x','6','4',0};
202 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
203 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
204 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
205 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
206 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
208 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
209 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
211 static const WCHAR backslashW[] = {'\\',0};
212 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
213 'i','o','n',' ','F','i','l','e',0};
214 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
215 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
216 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
217 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
218 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
219 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
220 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
221 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
222 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
223 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
224 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
225 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
226 static const WCHAR NameW[] = {'N','a','m','e',0};
227 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
228 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
229 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
230 static const WCHAR PortW[] = {'P','o','r','t',0};
231 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
232 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
233 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
234 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
235 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
236 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
237 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
238 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
239 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
240 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
241 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
242 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
243 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
244 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
245 static const WCHAR emptyStringW[] = {0};
246 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
247 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
249 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
251 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
252 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
253 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
255 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
256 'D','o','c','u','m','e','n','t',0};
258 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
259 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
260 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
261 0, sizeof(DRIVER_INFO_8W)};
264 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
265 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
266 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
267 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
268 sizeof(PRINTER_INFO_9W)};
270 /******************************************************************
271 * validate the user-supplied printing-environment [internal]
273 * PARAMS
274 * env [I] PTR to Environment-String or NULL
276 * RETURNS
277 * Failure: NULL
278 * Success: PTR to printenv_t
280 * NOTES
281 * An empty string is handled the same way as NULL.
282 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
286 static const printenv_t * validate_envW(LPCWSTR env)
288 static const printenv_t env_x64 = {envname_x64W, subdir_x64W,
289 3, Version3_RegPathW, Version3_SubdirW};
290 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
291 3, Version3_RegPathW, Version3_SubdirW};
292 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
293 0, Version0_RegPathW, Version0_SubdirW};
295 static const printenv_t * const all_printenv[]={&env_x86, &env_x64, &env_win40};
297 const printenv_t *result = NULL;
298 unsigned int i;
300 TRACE("testing %s\n", debugstr_w(env));
301 if (env && env[0])
303 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
305 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
307 result = all_printenv[i];
308 break;
312 if (result == NULL) {
313 FIXME("unsupported Environment: %s\n", debugstr_w(env));
314 SetLastError(ERROR_INVALID_ENVIRONMENT);
316 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
318 else
320 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
322 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
324 return result;
328 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
329 if passed a NULL string. This returns NULLs to the result.
331 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
333 if ( (src) )
335 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
336 return usBufferPtr->Buffer;
338 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
339 return NULL;
342 static LPWSTR strdupW(LPCWSTR p)
344 LPWSTR ret;
345 DWORD len;
347 if(!p) return NULL;
348 len = (strlenW(p) + 1) * sizeof(WCHAR);
349 ret = HeapAlloc(GetProcessHeap(), 0, len);
350 memcpy(ret, p, len);
351 return ret;
354 static LPSTR strdupWtoA( LPCWSTR str )
356 LPSTR ret;
357 INT len;
359 if (!str) return NULL;
360 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
361 ret = HeapAlloc( GetProcessHeap(), 0, len );
362 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
363 return ret;
366 /******************************************************************
367 * Return the number of bytes for an multi_sz string.
368 * The result includes all \0s
369 * (specifically the extra \0, that is needed as multi_sz terminator).
371 #if 0
372 static int multi_sz_lenW(const WCHAR *str)
374 const WCHAR *ptr = str;
375 if(!str) return 0;
378 ptr += lstrlenW(ptr) + 1;
379 } while(*ptr);
381 return (ptr - str + 1) * sizeof(WCHAR);
383 #endif
384 /* ################################ */
386 static int multi_sz_lenA(const char *str)
388 const char *ptr = str;
389 if(!str) return 0;
392 ptr += lstrlenA(ptr) + 1;
393 } while(*ptr);
395 return ptr - str + 1;
398 static void
399 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
400 char qbuf[200];
402 /* If forcing, or no profile string entry for device yet, set the entry
404 * The always change entry if not WINEPS yet is discussable.
406 if (force ||
407 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
408 !strcmp(qbuf,"*") ||
409 !strstr(qbuf,"WINEPS.DRV")
411 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
412 HKEY hkey;
414 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
415 WriteProfileStringA("windows","device",buf);
416 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
417 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
418 RegCloseKey(hkey);
420 HeapFree(GetProcessHeap(),0,buf);
424 static BOOL add_printer_driver(const char *name)
426 DRIVER_INFO_3A di3a;
428 static char driver_9x[] = "wineps16.drv",
429 driver_nt[] = "wineps.drv",
430 env_9x[] = "Windows 4.0",
431 env_nt[] = "Windows NT x86",
432 data_file[] = "generic.ppd",
433 default_data_type[] = "RAW";
435 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
436 di3a.cVersion = 3;
437 di3a.pName = (char *)name;
438 di3a.pEnvironment = env_nt;
439 di3a.pDriverPath = driver_nt;
440 di3a.pDataFile = data_file;
441 di3a.pConfigFile = driver_nt;
442 di3a.pDefaultDataType = default_data_type;
444 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
445 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
447 di3a.cVersion = 0;
448 di3a.pEnvironment = env_9x;
449 di3a.pDriverPath = driver_9x;
450 di3a.pConfigFile = driver_9x;
451 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
452 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
454 return TRUE;
457 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
458 debugstr_a(di3a.pEnvironment), GetLastError());
459 return FALSE;
462 #ifdef SONAME_LIBCUPS
463 static typeof(cupsFreeDests) *pcupsFreeDests;
464 static typeof(cupsGetDests) *pcupsGetDests;
465 static typeof(cupsGetPPD) *pcupsGetPPD;
466 static typeof(cupsPrintFile) *pcupsPrintFile;
467 static void *cupshandle;
469 static BOOL CUPS_LoadPrinters(void)
471 int i, nrofdests;
472 BOOL hadprinter = FALSE, haddefault = FALSE;
473 cups_dest_t *dests;
474 PRINTER_INFO_2A pinfo2a;
475 char *port,*devline;
476 HKEY hkeyPrinter, hkeyPrinters, hkey;
477 char loaderror[256];
479 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
480 if (!cupshandle) {
481 TRACE("%s\n", loaderror);
482 return FALSE;
484 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
486 #define DYNCUPS(x) \
487 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
488 if (!p##x) return FALSE;
490 DYNCUPS(cupsFreeDests);
491 DYNCUPS(cupsGetPPD);
492 DYNCUPS(cupsGetDests);
493 DYNCUPS(cupsPrintFile);
494 #undef DYNCUPS
496 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
497 ERROR_SUCCESS) {
498 ERR("Can't create Printers key\n");
499 return FALSE;
502 nrofdests = pcupsGetDests(&dests);
503 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
504 for (i=0;i<nrofdests;i++) {
505 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
506 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
507 sprintf(port,"LPR:%s", dests[i].name);
508 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
509 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
510 sprintf(devline, "WINEPS.DRV,%s", port);
511 WriteProfileStringA("devices", dests[i].name, devline);
512 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
513 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
514 RegCloseKey(hkey);
517 lstrcatA(devline, ",15,45");
518 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
519 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
520 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
521 RegCloseKey(hkey);
524 HeapFree(GetProcessHeap(), 0, devline);
526 TRACE("Printer %d: %s\n", i, dests[i].name);
527 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
528 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
529 and continue */
530 TRACE("Printer already exists\n");
531 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
532 RegCloseKey(hkeyPrinter);
533 } else {
534 static CHAR data_type[] = "RAW",
535 print_proc[] = "WinPrint",
536 comment[] = "WINEPS Printer using CUPS",
537 location[] = "<physical location of printer>",
538 params[] = "<parameters?>",
539 share_name[] = "<share name?>",
540 sep_file[] = "<sep file?>";
542 add_printer_driver(dests[i].name);
544 memset(&pinfo2a,0,sizeof(pinfo2a));
545 pinfo2a.pPrinterName = dests[i].name;
546 pinfo2a.pDatatype = data_type;
547 pinfo2a.pPrintProcessor = print_proc;
548 pinfo2a.pDriverName = dests[i].name;
549 pinfo2a.pComment = comment;
550 pinfo2a.pLocation = location;
551 pinfo2a.pPortName = port;
552 pinfo2a.pParameters = params;
553 pinfo2a.pShareName = share_name;
554 pinfo2a.pSepFile = sep_file;
556 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
557 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
558 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
561 HeapFree(GetProcessHeap(),0,port);
563 hadprinter = TRUE;
564 if (dests[i].is_default) {
565 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
566 haddefault = TRUE;
569 if (hadprinter & !haddefault)
570 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
571 pcupsFreeDests(nrofdests, dests);
572 RegCloseKey(hkeyPrinters);
573 return hadprinter;
575 #endif
577 static BOOL
578 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
579 PRINTER_INFO_2A pinfo2a;
580 char *e,*s,*name,*prettyname,*devname;
581 BOOL ret = FALSE, set_default = FALSE;
582 char *port = NULL, *devline,*env_default;
583 HKEY hkeyPrinter, hkeyPrinters, hkey;
585 while (isspace(*pent)) pent++;
586 s = strchr(pent,':');
587 if(s) *s='\0';
588 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
589 strcpy(name,pent);
590 if(s) {
591 *s=':';
592 pent = s;
593 } else
594 pent = "";
596 TRACE("name=%s entry=%s\n",name, pent);
598 if(ispunct(*name)) { /* a tc entry, not a real printer */
599 TRACE("skipping tc entry\n");
600 goto end;
603 if(strstr(pent,":server")) { /* server only version so skip */
604 TRACE("skipping server entry\n");
605 goto end;
608 /* Determine whether this is a postscript printer. */
610 ret = TRUE;
611 env_default = getenv("PRINTER");
612 prettyname = name;
613 /* Get longest name, usually the one at the right for later display. */
614 while((s=strchr(prettyname,'|'))) {
615 *s = '\0';
616 e = s;
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
620 for(prettyname = s+1; isspace(*prettyname); prettyname++)
623 e = prettyname + strlen(prettyname);
624 while(isspace(*--e)) *e = '\0';
625 TRACE("\t%s\n", debugstr_a(prettyname));
626 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
628 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
629 * if it is too long, we use it as comment below. */
630 devname = prettyname;
631 if (strlen(devname)>=CCHDEVICENAME-1)
632 devname = name;
633 if (strlen(devname)>=CCHDEVICENAME-1) {
634 ret = FALSE;
635 goto end;
638 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
639 sprintf(port,"LPR:%s",name);
641 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
642 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
643 sprintf(devline, "WINEPS.DRV,%s", port);
644 WriteProfileStringA("devices", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
647 RegCloseKey(hkey);
650 lstrcatA(devline, ",15,45");
651 WriteProfileStringA("PrinterPorts", devname, devline);
652 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
653 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
654 RegCloseKey(hkey);
657 HeapFree(GetProcessHeap(),0,devline);
659 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
660 ERROR_SUCCESS) {
661 ERR("Can't create Printers key\n");
662 ret = FALSE;
663 goto end;
665 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
666 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
667 and continue */
668 TRACE("Printer already exists\n");
669 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
670 RegCloseKey(hkeyPrinter);
671 } else {
672 static CHAR data_type[] = "RAW",
673 print_proc[] = "WinPrint",
674 comment[] = "WINEPS Printer using LPR",
675 params[] = "<parameters?>",
676 share_name[] = "<share name?>",
677 sep_file[] = "<sep file?>";
679 add_printer_driver(devname);
681 memset(&pinfo2a,0,sizeof(pinfo2a));
682 pinfo2a.pPrinterName = devname;
683 pinfo2a.pDatatype = data_type;
684 pinfo2a.pPrintProcessor = print_proc;
685 pinfo2a.pDriverName = devname;
686 pinfo2a.pComment = comment;
687 pinfo2a.pLocation = prettyname;
688 pinfo2a.pPortName = port;
689 pinfo2a.pParameters = params;
690 pinfo2a.pShareName = share_name;
691 pinfo2a.pSepFile = sep_file;
693 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
694 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
695 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
698 RegCloseKey(hkeyPrinters);
700 if (isfirst || set_default)
701 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
703 end:
704 HeapFree(GetProcessHeap(), 0, port);
705 HeapFree(GetProcessHeap(), 0, name);
706 return ret;
709 static BOOL
710 PRINTCAP_LoadPrinters(void) {
711 BOOL hadprinter = FALSE;
712 char buf[200];
713 FILE *f;
714 char *pent = NULL;
715 BOOL had_bash = FALSE;
717 f = fopen("/etc/printcap","r");
718 if (!f)
719 return FALSE;
721 while(fgets(buf,sizeof(buf),f)) {
722 char *start, *end;
724 end=strchr(buf,'\n');
725 if (end) *end='\0';
727 start = buf;
728 while(isspace(*start)) start++;
729 if(*start == '#' || *start == '\0')
730 continue;
732 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
733 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
734 HeapFree(GetProcessHeap(),0,pent);
735 pent = NULL;
738 if (end && *--end == '\\') {
739 *end = '\0';
740 had_bash = TRUE;
741 } else
742 had_bash = FALSE;
744 if (pent) {
745 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
746 strcat(pent,start);
747 } else {
748 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
749 strcpy(pent,start);
753 if(pent) {
754 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
755 HeapFree(GetProcessHeap(),0,pent);
757 fclose(f);
758 return hadprinter;
761 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
763 if (value)
764 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
765 (lstrlenW(value) + 1) * sizeof(WCHAR));
766 else
767 return ERROR_FILE_NOT_FOUND;
770 /******************************************************************
771 * monitor_unload [internal]
773 * release a printmonitor and unload it from memory, when needed
776 static void monitor_unload(monitor_t * pm)
778 if (pm == NULL) return;
779 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
781 EnterCriticalSection(&monitor_handles_cs);
783 if (pm->refcount) pm->refcount--;
785 if (pm->refcount == 0) {
786 list_remove(&pm->entry);
787 FreeLibrary(pm->hdll);
788 HeapFree(GetProcessHeap(), 0, pm->name);
789 HeapFree(GetProcessHeap(), 0, pm->dllname);
790 HeapFree(GetProcessHeap(), 0, pm);
792 LeaveCriticalSection(&monitor_handles_cs);
795 /******************************************************************
796 * monitor_load [internal]
798 * load a printmonitor, get the dllname from the registry, when needed
799 * initialize the monitor and dump found function-pointers
801 * On failure, SetLastError() is called and NULL is returned
804 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
806 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
807 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
808 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
809 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
810 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
812 monitor_t * pm = NULL;
813 monitor_t * cursor;
814 LPWSTR regroot = NULL;
815 LPWSTR driver = dllname;
817 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
818 /* Is the Monitor already loaded? */
819 EnterCriticalSection(&monitor_handles_cs);
821 if (name) {
822 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
824 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
825 pm = cursor;
826 break;
831 if (pm == NULL) {
832 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
833 if (pm == NULL) goto cleanup;
834 list_add_tail(&monitor_handles, &pm->entry);
836 pm->refcount++;
838 if (pm->name == NULL) {
839 /* Load the monitor */
840 LPMONITOREX pmonitorEx;
841 DWORD len;
843 if (name) {
844 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
845 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
848 if (regroot) {
849 lstrcpyW(regroot, MonitorsW);
850 lstrcatW(regroot, name);
851 /* Get the Driver from the Registry */
852 if (driver == NULL) {
853 HKEY hroot;
854 DWORD namesize;
855 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
856 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
857 &namesize) == ERROR_SUCCESS) {
858 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
859 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
861 RegCloseKey(hroot);
866 pm->name = strdupW(name);
867 pm->dllname = strdupW(driver);
869 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
870 monitor_unload(pm);
871 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
872 pm = NULL;
873 goto cleanup;
876 pm->hdll = LoadLibraryW(driver);
877 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
879 if (pm->hdll == NULL) {
880 monitor_unload(pm);
881 SetLastError(ERROR_MOD_NOT_FOUND);
882 pm = NULL;
883 goto cleanup;
886 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
887 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
888 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
889 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
890 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
893 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
894 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
895 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
896 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
897 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
899 if (pInitializePrintMonitorUI != NULL) {
900 pm->monitorUI = pInitializePrintMonitorUI();
901 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
902 if (pm->monitorUI) {
903 TRACE( "0x%08x: dwMonitorSize (%d)\n",
904 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
909 if (pInitializePrintMonitor && regroot) {
910 pmonitorEx = pInitializePrintMonitor(regroot);
911 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
912 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
914 if (pmonitorEx) {
915 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
916 pm->monitor = &(pmonitorEx->Monitor);
920 if (pm->monitor) {
921 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
925 if (!pm->monitor && regroot) {
926 if (pInitializePrintMonitor2 != NULL) {
927 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
929 if (pInitializeMonitorEx != NULL) {
930 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
932 if (pInitializeMonitor != NULL) {
933 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
936 if (!pm->monitor && !pm->monitorUI) {
937 monitor_unload(pm);
938 SetLastError(ERROR_PROC_NOT_FOUND);
939 pm = NULL;
942 cleanup:
943 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
944 pm->refcount++;
945 pm_localport = pm;
947 LeaveCriticalSection(&monitor_handles_cs);
948 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
949 HeapFree(GetProcessHeap(), 0, regroot);
950 TRACE("=> %p\n", pm);
951 return pm;
954 /******************************************************************
955 * monitor_loadui [internal]
957 * load the userinterface-dll for a given portmonitor
959 * On failure, NULL is returned
962 static monitor_t * monitor_loadui(monitor_t * pm)
964 monitor_t * pui = NULL;
965 LPWSTR buffer[MAX_PATH];
966 HANDLE hXcv;
967 DWORD len;
968 DWORD res;
970 if (pm == NULL) return NULL;
971 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
973 /* Try the Portmonitor first; works for many monitors */
974 if (pm->monitorUI) {
975 EnterCriticalSection(&monitor_handles_cs);
976 pm->refcount++;
977 LeaveCriticalSection(&monitor_handles_cs);
978 return pm;
981 /* query the userinterface-dllname from the Portmonitor */
982 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
983 /* building (",XcvMonitor %s",pm->name) not needed yet */
984 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
985 TRACE("got %u with %p\n", res, hXcv);
986 if (res) {
987 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
988 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
989 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
990 pm->monitor->pfnXcvClosePort(hXcv);
993 return pui;
997 /******************************************************************
998 * monitor_load_by_port [internal]
1000 * load a printmonitor for a given port
1002 * On failure, NULL is returned
1005 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1007 HKEY hroot;
1008 HKEY hport;
1009 LPWSTR buffer;
1010 monitor_t * pm = NULL;
1011 DWORD registered = 0;
1012 DWORD id = 0;
1013 DWORD len;
1015 TRACE("(%s)\n", debugstr_w(portname));
1017 /* Try the Local Monitor first */
1018 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1019 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1020 /* found the portname */
1021 RegCloseKey(hroot);
1022 return monitor_load(LocalPortW, NULL);
1024 RegCloseKey(hroot);
1027 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1028 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1029 if (buffer == NULL) return NULL;
1031 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1032 EnterCriticalSection(&monitor_handles_cs);
1033 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1035 while ((pm == NULL) && (id < registered)) {
1036 buffer[0] = '\0';
1037 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1038 TRACE("testing %s\n", debugstr_w(buffer));
1039 len = lstrlenW(buffer);
1040 lstrcatW(buffer, bs_Ports_bsW);
1041 lstrcatW(buffer, portname);
1042 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1043 RegCloseKey(hport);
1044 buffer[len] = '\0'; /* use only the Monitor-Name */
1045 pm = monitor_load(buffer, NULL);
1047 id++;
1049 LeaveCriticalSection(&monitor_handles_cs);
1050 RegCloseKey(hroot);
1052 HeapFree(GetProcessHeap(), 0, buffer);
1053 return pm;
1056 /******************************************************************
1057 * get_servername_from_name (internal)
1059 * for an external server, a copy of the serverpart from the full name is returned
1062 static LPWSTR get_servername_from_name(LPCWSTR name)
1064 LPWSTR server;
1065 LPWSTR ptr;
1066 WCHAR buffer[MAX_PATH];
1067 DWORD len;
1069 if (name == NULL) return NULL;
1070 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1072 server = strdupW(&name[2]); /* skip over both backslash */
1073 if (server == NULL) return NULL;
1075 /* strip '\' and the printername */
1076 ptr = strchrW(server, '\\');
1077 if (ptr) ptr[0] = '\0';
1079 TRACE("found %s\n", debugstr_w(server));
1081 len = sizeof(buffer)/sizeof(buffer[0]);
1082 if (GetComputerNameW(buffer, &len)) {
1083 if (lstrcmpW(buffer, server) == 0) {
1084 /* The requested Servername is our computername */
1085 HeapFree(GetProcessHeap(), 0, server);
1086 return NULL;
1089 return server;
1092 /******************************************************************
1093 * get_basename_from_name (internal)
1095 * skip over the serverpart from the full name
1098 static LPCWSTR get_basename_from_name(LPCWSTR name)
1100 if (name == NULL) return NULL;
1101 if ((name[0] == '\\') && (name[1] == '\\')) {
1102 /* skip over the servername and search for the following '\' */
1103 name = strchrW(&name[2], '\\');
1104 if ((name) && (name[1])) {
1105 /* found a separator ('\') followed by a name:
1106 skip over the separator and return the rest */
1107 name++;
1109 else
1111 /* no basename present (we found only a servername) */
1112 return NULL;
1115 return name;
1118 /******************************************************************
1119 * get_opened_printer_entry
1120 * Get the first place empty in the opened printer table
1122 * ToDo:
1123 * - pDefault is ignored
1125 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1127 UINT_PTR handle = nb_printer_handles, i;
1128 jobqueue_t *queue = NULL;
1129 opened_printer_t *printer = NULL;
1130 LPWSTR servername;
1131 LPCWSTR printername;
1132 HKEY hkeyPrinters;
1133 HKEY hkeyPrinter;
1134 DWORD len;
1136 servername = get_servername_from_name(name);
1137 if (servername) {
1138 FIXME("server %s not supported\n", debugstr_w(servername));
1139 HeapFree(GetProcessHeap(), 0, servername);
1140 SetLastError(ERROR_INVALID_PRINTER_NAME);
1141 return NULL;
1144 printername = get_basename_from_name(name);
1145 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1147 /* an empty printername is invalid */
1148 if (printername && (!printername[0])) {
1149 SetLastError(ERROR_INVALID_PARAMETER);
1150 return NULL;
1153 EnterCriticalSection(&printer_handles_cs);
1155 for (i = 0; i < nb_printer_handles; i++)
1157 if (!printer_handles[i])
1159 if(handle == nb_printer_handles)
1160 handle = i;
1162 else
1164 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1165 queue = printer_handles[i]->queue;
1169 if (handle >= nb_printer_handles)
1171 opened_printer_t **new_array;
1172 if (printer_handles)
1173 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1174 (nb_printer_handles + 16) * sizeof(*new_array) );
1175 else
1176 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1177 (nb_printer_handles + 16) * sizeof(*new_array) );
1179 if (!new_array)
1181 handle = 0;
1182 goto end;
1184 printer_handles = new_array;
1185 nb_printer_handles += 16;
1188 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1190 handle = 0;
1191 goto end;
1195 /* clone the base name. This is NULL for the printserver */
1196 printer->printername = strdupW(printername);
1198 /* clone the full name */
1199 printer->name = strdupW(name);
1200 if (name && (!printer->name)) {
1201 handle = 0;
1202 goto end;
1205 if (printername) {
1206 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1207 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1208 /* OpenPrinter(",XcvMonitor " detected */
1209 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1210 printer->pm = monitor_load(&printername[len], NULL);
1211 if (printer->pm == NULL) {
1212 SetLastError(ERROR_UNKNOWN_PORT);
1213 handle = 0;
1214 goto end;
1217 else
1219 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1220 if (strncmpW( printername, XcvPortW, len) == 0) {
1221 /* OpenPrinter(",XcvPort " detected */
1222 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1223 printer->pm = monitor_load_by_port(&printername[len]);
1224 if (printer->pm == NULL) {
1225 SetLastError(ERROR_UNKNOWN_PORT);
1226 handle = 0;
1227 goto end;
1232 if (printer->pm) {
1233 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1234 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1235 pDefault ? pDefault->DesiredAccess : 0,
1236 &printer->hXcv);
1238 if (printer->hXcv == NULL) {
1239 SetLastError(ERROR_INVALID_PARAMETER);
1240 handle = 0;
1241 goto end;
1244 else
1246 /* Does the Printer exist? */
1247 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1248 ERR("Can't create Printers key\n");
1249 handle = 0;
1250 goto end;
1252 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1253 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1254 RegCloseKey(hkeyPrinters);
1255 SetLastError(ERROR_INVALID_PRINTER_NAME);
1256 handle = 0;
1257 goto end;
1259 RegCloseKey(hkeyPrinter);
1260 RegCloseKey(hkeyPrinters);
1263 else
1265 TRACE("using the local printserver\n");
1268 if(queue)
1269 printer->queue = queue;
1270 else
1272 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1273 if (!printer->queue) {
1274 handle = 0;
1275 goto end;
1277 list_init(&printer->queue->jobs);
1278 printer->queue->ref = 0;
1280 InterlockedIncrement(&printer->queue->ref);
1282 printer_handles[handle] = printer;
1283 handle++;
1284 end:
1285 LeaveCriticalSection(&printer_handles_cs);
1286 if (!handle && printer) {
1287 /* Something failed: Free all resources */
1288 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1289 monitor_unload(printer->pm);
1290 HeapFree(GetProcessHeap(), 0, printer->printername);
1291 HeapFree(GetProcessHeap(), 0, printer->name);
1292 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1293 HeapFree(GetProcessHeap(), 0, printer);
1296 return (HANDLE)handle;
1299 /******************************************************************
1300 * get_opened_printer
1301 * Get the pointer to the opened printer referred by the handle
1303 static opened_printer_t *get_opened_printer(HANDLE hprn)
1305 UINT_PTR idx = (UINT_PTR)hprn;
1306 opened_printer_t *ret = NULL;
1308 EnterCriticalSection(&printer_handles_cs);
1310 if ((idx > 0) && (idx <= nb_printer_handles)) {
1311 ret = printer_handles[idx - 1];
1313 LeaveCriticalSection(&printer_handles_cs);
1314 return ret;
1317 /******************************************************************
1318 * get_opened_printer_name
1319 * Get the pointer to the opened printer name referred by the handle
1321 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1323 opened_printer_t *printer = get_opened_printer(hprn);
1324 if(!printer) return NULL;
1325 return printer->name;
1328 /******************************************************************
1329 * WINSPOOL_GetOpenedPrinterRegKey
1332 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1334 LPCWSTR name = get_opened_printer_name(hPrinter);
1335 DWORD ret;
1336 HKEY hkeyPrinters;
1338 if(!name) return ERROR_INVALID_HANDLE;
1340 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1341 ERROR_SUCCESS)
1342 return ret;
1344 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1346 ERR("Can't find opened printer %s in registry\n",
1347 debugstr_w(name));
1348 RegCloseKey(hkeyPrinters);
1349 return ERROR_INVALID_PRINTER_NAME; /* ? */
1351 RegCloseKey(hkeyPrinters);
1352 return ERROR_SUCCESS;
1355 void WINSPOOL_LoadSystemPrinters(void)
1357 HKEY hkey, hkeyPrinters;
1358 HANDLE hprn;
1359 DWORD needed, num, i;
1360 WCHAR PrinterName[256];
1361 BOOL done = FALSE;
1363 /* This ensures that all printer entries have a valid Name value. If causes
1364 problems later if they don't. If one is found to be missed we create one
1365 and set it equal to the name of the key */
1366 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1367 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1368 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1369 for(i = 0; i < num; i++) {
1370 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1371 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1372 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1373 set_reg_szW(hkey, NameW, PrinterName);
1375 RegCloseKey(hkey);
1380 RegCloseKey(hkeyPrinters);
1383 /* We want to avoid calling AddPrinter on printers as much as
1384 possible, because on cups printers this will (eventually) lead
1385 to a call to cupsGetPPD which takes forever, even with non-cups
1386 printers AddPrinter takes a while. So we'll tag all printers that
1387 were automatically added last time around, if they still exist
1388 we'll leave them be otherwise we'll delete them. */
1389 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1390 if(needed) {
1391 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1392 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1393 for(i = 0; i < num; i++) {
1394 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1395 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1396 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1397 DWORD dw = 1;
1398 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1399 RegCloseKey(hkey);
1401 ClosePrinter(hprn);
1406 HeapFree(GetProcessHeap(), 0, pi);
1410 #ifdef SONAME_LIBCUPS
1411 done = CUPS_LoadPrinters();
1412 #endif
1414 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1415 PRINTCAP_LoadPrinters();
1417 /* Now enumerate the list again and delete any printers that are still tagged */
1418 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1419 if(needed) {
1420 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1421 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1422 for(i = 0; i < num; i++) {
1423 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1424 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1425 BOOL delete_driver = FALSE;
1426 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1427 DWORD dw, type, size = sizeof(dw);
1428 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1429 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1430 DeletePrinter(hprn);
1431 delete_driver = TRUE;
1433 RegCloseKey(hkey);
1435 ClosePrinter(hprn);
1436 if(delete_driver)
1437 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1442 HeapFree(GetProcessHeap(), 0, pi);
1445 return;
1449 /******************************************************************
1450 * get_job
1452 * Get the pointer to the specified job.
1453 * Should hold the printer_handles_cs before calling.
1455 static job_t *get_job(HANDLE hprn, DWORD JobId)
1457 opened_printer_t *printer = get_opened_printer(hprn);
1458 job_t *job;
1460 if(!printer) return NULL;
1461 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1463 if(job->job_id == JobId)
1464 return job;
1466 return NULL;
1469 /***********************************************************
1470 * DEVMODEcpyAtoW
1472 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1474 BOOL Formname;
1475 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1476 DWORD size;
1478 Formname = (dmA->dmSize > off_formname);
1479 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1480 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1481 dmW->dmDeviceName, CCHDEVICENAME);
1482 if(!Formname) {
1483 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1484 dmA->dmSize - CCHDEVICENAME);
1485 } else {
1486 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1487 off_formname - CCHDEVICENAME);
1488 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1489 dmW->dmFormName, CCHFORMNAME);
1490 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1491 (off_formname + CCHFORMNAME));
1493 dmW->dmSize = size;
1494 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1495 dmA->dmDriverExtra);
1496 return dmW;
1499 /***********************************************************
1500 * DEVMODEdupWtoA
1501 * Creates an ansi copy of supplied devmode
1503 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1505 LPDEVMODEA dmA;
1506 DWORD size;
1508 if (!dmW) return NULL;
1509 size = dmW->dmSize - CCHDEVICENAME -
1510 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1512 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1513 if (!dmA) return NULL;
1515 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1516 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1518 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1519 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1520 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1522 else
1524 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1525 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1526 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1527 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1529 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1532 dmA->dmSize = size;
1533 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1534 return dmA;
1537 /******************************************************************
1538 * convert_printerinfo_W_to_A [internal]
1541 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1542 DWORD level, DWORD outlen, DWORD numentries)
1544 DWORD id = 0;
1545 LPSTR ptr;
1546 INT len;
1548 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1550 len = pi_sizeof[level] * numentries;
1551 ptr = (LPSTR) out + len;
1552 outlen -= len;
1554 /* copy the numbers of all PRINTER_INFO_* first */
1555 memcpy(out, pPrintersW, len);
1557 while (id < numentries) {
1558 switch (level) {
1559 case 1:
1561 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1562 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1564 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1565 if (piW->pDescription) {
1566 piA->pDescription = ptr;
1567 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1568 ptr, outlen, NULL, NULL);
1569 ptr += len;
1570 outlen -= len;
1572 if (piW->pName) {
1573 piA->pName = ptr;
1574 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1575 ptr, outlen, NULL, NULL);
1576 ptr += len;
1577 outlen -= len;
1579 if (piW->pComment) {
1580 piA->pComment = ptr;
1581 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1582 ptr, outlen, NULL, NULL);
1583 ptr += len;
1584 outlen -= len;
1586 break;
1589 case 2:
1591 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1592 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1593 LPDEVMODEA dmA;
1595 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1596 if (piW->pServerName) {
1597 piA->pServerName = ptr;
1598 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1599 ptr, outlen, NULL, NULL);
1600 ptr += len;
1601 outlen -= len;
1603 if (piW->pPrinterName) {
1604 piA->pPrinterName = ptr;
1605 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1606 ptr, outlen, NULL, NULL);
1607 ptr += len;
1608 outlen -= len;
1610 if (piW->pShareName) {
1611 piA->pShareName = ptr;
1612 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1613 ptr, outlen, NULL, NULL);
1614 ptr += len;
1615 outlen -= len;
1617 if (piW->pPortName) {
1618 piA->pPortName = ptr;
1619 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1620 ptr, outlen, NULL, NULL);
1621 ptr += len;
1622 outlen -= len;
1624 if (piW->pDriverName) {
1625 piA->pDriverName = ptr;
1626 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1627 ptr, outlen, NULL, NULL);
1628 ptr += len;
1629 outlen -= len;
1631 if (piW->pComment) {
1632 piA->pComment = ptr;
1633 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1634 ptr, outlen, NULL, NULL);
1635 ptr += len;
1636 outlen -= len;
1638 if (piW->pLocation) {
1639 piA->pLocation = ptr;
1640 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1641 ptr, outlen, NULL, NULL);
1642 ptr += len;
1643 outlen -= len;
1646 dmA = DEVMODEdupWtoA(piW->pDevMode);
1647 if (dmA) {
1648 /* align DEVMODEA to a DWORD boundary */
1649 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1650 ptr += len;
1651 outlen -= len;
1653 piA->pDevMode = (LPDEVMODEA) ptr;
1654 len = dmA->dmSize + dmA->dmDriverExtra;
1655 memcpy(ptr, dmA, len);
1656 HeapFree(GetProcessHeap(), 0, dmA);
1658 ptr += len;
1659 outlen -= len;
1662 if (piW->pSepFile) {
1663 piA->pSepFile = ptr;
1664 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1665 ptr, outlen, NULL, NULL);
1666 ptr += len;
1667 outlen -= len;
1669 if (piW->pPrintProcessor) {
1670 piA->pPrintProcessor = ptr;
1671 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1672 ptr, outlen, NULL, NULL);
1673 ptr += len;
1674 outlen -= len;
1676 if (piW->pDatatype) {
1677 piA->pDatatype = ptr;
1678 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1679 ptr, outlen, NULL, NULL);
1680 ptr += len;
1681 outlen -= len;
1683 if (piW->pParameters) {
1684 piA->pParameters = ptr;
1685 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1686 ptr, outlen, NULL, NULL);
1687 ptr += len;
1688 outlen -= len;
1690 if (piW->pSecurityDescriptor) {
1691 piA->pSecurityDescriptor = NULL;
1692 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1694 break;
1697 case 4:
1699 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1700 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1702 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1704 if (piW->pPrinterName) {
1705 piA->pPrinterName = ptr;
1706 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1707 ptr, outlen, NULL, NULL);
1708 ptr += len;
1709 outlen -= len;
1711 if (piW->pServerName) {
1712 piA->pServerName = ptr;
1713 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1714 ptr, outlen, NULL, NULL);
1715 ptr += len;
1716 outlen -= len;
1718 break;
1721 case 5:
1723 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1724 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1726 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1728 if (piW->pPrinterName) {
1729 piA->pPrinterName = ptr;
1730 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1731 ptr, outlen, NULL, NULL);
1732 ptr += len;
1733 outlen -= len;
1735 if (piW->pPortName) {
1736 piA->pPortName = ptr;
1737 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1738 ptr, outlen, NULL, NULL);
1739 ptr += len;
1740 outlen -= len;
1742 break;
1745 default:
1746 FIXME("for level %u\n", level);
1748 pPrintersW += pi_sizeof[level];
1749 out += pi_sizeof[level];
1750 id++;
1754 /***********************************************************
1755 * PRINTER_INFO_2AtoW
1756 * Creates a unicode copy of PRINTER_INFO_2A on heap
1758 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1760 LPPRINTER_INFO_2W piW;
1761 UNICODE_STRING usBuffer;
1763 if(!piA) return NULL;
1764 piW = HeapAlloc(heap, 0, sizeof(*piW));
1765 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1767 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1768 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1769 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1770 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1771 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1772 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1773 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1774 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1775 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1776 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1777 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1778 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1779 return piW;
1782 /***********************************************************
1783 * FREE_PRINTER_INFO_2W
1784 * Free PRINTER_INFO_2W and all strings
1786 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1788 if(!piW) return;
1790 HeapFree(heap,0,piW->pServerName);
1791 HeapFree(heap,0,piW->pPrinterName);
1792 HeapFree(heap,0,piW->pShareName);
1793 HeapFree(heap,0,piW->pPortName);
1794 HeapFree(heap,0,piW->pDriverName);
1795 HeapFree(heap,0,piW->pComment);
1796 HeapFree(heap,0,piW->pLocation);
1797 HeapFree(heap,0,piW->pDevMode);
1798 HeapFree(heap,0,piW->pSepFile);
1799 HeapFree(heap,0,piW->pPrintProcessor);
1800 HeapFree(heap,0,piW->pDatatype);
1801 HeapFree(heap,0,piW->pParameters);
1802 HeapFree(heap,0,piW);
1803 return;
1806 /******************************************************************
1807 * DeviceCapabilities [WINSPOOL.@]
1808 * DeviceCapabilitiesA [WINSPOOL.@]
1811 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1812 LPSTR pOutput, LPDEVMODEA lpdm)
1814 INT ret;
1816 if (!GDI_CallDeviceCapabilities16)
1818 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1819 (LPCSTR)104 );
1820 if (!GDI_CallDeviceCapabilities16) return -1;
1822 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1824 /* If DC_PAPERSIZE map POINT16s to POINTs */
1825 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1826 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1827 POINT *pt = (POINT *)pOutput;
1828 INT i;
1829 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1830 for(i = 0; i < ret; i++, pt++)
1832 pt->x = tmp[i].x;
1833 pt->y = tmp[i].y;
1835 HeapFree( GetProcessHeap(), 0, tmp );
1837 return ret;
1841 /*****************************************************************************
1842 * DeviceCapabilitiesW [WINSPOOL.@]
1844 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1847 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1848 WORD fwCapability, LPWSTR pOutput,
1849 const DEVMODEW *pDevMode)
1851 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1852 LPSTR pDeviceA = strdupWtoA(pDevice);
1853 LPSTR pPortA = strdupWtoA(pPort);
1854 INT ret;
1856 if(pOutput && (fwCapability == DC_BINNAMES ||
1857 fwCapability == DC_FILEDEPENDENCIES ||
1858 fwCapability == DC_PAPERNAMES)) {
1859 /* These need A -> W translation */
1860 INT size = 0, i;
1861 LPSTR pOutputA;
1862 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1863 dmA);
1864 if(ret == -1)
1865 return ret;
1866 switch(fwCapability) {
1867 case DC_BINNAMES:
1868 size = 24;
1869 break;
1870 case DC_PAPERNAMES:
1871 case DC_FILEDEPENDENCIES:
1872 size = 64;
1873 break;
1875 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1876 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1877 dmA);
1878 for(i = 0; i < ret; i++)
1879 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1880 pOutput + (i * size), size);
1881 HeapFree(GetProcessHeap(), 0, pOutputA);
1882 } else {
1883 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1884 (LPSTR)pOutput, dmA);
1886 HeapFree(GetProcessHeap(),0,pPortA);
1887 HeapFree(GetProcessHeap(),0,pDeviceA);
1888 HeapFree(GetProcessHeap(),0,dmA);
1889 return ret;
1892 /******************************************************************
1893 * DocumentPropertiesA [WINSPOOL.@]
1895 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1897 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1898 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1899 LPDEVMODEA pDevModeInput,DWORD fMode )
1901 LPSTR lpName = pDeviceName;
1902 static CHAR port[] = "LPT1:";
1903 LONG ret;
1905 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1906 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1909 if(!pDeviceName) {
1910 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1911 if(!lpNameW) {
1912 ERR("no name from hPrinter?\n");
1913 SetLastError(ERROR_INVALID_HANDLE);
1914 return -1;
1916 lpName = strdupWtoA(lpNameW);
1919 if (!GDI_CallExtDeviceMode16)
1921 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1922 (LPCSTR)102 );
1923 if (!GDI_CallExtDeviceMode16) {
1924 ERR("No CallExtDeviceMode16?\n");
1925 return -1;
1928 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1929 pDevModeInput, NULL, fMode);
1931 if(!pDeviceName)
1932 HeapFree(GetProcessHeap(),0,lpName);
1933 return ret;
1937 /*****************************************************************************
1938 * DocumentPropertiesW (WINSPOOL.@)
1940 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1942 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1943 LPWSTR pDeviceName,
1944 LPDEVMODEW pDevModeOutput,
1945 LPDEVMODEW pDevModeInput, DWORD fMode)
1948 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1949 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1950 LPDEVMODEA pDevModeOutputA = NULL;
1951 LONG ret;
1953 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1954 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1955 fMode);
1956 if(pDevModeOutput) {
1957 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1958 if(ret < 0) return ret;
1959 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1961 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1962 pDevModeInputA, fMode);
1963 if(pDevModeOutput) {
1964 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1965 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1967 if(fMode == 0 && ret > 0)
1968 ret += (CCHDEVICENAME + CCHFORMNAME);
1969 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1970 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1971 return ret;
1974 /******************************************************************
1975 * OpenPrinterA [WINSPOOL.@]
1977 * See OpenPrinterW.
1980 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1981 LPPRINTER_DEFAULTSA pDefault)
1983 UNICODE_STRING lpPrinterNameW;
1984 UNICODE_STRING usBuffer;
1985 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1986 PWSTR pwstrPrinterNameW;
1987 BOOL ret;
1989 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1991 if(pDefault) {
1992 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1993 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1994 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1995 pDefaultW = &DefaultW;
1997 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1998 if(pDefault) {
1999 RtlFreeUnicodeString(&usBuffer);
2000 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2002 RtlFreeUnicodeString(&lpPrinterNameW);
2003 return ret;
2006 /******************************************************************
2007 * OpenPrinterW [WINSPOOL.@]
2009 * Open a Printer / Printserver or a Printer-Object
2011 * PARAMS
2012 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2013 * phPrinter [O] The resulting Handle is stored here
2014 * pDefault [I] PTR to Default Printer Settings or NULL
2016 * RETURNS
2017 * Success: TRUE
2018 * Failure: FALSE
2020 * NOTES
2021 * lpPrinterName is one of:
2022 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2023 *| Printer: "PrinterName"
2024 *| Printer-Object: "PrinterName,Job xxx"
2025 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2026 *| XcvPort: "Servername,XcvPort PortName"
2028 * BUGS
2029 *| Printer-Object not supported
2030 *| pDefaults is ignored
2033 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2036 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2037 if (pDefault) {
2038 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2039 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2042 if(!phPrinter) {
2043 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2044 SetLastError(ERROR_INVALID_PARAMETER);
2045 return FALSE;
2048 /* Get the unique handle of the printer or Printserver */
2049 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2050 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2051 return (*phPrinter != 0);
2054 /******************************************************************
2055 * AddMonitorA [WINSPOOL.@]
2057 * See AddMonitorW.
2060 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2062 LPWSTR nameW = NULL;
2063 INT len;
2064 BOOL res;
2065 LPMONITOR_INFO_2A mi2a;
2066 MONITOR_INFO_2W mi2w;
2068 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2069 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2070 debugstr_a(mi2a ? mi2a->pName : NULL),
2071 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2072 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2074 if (Level != 2) {
2075 SetLastError(ERROR_INVALID_LEVEL);
2076 return FALSE;
2079 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2080 if (mi2a == NULL) {
2081 return FALSE;
2084 if (pName) {
2085 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2086 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2087 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2090 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2091 if (mi2a->pName) {
2092 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2093 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2094 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2096 if (mi2a->pEnvironment) {
2097 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2098 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2099 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2101 if (mi2a->pDLLName) {
2102 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2103 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2104 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2107 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2109 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2110 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2111 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2113 HeapFree(GetProcessHeap(), 0, nameW);
2114 return (res);
2117 /******************************************************************************
2118 * AddMonitorW [WINSPOOL.@]
2120 * Install a Printmonitor
2122 * PARAMS
2123 * pName [I] Servername or NULL (local Computer)
2124 * Level [I] Structure-Level (Must be 2)
2125 * pMonitors [I] PTR to MONITOR_INFO_2
2127 * RETURNS
2128 * Success: TRUE
2129 * Failure: FALSE
2131 * NOTES
2132 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2135 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2137 LPMONITOR_INFO_2W mi2w;
2139 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2140 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2141 debugstr_w(mi2w ? mi2w->pName : NULL),
2142 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2143 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2145 if ((backend == NULL) && !load_backend()) return FALSE;
2147 if (Level != 2) {
2148 SetLastError(ERROR_INVALID_LEVEL);
2149 return FALSE;
2152 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2153 if (mi2w == NULL) {
2154 return FALSE;
2157 return backend->fpAddMonitor(pName, Level, pMonitors);
2160 /******************************************************************
2161 * DeletePrinterDriverA [WINSPOOL.@]
2164 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2166 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2169 /******************************************************************
2170 * DeletePrinterDriverW [WINSPOOL.@]
2173 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2175 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2178 /******************************************************************
2179 * DeleteMonitorA [WINSPOOL.@]
2181 * See DeleteMonitorW.
2184 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2186 LPWSTR nameW = NULL;
2187 LPWSTR EnvironmentW = NULL;
2188 LPWSTR MonitorNameW = NULL;
2189 BOOL res;
2190 INT len;
2192 if (pName) {
2193 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2194 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2195 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2198 if (pEnvironment) {
2199 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2200 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2201 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2203 if (pMonitorName) {
2204 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2205 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2209 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2211 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2212 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2213 HeapFree(GetProcessHeap(), 0, nameW);
2214 return (res);
2217 /******************************************************************
2218 * DeleteMonitorW [WINSPOOL.@]
2220 * Delete a specific Printmonitor from a Printing-Environment
2222 * PARAMS
2223 * pName [I] Servername or NULL (local Computer)
2224 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2225 * pMonitorName [I] Name of the Monitor, that should be deleted
2227 * RETURNS
2228 * Success: TRUE
2229 * Failure: FALSE
2231 * NOTES
2232 * pEnvironment is ignored in Windows for the local Computer.
2235 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2238 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2239 debugstr_w(pMonitorName));
2241 if ((backend == NULL) && !load_backend()) return FALSE;
2243 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2247 /******************************************************************
2248 * DeletePortA [WINSPOOL.@]
2250 * See DeletePortW.
2253 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2255 LPWSTR nameW = NULL;
2256 LPWSTR portW = NULL;
2257 INT len;
2258 DWORD res;
2260 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2262 /* convert servername to unicode */
2263 if (pName) {
2264 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2265 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2266 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2269 /* convert portname to unicode */
2270 if (pPortName) {
2271 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2272 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2273 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2276 res = DeletePortW(nameW, hWnd, portW);
2277 HeapFree(GetProcessHeap(), 0, nameW);
2278 HeapFree(GetProcessHeap(), 0, portW);
2279 return res;
2282 /******************************************************************
2283 * DeletePortW [WINSPOOL.@]
2285 * Delete a specific Port
2287 * PARAMS
2288 * pName [I] Servername or NULL (local Computer)
2289 * hWnd [I] Handle to parent Window for the Dialog-Box
2290 * pPortName [I] Name of the Port, that should be deleted
2292 * RETURNS
2293 * Success: TRUE
2294 * Failure: FALSE
2297 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2299 monitor_t * pm;
2300 monitor_t * pui;
2301 DWORD res;
2303 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2305 if (pName && pName[0]) {
2306 SetLastError(ERROR_INVALID_PARAMETER);
2307 return FALSE;
2310 if (!pPortName) {
2311 SetLastError(RPC_X_NULL_REF_POINTER);
2312 return FALSE;
2315 /* an empty Portname is Invalid */
2316 if (!pPortName[0]) {
2317 SetLastError(ERROR_NOT_SUPPORTED);
2318 return FALSE;
2321 pm = monitor_load_by_port(pPortName);
2322 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2323 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2324 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2325 TRACE("got %d with %u\n", res, GetLastError());
2327 else
2329 pui = monitor_loadui(pm);
2330 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2331 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2332 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2333 TRACE("got %d with %u\n", res, GetLastError());
2335 else
2337 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2338 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2340 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2341 SetLastError(ERROR_NOT_SUPPORTED);
2342 res = FALSE;
2344 monitor_unload(pui);
2346 monitor_unload(pm);
2348 TRACE("returning %d with %u\n", res, GetLastError());
2349 return res;
2352 /******************************************************************************
2353 * SetPrinterW [WINSPOOL.@]
2355 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2357 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2358 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2359 return FALSE;
2362 /******************************************************************************
2363 * WritePrinter [WINSPOOL.@]
2365 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2367 opened_printer_t *printer;
2368 BOOL ret = FALSE;
2370 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2372 EnterCriticalSection(&printer_handles_cs);
2373 printer = get_opened_printer(hPrinter);
2374 if(!printer)
2376 SetLastError(ERROR_INVALID_HANDLE);
2377 goto end;
2380 if(!printer->doc)
2382 SetLastError(ERROR_SPL_NO_STARTDOC);
2383 goto end;
2386 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2387 end:
2388 LeaveCriticalSection(&printer_handles_cs);
2389 return ret;
2392 /*****************************************************************************
2393 * AddFormA [WINSPOOL.@]
2395 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2397 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2398 return 1;
2401 /*****************************************************************************
2402 * AddFormW [WINSPOOL.@]
2404 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2406 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2407 return 1;
2410 /*****************************************************************************
2411 * AddJobA [WINSPOOL.@]
2413 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2415 BOOL ret;
2416 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2417 DWORD needed;
2419 if(Level != 1) {
2420 SetLastError(ERROR_INVALID_LEVEL);
2421 return FALSE;
2424 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2426 if(ret) {
2427 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2428 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2429 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2430 if(*pcbNeeded > cbBuf) {
2431 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2432 ret = FALSE;
2433 } else {
2434 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2435 addjobA->JobId = addjobW->JobId;
2436 addjobA->Path = (char *)(addjobA + 1);
2437 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2440 return ret;
2443 /*****************************************************************************
2444 * AddJobW [WINSPOOL.@]
2446 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2448 opened_printer_t *printer;
2449 job_t *job;
2450 BOOL ret = FALSE;
2451 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2452 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2453 WCHAR path[MAX_PATH], filename[MAX_PATH];
2454 DWORD len;
2455 ADDJOB_INFO_1W *addjob;
2457 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2459 EnterCriticalSection(&printer_handles_cs);
2461 printer = get_opened_printer(hPrinter);
2463 if(!printer) {
2464 SetLastError(ERROR_INVALID_HANDLE);
2465 goto end;
2468 if(Level != 1) {
2469 SetLastError(ERROR_INVALID_LEVEL);
2470 goto end;
2473 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2474 if(!job)
2475 goto end;
2477 job->job_id = InterlockedIncrement(&next_job_id);
2479 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2480 if(path[len - 1] != '\\')
2481 path[len++] = '\\';
2482 memcpy(path + len, spool_path, sizeof(spool_path));
2483 sprintfW(filename, fmtW, path, job->job_id);
2485 len = strlenW(filename);
2486 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2487 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2488 job->document_title = strdupW(default_doc_title);
2489 list_add_tail(&printer->queue->jobs, &job->entry);
2491 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2492 if(*pcbNeeded <= cbBuf) {
2493 addjob = (ADDJOB_INFO_1W*)pData;
2494 addjob->JobId = job->job_id;
2495 addjob->Path = (WCHAR *)(addjob + 1);
2496 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2497 ret = TRUE;
2498 } else
2499 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2501 end:
2502 LeaveCriticalSection(&printer_handles_cs);
2503 return ret;
2506 /*****************************************************************************
2507 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2509 * Return the PATH for the Print-Processors
2511 * See GetPrintProcessorDirectoryW.
2515 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2516 DWORD level, LPBYTE Info,
2517 DWORD cbBuf, LPDWORD pcbNeeded)
2519 LPWSTR serverW = NULL;
2520 LPWSTR envW = NULL;
2521 BOOL ret;
2522 INT len;
2524 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2525 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2528 if (server) {
2529 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2530 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2531 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2534 if (env) {
2535 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2536 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2537 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2540 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2541 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2543 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2544 cbBuf, pcbNeeded);
2546 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2547 cbBuf, NULL, NULL) > 0;
2550 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2551 HeapFree(GetProcessHeap(), 0, envW);
2552 HeapFree(GetProcessHeap(), 0, serverW);
2553 return ret;
2556 /*****************************************************************************
2557 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2559 * Return the PATH for the Print-Processors
2561 * PARAMS
2562 * server [I] Servername (NT only) or NULL (local Computer)
2563 * env [I] Printing-Environment (see below) or NULL (Default)
2564 * level [I] Structure-Level (must be 1)
2565 * Info [O] PTR to Buffer that receives the Result
2566 * cbBuf [I] Size of Buffer at "Info"
2567 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2568 * required for the Buffer at "Info"
2570 * RETURNS
2571 * Success: TRUE and in pcbNeeded the Bytes used in Info
2572 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2573 * if cbBuf is too small
2575 * Native Values returned in Info on Success:
2576 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2577 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2578 *| win9x(Windows 4.0): "%winsysdir%"
2580 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2582 * BUGS
2583 * Only NULL or "" is supported for server
2586 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2587 DWORD level, LPBYTE Info,
2588 DWORD cbBuf, LPDWORD pcbNeeded)
2590 DWORD needed;
2591 const printenv_t * env_t;
2593 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2594 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2596 if(server != NULL && server[0]) {
2597 FIXME("server not supported: %s\n", debugstr_w(server));
2598 SetLastError(ERROR_INVALID_PARAMETER);
2599 return FALSE;
2602 env_t = validate_envW(env);
2603 if(!env_t) return FALSE; /* environment invalid or unsupported */
2605 if(level != 1) {
2606 WARN("(Level: %d) is ignored in win9x\n", level);
2607 SetLastError(ERROR_INVALID_LEVEL);
2608 return FALSE;
2611 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2612 needed = GetSystemDirectoryW(NULL, 0);
2613 /* add the Size for the Subdirectories */
2614 needed += lstrlenW(spoolprtprocsW);
2615 needed += lstrlenW(env_t->subdir);
2616 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2618 if(pcbNeeded) *pcbNeeded = needed;
2619 TRACE ("required: 0x%x/%d\n", needed, needed);
2620 if (needed > cbBuf) {
2621 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2622 return FALSE;
2624 if(pcbNeeded == NULL) {
2625 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2626 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2627 SetLastError(RPC_X_NULL_REF_POINTER);
2628 return FALSE;
2630 if(Info == NULL) {
2631 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2632 SetLastError(RPC_X_NULL_REF_POINTER);
2633 return FALSE;
2636 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2637 /* add the Subdirectories */
2638 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2639 lstrcatW((LPWSTR) Info, env_t->subdir);
2640 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2641 return TRUE;
2644 /*****************************************************************************
2645 * WINSPOOL_OpenDriverReg [internal]
2647 * opens the registry for the printer drivers depending on the given input
2648 * variable pEnvironment
2650 * RETURNS:
2651 * the opened hkey on success
2652 * NULL on error
2654 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2656 HKEY retval = NULL;
2657 LPWSTR buffer;
2658 const printenv_t * env;
2660 TRACE("(%s, %d)\n",
2661 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2663 if (!pEnvironment || unicode) {
2664 /* pEnvironment was NULL or a Unicode-String: use it direct */
2665 env = validate_envW(pEnvironment);
2667 else
2669 /* pEnvironment was an ANSI-String: convert to unicode first */
2670 LPWSTR buffer;
2671 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2672 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2673 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2674 env = validate_envW(buffer);
2675 HeapFree(GetProcessHeap(), 0, buffer);
2677 if (!env) return NULL;
2679 buffer = HeapAlloc( GetProcessHeap(), 0,
2680 (strlenW(DriversW) + strlenW(env->envname) +
2681 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2682 if(buffer) {
2683 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2684 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2685 HeapFree(GetProcessHeap(), 0, buffer);
2687 return retval;
2690 /*****************************************************************************
2691 * AddPrinterW [WINSPOOL.@]
2693 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2695 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2696 LPDEVMODEA dmA;
2697 LPDEVMODEW dmW;
2698 HANDLE retval;
2699 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2700 LONG size;
2701 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2702 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2703 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2704 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2705 statusW[] = {'S','t','a','t','u','s',0},
2706 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2708 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2710 if(pName != NULL) {
2711 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2712 SetLastError(ERROR_INVALID_PARAMETER);
2713 return 0;
2715 if(Level != 2) {
2716 ERR("Level = %d, unsupported!\n", Level);
2717 SetLastError(ERROR_INVALID_LEVEL);
2718 return 0;
2720 if(!pPrinter) {
2721 SetLastError(ERROR_INVALID_PARAMETER);
2722 return 0;
2724 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2725 ERROR_SUCCESS) {
2726 ERR("Can't create Printers key\n");
2727 return 0;
2729 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2730 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2731 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2732 RegCloseKey(hkeyPrinter);
2733 RegCloseKey(hkeyPrinters);
2734 return 0;
2736 RegCloseKey(hkeyPrinter);
2738 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2739 if(!hkeyDrivers) {
2740 ERR("Can't create Drivers key\n");
2741 RegCloseKey(hkeyPrinters);
2742 return 0;
2744 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2745 ERROR_SUCCESS) {
2746 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2747 RegCloseKey(hkeyPrinters);
2748 RegCloseKey(hkeyDrivers);
2749 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2750 return 0;
2752 RegCloseKey(hkeyDriver);
2753 RegCloseKey(hkeyDrivers);
2755 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2756 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2757 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2758 RegCloseKey(hkeyPrinters);
2759 return 0;
2762 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2763 ERROR_SUCCESS) {
2764 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2765 SetLastError(ERROR_INVALID_PRINTER_NAME);
2766 RegCloseKey(hkeyPrinters);
2767 return 0;
2769 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2770 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2771 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2773 /* See if we can load the driver. We may need the devmode structure anyway
2775 * FIXME:
2776 * Note that DocumentPropertiesW will briefly try to open the printer we
2777 * just create to find a DEVMODEA struct (it will use the WINEPS default
2778 * one in case it is not there, so we are ok).
2780 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2782 if(size < 0) {
2783 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2784 size = sizeof(DEVMODEW);
2786 if(pi->pDevMode)
2787 dmW = pi->pDevMode;
2788 else
2790 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2791 dmW->dmSize = size;
2792 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2794 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2795 HeapFree(GetProcessHeap(),0,dmW);
2796 dmW=NULL;
2798 else
2800 /* set devmode to printer name */
2801 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2805 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2806 and we support these drivers. NT writes DEVMODEW so somehow
2807 we'll need to distinguish between these when we support NT
2808 drivers */
2809 if (dmW)
2811 dmA = DEVMODEdupWtoA(dmW);
2812 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2813 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2814 HeapFree(GetProcessHeap(), 0, dmA);
2815 if(!pi->pDevMode)
2816 HeapFree(GetProcessHeap(), 0, dmW);
2818 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2819 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2820 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2821 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2823 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2824 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2825 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2826 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2827 (LPBYTE)&pi->Priority, sizeof(DWORD));
2828 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2829 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2830 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2831 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2832 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2833 (LPBYTE)&pi->Status, sizeof(DWORD));
2834 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2835 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2837 RegCloseKey(hkeyPrinter);
2838 RegCloseKey(hkeyPrinters);
2839 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2840 ERR("OpenPrinter failing\n");
2841 return 0;
2843 return retval;
2846 /*****************************************************************************
2847 * AddPrinterA [WINSPOOL.@]
2849 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2851 UNICODE_STRING pNameW;
2852 PWSTR pwstrNameW;
2853 PRINTER_INFO_2W *piW;
2854 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2855 HANDLE ret;
2857 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2858 if(Level != 2) {
2859 ERR("Level = %d, unsupported!\n", Level);
2860 SetLastError(ERROR_INVALID_LEVEL);
2861 return 0;
2863 pwstrNameW = asciitounicode(&pNameW,pName);
2864 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2866 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2868 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2869 RtlFreeUnicodeString(&pNameW);
2870 return ret;
2874 /*****************************************************************************
2875 * ClosePrinter [WINSPOOL.@]
2877 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2879 UINT_PTR i = (UINT_PTR)hPrinter;
2880 opened_printer_t *printer = NULL;
2881 BOOL ret = FALSE;
2883 TRACE("(%p)\n", hPrinter);
2885 EnterCriticalSection(&printer_handles_cs);
2887 if ((i > 0) && (i <= nb_printer_handles))
2888 printer = printer_handles[i - 1];
2891 if(printer)
2893 struct list *cursor, *cursor2;
2895 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2896 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2897 printer->hXcv, debugstr_w(printer->name), printer->doc );
2899 if(printer->doc)
2900 EndDocPrinter(hPrinter);
2902 if(InterlockedDecrement(&printer->queue->ref) == 0)
2904 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2906 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2907 ScheduleJob(hPrinter, job->job_id);
2909 HeapFree(GetProcessHeap(), 0, printer->queue);
2911 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2912 monitor_unload(printer->pm);
2913 HeapFree(GetProcessHeap(), 0, printer->printername);
2914 HeapFree(GetProcessHeap(), 0, printer->name);
2915 HeapFree(GetProcessHeap(), 0, printer);
2916 printer_handles[i - 1] = NULL;
2917 ret = TRUE;
2919 LeaveCriticalSection(&printer_handles_cs);
2920 return ret;
2923 /*****************************************************************************
2924 * DeleteFormA [WINSPOOL.@]
2926 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2928 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2929 return 1;
2932 /*****************************************************************************
2933 * DeleteFormW [WINSPOOL.@]
2935 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2937 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2938 return 1;
2941 /*****************************************************************************
2942 * DeletePrinter [WINSPOOL.@]
2944 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2946 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2947 HKEY hkeyPrinters, hkey;
2949 if(!lpNameW) {
2950 SetLastError(ERROR_INVALID_HANDLE);
2951 return FALSE;
2953 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2954 RegDeleteTreeW(hkeyPrinters, lpNameW);
2955 RegCloseKey(hkeyPrinters);
2957 WriteProfileStringW(devicesW, lpNameW, NULL);
2958 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2960 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2961 RegDeleteValueW(hkey, lpNameW);
2962 RegCloseKey(hkey);
2965 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2966 RegDeleteValueW(hkey, lpNameW);
2967 RegCloseKey(hkey);
2969 return TRUE;
2972 /*****************************************************************************
2973 * SetPrinterA [WINSPOOL.@]
2975 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2976 DWORD Command)
2978 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2979 return FALSE;
2982 /*****************************************************************************
2983 * SetJobA [WINSPOOL.@]
2985 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2986 LPBYTE pJob, DWORD Command)
2988 BOOL ret;
2989 LPBYTE JobW;
2990 UNICODE_STRING usBuffer;
2992 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2994 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2995 are all ignored by SetJob, so we don't bother copying them */
2996 switch(Level)
2998 case 0:
2999 JobW = NULL;
3000 break;
3001 case 1:
3003 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3004 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3006 JobW = (LPBYTE)info1W;
3007 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3008 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3009 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3010 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3011 info1W->Status = info1A->Status;
3012 info1W->Priority = info1A->Priority;
3013 info1W->Position = info1A->Position;
3014 info1W->PagesPrinted = info1A->PagesPrinted;
3015 break;
3017 case 2:
3019 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3020 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3022 JobW = (LPBYTE)info2W;
3023 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3024 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3025 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3026 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3027 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3028 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3029 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3030 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3031 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3032 info2W->Status = info2A->Status;
3033 info2W->Priority = info2A->Priority;
3034 info2W->Position = info2A->Position;
3035 info2W->StartTime = info2A->StartTime;
3036 info2W->UntilTime = info2A->UntilTime;
3037 info2W->PagesPrinted = info2A->PagesPrinted;
3038 break;
3040 case 3:
3041 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3042 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3043 break;
3044 default:
3045 SetLastError(ERROR_INVALID_LEVEL);
3046 return FALSE;
3049 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3051 switch(Level)
3053 case 1:
3055 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3056 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3057 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3058 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3059 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3060 break;
3062 case 2:
3064 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3065 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3066 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3067 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3068 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3069 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3070 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3071 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3072 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3073 break;
3076 HeapFree(GetProcessHeap(), 0, JobW);
3078 return ret;
3081 /*****************************************************************************
3082 * SetJobW [WINSPOOL.@]
3084 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3085 LPBYTE pJob, DWORD Command)
3087 BOOL ret = FALSE;
3088 job_t *job;
3090 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3091 FIXME("Ignoring everything other than document title\n");
3093 EnterCriticalSection(&printer_handles_cs);
3094 job = get_job(hPrinter, JobId);
3095 if(!job)
3096 goto end;
3098 switch(Level)
3100 case 0:
3101 break;
3102 case 1:
3104 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3105 HeapFree(GetProcessHeap(), 0, job->document_title);
3106 job->document_title = strdupW(info1->pDocument);
3107 break;
3109 case 2:
3111 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3112 HeapFree(GetProcessHeap(), 0, job->document_title);
3113 job->document_title = strdupW(info2->pDocument);
3114 break;
3116 case 3:
3117 break;
3118 default:
3119 SetLastError(ERROR_INVALID_LEVEL);
3120 goto end;
3122 ret = TRUE;
3123 end:
3124 LeaveCriticalSection(&printer_handles_cs);
3125 return ret;
3128 /*****************************************************************************
3129 * EndDocPrinter [WINSPOOL.@]
3131 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3133 opened_printer_t *printer;
3134 BOOL ret = FALSE;
3135 TRACE("(%p)\n", hPrinter);
3137 EnterCriticalSection(&printer_handles_cs);
3139 printer = get_opened_printer(hPrinter);
3140 if(!printer)
3142 SetLastError(ERROR_INVALID_HANDLE);
3143 goto end;
3146 if(!printer->doc)
3148 SetLastError(ERROR_SPL_NO_STARTDOC);
3149 goto end;
3152 CloseHandle(printer->doc->hf);
3153 ScheduleJob(hPrinter, printer->doc->job_id);
3154 HeapFree(GetProcessHeap(), 0, printer->doc);
3155 printer->doc = NULL;
3156 ret = TRUE;
3157 end:
3158 LeaveCriticalSection(&printer_handles_cs);
3159 return ret;
3162 /*****************************************************************************
3163 * EndPagePrinter [WINSPOOL.@]
3165 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3167 FIXME("(%p): stub\n", hPrinter);
3168 return TRUE;
3171 /*****************************************************************************
3172 * StartDocPrinterA [WINSPOOL.@]
3174 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3176 UNICODE_STRING usBuffer;
3177 DOC_INFO_2W doc2W;
3178 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3179 DWORD ret;
3181 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3182 or one (DOC_INFO_3) extra DWORDs */
3184 switch(Level) {
3185 case 2:
3186 doc2W.JobId = doc2->JobId;
3187 /* fall through */
3188 case 3:
3189 doc2W.dwMode = doc2->dwMode;
3190 /* fall through */
3191 case 1:
3192 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3193 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3194 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3195 break;
3197 default:
3198 SetLastError(ERROR_INVALID_LEVEL);
3199 return FALSE;
3202 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3204 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3205 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3206 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3208 return ret;
3211 /*****************************************************************************
3212 * StartDocPrinterW [WINSPOOL.@]
3214 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3216 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3217 opened_printer_t *printer;
3218 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3219 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3220 JOB_INFO_1W job_info;
3221 DWORD needed, ret = 0;
3222 HANDLE hf;
3223 WCHAR *filename;
3225 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3226 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3227 debugstr_w(doc->pDatatype));
3229 if(Level < 1 || Level > 3)
3231 SetLastError(ERROR_INVALID_LEVEL);
3232 return 0;
3235 EnterCriticalSection(&printer_handles_cs);
3236 printer = get_opened_printer(hPrinter);
3237 if(!printer)
3239 SetLastError(ERROR_INVALID_HANDLE);
3240 goto end;
3243 if(printer->doc)
3245 SetLastError(ERROR_INVALID_PRINTER_STATE);
3246 goto end;
3249 /* Even if we're printing to a file we still add a print job, we'll
3250 just ignore the spool file name */
3252 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3254 ERR("AddJob failed gle %u\n", GetLastError());
3255 goto end;
3258 if(doc->pOutputFile)
3259 filename = doc->pOutputFile;
3260 else
3261 filename = addjob->Path;
3263 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3264 if(hf == INVALID_HANDLE_VALUE)
3265 goto end;
3267 memset(&job_info, 0, sizeof(job_info));
3268 job_info.pDocument = doc->pDocName;
3269 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3271 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3272 printer->doc->hf = hf;
3273 ret = printer->doc->job_id = addjob->JobId;
3274 end:
3275 LeaveCriticalSection(&printer_handles_cs);
3277 return ret;
3280 /*****************************************************************************
3281 * StartPagePrinter [WINSPOOL.@]
3283 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3285 FIXME("(%p): stub\n", hPrinter);
3286 return TRUE;
3289 /*****************************************************************************
3290 * GetFormA [WINSPOOL.@]
3292 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3293 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3295 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3296 Level,pForm,cbBuf,pcbNeeded);
3297 return FALSE;
3300 /*****************************************************************************
3301 * GetFormW [WINSPOOL.@]
3303 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3304 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3306 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3307 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3308 return FALSE;
3311 /*****************************************************************************
3312 * SetFormA [WINSPOOL.@]
3314 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3315 LPBYTE pForm)
3317 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3318 return FALSE;
3321 /*****************************************************************************
3322 * SetFormW [WINSPOOL.@]
3324 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3325 LPBYTE pForm)
3327 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3328 return FALSE;
3331 /*****************************************************************************
3332 * ReadPrinter [WINSPOOL.@]
3334 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3335 LPDWORD pNoBytesRead)
3337 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3338 return FALSE;
3341 /*****************************************************************************
3342 * ResetPrinterA [WINSPOOL.@]
3344 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3346 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3347 return FALSE;
3350 /*****************************************************************************
3351 * ResetPrinterW [WINSPOOL.@]
3353 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3355 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3356 return FALSE;
3359 /*****************************************************************************
3360 * WINSPOOL_GetDWORDFromReg
3362 * Return DWORD associated with ValueName from hkey.
3364 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3366 DWORD sz = sizeof(DWORD), type, value = 0;
3367 LONG ret;
3369 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3371 if(ret != ERROR_SUCCESS) {
3372 WARN("Got ret = %d on name %s\n", ret, ValueName);
3373 return 0;
3375 if(type != REG_DWORD) {
3376 ERR("Got type %d\n", type);
3377 return 0;
3379 return value;
3383 /*****************************************************************************
3384 * get_filename_from_reg [internal]
3386 * Get ValueName from hkey storing result in out
3387 * when the Value in the registry has only a filename, use driverdir as prefix
3388 * outlen is space left in out
3389 * String is stored either as unicode or ascii
3393 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3394 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3396 WCHAR filename[MAX_PATH];
3397 DWORD size;
3398 DWORD type;
3399 LONG ret;
3400 LPWSTR buffer = filename;
3401 LPWSTR ptr;
3403 *needed = 0;
3404 size = sizeof(filename);
3405 buffer[0] = '\0';
3406 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3407 if (ret == ERROR_MORE_DATA) {
3408 TRACE("need dynamic buffer: %u\n", size);
3409 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3410 if (!buffer) {
3411 /* No Memory is bad */
3412 return FALSE;
3414 buffer[0] = '\0';
3415 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3418 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3419 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3420 return FALSE;
3423 ptr = buffer;
3424 while (ptr) {
3425 /* do we have a full path ? */
3426 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3427 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3429 if (!ret) {
3430 /* we must build the full Path */
3431 *needed += dirlen;
3432 if ((out) && (outlen > dirlen)) {
3433 if (unicode) {
3434 lstrcpyW((LPWSTR)out, driverdir);
3436 else
3438 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3440 out += dirlen;
3441 outlen -= dirlen;
3443 else
3444 out = NULL;
3447 /* write the filename */
3448 if (unicode) {
3449 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3450 if ((out) && (outlen >= size)) {
3451 lstrcpyW((LPWSTR)out, ptr);
3452 out += size;
3453 outlen -= size;
3455 else
3456 out = NULL;
3458 else
3460 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3461 if ((out) && (outlen >= size)) {
3462 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3463 out += size;
3464 outlen -= size;
3466 else
3467 out = NULL;
3469 *needed += size;
3470 ptr += lstrlenW(ptr)+1;
3471 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3474 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3476 /* write the multisz-termination */
3477 if (type == REG_MULTI_SZ) {
3478 size = (unicode) ? sizeof(WCHAR) : 1;
3480 *needed += size;
3481 if (out && (outlen >= size)) {
3482 memset (out, 0, size);
3485 return TRUE;
3488 /*****************************************************************************
3489 * WINSPOOL_GetStringFromReg
3491 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3492 * String is stored either as unicode or ascii.
3493 * Bit of a hack here to get the ValueName if we want ascii.
3495 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3496 DWORD buflen, DWORD *needed,
3497 BOOL unicode)
3499 DWORD sz = buflen, type;
3500 LONG ret;
3502 if(unicode)
3503 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3504 else {
3505 LPSTR ValueNameA = strdupWtoA(ValueName);
3506 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3507 HeapFree(GetProcessHeap(),0,ValueNameA);
3509 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3510 WARN("Got ret = %d\n", ret);
3511 *needed = 0;
3512 return FALSE;
3514 /* add space for terminating '\0' */
3515 sz += unicode ? sizeof(WCHAR) : 1;
3516 *needed = sz;
3518 if (ptr)
3519 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3521 return TRUE;
3524 /*****************************************************************************
3525 * WINSPOOL_GetDefaultDevMode
3527 * Get a default DevMode values for wineps.
3528 * FIXME - use ppd.
3531 static void WINSPOOL_GetDefaultDevMode(
3532 LPBYTE ptr,
3533 DWORD buflen, DWORD *needed,
3534 BOOL unicode)
3536 DEVMODEA dm;
3537 static const char szwps[] = "wineps.drv";
3539 /* fill default DEVMODE - should be read from ppd... */
3540 ZeroMemory( &dm, sizeof(dm) );
3541 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3542 dm.dmSpecVersion = DM_SPECVERSION;
3543 dm.dmDriverVersion = 1;
3544 dm.dmSize = sizeof(DEVMODEA);
3545 dm.dmDriverExtra = 0;
3546 dm.dmFields =
3547 DM_ORIENTATION | DM_PAPERSIZE |
3548 DM_PAPERLENGTH | DM_PAPERWIDTH |
3549 DM_SCALE |
3550 DM_COPIES |
3551 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3552 DM_YRESOLUTION | DM_TTOPTION;
3554 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3555 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3556 dm.u1.s1.dmPaperLength = 2970;
3557 dm.u1.s1.dmPaperWidth = 2100;
3559 dm.u1.s1.dmScale = 100;
3560 dm.u1.s1.dmCopies = 1;
3561 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3562 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3563 /* dm.dmColor */
3564 /* dm.dmDuplex */
3565 dm.dmYResolution = 300; /* 300dpi */
3566 dm.dmTTOption = DMTT_BITMAP;
3567 /* dm.dmCollate */
3568 /* dm.dmFormName */
3569 /* dm.dmLogPixels */
3570 /* dm.dmBitsPerPel */
3571 /* dm.dmPelsWidth */
3572 /* dm.dmPelsHeight */
3573 /* dm.u2.dmDisplayFlags */
3574 /* dm.dmDisplayFrequency */
3575 /* dm.dmICMMethod */
3576 /* dm.dmICMIntent */
3577 /* dm.dmMediaType */
3578 /* dm.dmDitherType */
3579 /* dm.dmReserved1 */
3580 /* dm.dmReserved2 */
3581 /* dm.dmPanningWidth */
3582 /* dm.dmPanningHeight */
3584 if(unicode) {
3585 if(buflen >= sizeof(DEVMODEW)) {
3586 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3587 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3588 HeapFree(GetProcessHeap(),0,pdmW);
3590 *needed = sizeof(DEVMODEW);
3592 else
3594 if(buflen >= sizeof(DEVMODEA)) {
3595 memcpy(ptr, &dm, sizeof(DEVMODEA));
3597 *needed = sizeof(DEVMODEA);
3601 /*****************************************************************************
3602 * WINSPOOL_GetDevModeFromReg
3604 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3605 * DevMode is stored either as unicode or ascii.
3607 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3608 LPBYTE ptr,
3609 DWORD buflen, DWORD *needed,
3610 BOOL unicode)
3612 DWORD sz = buflen, type;
3613 LONG ret;
3615 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3616 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3617 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3618 if (sz < sizeof(DEVMODEA))
3620 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3621 return FALSE;
3623 /* ensures that dmSize is not erratically bogus if registry is invalid */
3624 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3625 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3626 if(unicode) {
3627 sz += (CCHDEVICENAME + CCHFORMNAME);
3628 if(buflen >= sz) {
3629 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3630 memcpy(ptr, dmW, sz);
3631 HeapFree(GetProcessHeap(),0,dmW);
3634 *needed = sz;
3635 return TRUE;
3638 /*********************************************************************
3639 * WINSPOOL_GetPrinter_1
3641 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3642 * The strings are either stored as unicode or ascii.
3644 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3645 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3646 BOOL unicode)
3648 DWORD size, left = cbBuf;
3649 BOOL space = (cbBuf > 0);
3650 LPBYTE ptr = buf;
3652 *pcbNeeded = 0;
3654 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3655 unicode)) {
3656 if(space && size <= left) {
3657 pi1->pName = (LPWSTR)ptr;
3658 ptr += size;
3659 left -= size;
3660 } else
3661 space = FALSE;
3662 *pcbNeeded += size;
3665 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3666 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3667 unicode)) {
3668 if(space && size <= left) {
3669 pi1->pDescription = (LPWSTR)ptr;
3670 ptr += size;
3671 left -= size;
3672 } else
3673 space = FALSE;
3674 *pcbNeeded += size;
3677 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3678 unicode)) {
3679 if(space && size <= left) {
3680 pi1->pComment = (LPWSTR)ptr;
3681 ptr += size;
3682 left -= size;
3683 } else
3684 space = FALSE;
3685 *pcbNeeded += size;
3688 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3690 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3691 memset(pi1, 0, sizeof(*pi1));
3693 return space;
3695 /*********************************************************************
3696 * WINSPOOL_GetPrinter_2
3698 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3699 * The strings are either stored as unicode or ascii.
3701 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3702 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3703 BOOL unicode)
3705 DWORD size, left = cbBuf;
3706 BOOL space = (cbBuf > 0);
3707 LPBYTE ptr = buf;
3709 *pcbNeeded = 0;
3711 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3712 unicode)) {
3713 if(space && size <= left) {
3714 pi2->pPrinterName = (LPWSTR)ptr;
3715 ptr += size;
3716 left -= size;
3717 } else
3718 space = FALSE;
3719 *pcbNeeded += size;
3721 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3722 unicode)) {
3723 if(space && size <= left) {
3724 pi2->pShareName = (LPWSTR)ptr;
3725 ptr += size;
3726 left -= size;
3727 } else
3728 space = FALSE;
3729 *pcbNeeded += size;
3731 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3732 unicode)) {
3733 if(space && size <= left) {
3734 pi2->pPortName = (LPWSTR)ptr;
3735 ptr += size;
3736 left -= size;
3737 } else
3738 space = FALSE;
3739 *pcbNeeded += size;
3741 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3742 &size, unicode)) {
3743 if(space && size <= left) {
3744 pi2->pDriverName = (LPWSTR)ptr;
3745 ptr += size;
3746 left -= size;
3747 } else
3748 space = FALSE;
3749 *pcbNeeded += size;
3751 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3752 unicode)) {
3753 if(space && size <= left) {
3754 pi2->pComment = (LPWSTR)ptr;
3755 ptr += size;
3756 left -= size;
3757 } else
3758 space = FALSE;
3759 *pcbNeeded += size;
3761 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3762 unicode)) {
3763 if(space && size <= left) {
3764 pi2->pLocation = (LPWSTR)ptr;
3765 ptr += size;
3766 left -= size;
3767 } else
3768 space = FALSE;
3769 *pcbNeeded += size;
3771 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3772 &size, unicode)) {
3773 if(space && size <= left) {
3774 pi2->pDevMode = (LPDEVMODEW)ptr;
3775 ptr += size;
3776 left -= size;
3777 } else
3778 space = FALSE;
3779 *pcbNeeded += size;
3781 else
3783 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3784 if(space && size <= left) {
3785 pi2->pDevMode = (LPDEVMODEW)ptr;
3786 ptr += size;
3787 left -= size;
3788 } else
3789 space = FALSE;
3790 *pcbNeeded += size;
3792 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3793 &size, unicode)) {
3794 if(space && size <= left) {
3795 pi2->pSepFile = (LPWSTR)ptr;
3796 ptr += size;
3797 left -= size;
3798 } else
3799 space = FALSE;
3800 *pcbNeeded += size;
3802 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3803 &size, unicode)) {
3804 if(space && size <= left) {
3805 pi2->pPrintProcessor = (LPWSTR)ptr;
3806 ptr += size;
3807 left -= size;
3808 } else
3809 space = FALSE;
3810 *pcbNeeded += size;
3812 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3813 &size, unicode)) {
3814 if(space && size <= left) {
3815 pi2->pDatatype = (LPWSTR)ptr;
3816 ptr += size;
3817 left -= size;
3818 } else
3819 space = FALSE;
3820 *pcbNeeded += size;
3822 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3823 &size, unicode)) {
3824 if(space && size <= left) {
3825 pi2->pParameters = (LPWSTR)ptr;
3826 ptr += size;
3827 left -= size;
3828 } else
3829 space = FALSE;
3830 *pcbNeeded += size;
3832 if(pi2) {
3833 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3834 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3835 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3836 "Default Priority");
3837 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3838 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3841 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3842 memset(pi2, 0, sizeof(*pi2));
3844 return space;
3847 /*********************************************************************
3848 * WINSPOOL_GetPrinter_4
3850 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3852 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3853 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3854 BOOL unicode)
3856 DWORD size, left = cbBuf;
3857 BOOL space = (cbBuf > 0);
3858 LPBYTE ptr = buf;
3860 *pcbNeeded = 0;
3862 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3863 unicode)) {
3864 if(space && size <= left) {
3865 pi4->pPrinterName = (LPWSTR)ptr;
3866 ptr += size;
3867 left -= size;
3868 } else
3869 space = FALSE;
3870 *pcbNeeded += size;
3872 if(pi4) {
3873 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3876 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3877 memset(pi4, 0, sizeof(*pi4));
3879 return space;
3882 /*********************************************************************
3883 * WINSPOOL_GetPrinter_5
3885 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3887 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3888 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3889 BOOL unicode)
3891 DWORD size, left = cbBuf;
3892 BOOL space = (cbBuf > 0);
3893 LPBYTE ptr = buf;
3895 *pcbNeeded = 0;
3897 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3898 unicode)) {
3899 if(space && size <= left) {
3900 pi5->pPrinterName = (LPWSTR)ptr;
3901 ptr += size;
3902 left -= size;
3903 } else
3904 space = FALSE;
3905 *pcbNeeded += size;
3907 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3908 unicode)) {
3909 if(space && size <= left) {
3910 pi5->pPortName = (LPWSTR)ptr;
3911 ptr += size;
3912 left -= size;
3913 } else
3914 space = FALSE;
3915 *pcbNeeded += size;
3917 if(pi5) {
3918 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3919 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3920 "dnsTimeout");
3921 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3922 "txTimeout");
3925 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3926 memset(pi5, 0, sizeof(*pi5));
3928 return space;
3931 /*********************************************************************
3932 * WINSPOOL_GetPrinter_7
3934 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3936 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3937 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3939 DWORD size, left = cbBuf;
3940 BOOL space = (cbBuf > 0);
3941 LPBYTE ptr = buf;
3943 *pcbNeeded = 0;
3945 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3947 if (space && size <= left) {
3948 pi7->pszObjectGUID = (LPWSTR)ptr;
3949 ptr += size;
3950 left -= size;
3951 } else
3952 space = FALSE;
3953 *pcbNeeded += size;
3955 if (pi7) {
3956 /* We do not have a Directory Service */
3957 pi7->dwAction = DSPRINT_UNPUBLISH;
3960 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3961 memset(pi7, 0, sizeof(*pi7));
3963 return space;
3966 /*********************************************************************
3967 * WINSPOOL_GetPrinter_9
3969 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3970 * The strings are either stored as unicode or ascii.
3972 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3973 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3975 DWORD size;
3976 BOOL space = (cbBuf > 0);
3978 *pcbNeeded = 0;
3980 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3981 if(space && size <= cbBuf) {
3982 pi9->pDevMode = (LPDEVMODEW)buf;
3983 } else
3984 space = FALSE;
3985 *pcbNeeded += size;
3987 else
3989 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3990 if(space && size <= cbBuf) {
3991 pi9->pDevMode = (LPDEVMODEW)buf;
3992 } else
3993 space = FALSE;
3994 *pcbNeeded += size;
3997 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3998 memset(pi9, 0, sizeof(*pi9));
4000 return space;
4003 /*****************************************************************************
4004 * WINSPOOL_GetPrinter
4006 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4007 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4008 * just a collection of pointers to strings.
4010 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4011 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4013 LPCWSTR name;
4014 DWORD size, needed = 0;
4015 LPBYTE ptr = NULL;
4016 HKEY hkeyPrinter, hkeyPrinters;
4017 BOOL ret;
4019 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4021 if (!(name = get_opened_printer_name(hPrinter))) {
4022 SetLastError(ERROR_INVALID_HANDLE);
4023 return FALSE;
4026 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4027 ERROR_SUCCESS) {
4028 ERR("Can't create Printers key\n");
4029 return FALSE;
4031 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4033 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4034 RegCloseKey(hkeyPrinters);
4035 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4036 return FALSE;
4039 switch(Level) {
4040 case 2:
4042 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4044 size = sizeof(PRINTER_INFO_2W);
4045 if(size <= cbBuf) {
4046 ptr = pPrinter + size;
4047 cbBuf -= size;
4048 memset(pPrinter, 0, size);
4049 } else {
4050 pi2 = NULL;
4051 cbBuf = 0;
4053 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4054 unicode);
4055 needed += size;
4056 break;
4059 case 4:
4061 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4063 size = sizeof(PRINTER_INFO_4W);
4064 if(size <= cbBuf) {
4065 ptr = pPrinter + size;
4066 cbBuf -= size;
4067 memset(pPrinter, 0, size);
4068 } else {
4069 pi4 = NULL;
4070 cbBuf = 0;
4072 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4073 unicode);
4074 needed += size;
4075 break;
4079 case 5:
4081 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4083 size = sizeof(PRINTER_INFO_5W);
4084 if(size <= cbBuf) {
4085 ptr = pPrinter + size;
4086 cbBuf -= size;
4087 memset(pPrinter, 0, size);
4088 } else {
4089 pi5 = NULL;
4090 cbBuf = 0;
4093 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4094 unicode);
4095 needed += size;
4096 break;
4100 case 6:
4102 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4104 size = sizeof(PRINTER_INFO_6);
4105 if (size <= cbBuf) {
4106 /* FIXME: We do not update the status yet */
4107 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4108 ret = TRUE;
4109 } else {
4110 ret = FALSE;
4113 needed += size;
4114 break;
4117 case 7:
4119 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4121 size = sizeof(PRINTER_INFO_7W);
4122 if (size <= cbBuf) {
4123 ptr = pPrinter + size;
4124 cbBuf -= size;
4125 memset(pPrinter, 0, size);
4126 } else {
4127 pi7 = NULL;
4128 cbBuf = 0;
4131 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4132 needed += size;
4133 break;
4137 case 9:
4139 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4141 size = sizeof(PRINTER_INFO_9W);
4142 if(size <= cbBuf) {
4143 ptr = pPrinter + size;
4144 cbBuf -= size;
4145 memset(pPrinter, 0, size);
4146 } else {
4147 pi9 = NULL;
4148 cbBuf = 0;
4151 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4152 needed += size;
4153 break;
4157 default:
4158 FIXME("Unimplemented level %d\n", Level);
4159 SetLastError(ERROR_INVALID_LEVEL);
4160 RegCloseKey(hkeyPrinters);
4161 RegCloseKey(hkeyPrinter);
4162 return FALSE;
4165 RegCloseKey(hkeyPrinter);
4166 RegCloseKey(hkeyPrinters);
4168 TRACE("returning %d needed = %d\n", ret, needed);
4169 if(pcbNeeded) *pcbNeeded = needed;
4170 if(!ret)
4171 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4172 return ret;
4175 /*****************************************************************************
4176 * GetPrinterW [WINSPOOL.@]
4178 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4179 DWORD cbBuf, LPDWORD pcbNeeded)
4181 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4182 TRUE);
4185 /*****************************************************************************
4186 * GetPrinterA [WINSPOOL.@]
4188 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4189 DWORD cbBuf, LPDWORD pcbNeeded)
4191 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4192 FALSE);
4195 /*****************************************************************************
4196 * WINSPOOL_EnumPrinters
4198 * Implementation of EnumPrintersA|W
4200 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4201 DWORD dwLevel, LPBYTE lpbPrinters,
4202 DWORD cbBuf, LPDWORD lpdwNeeded,
4203 LPDWORD lpdwReturned, BOOL unicode)
4206 HKEY hkeyPrinters, hkeyPrinter;
4207 WCHAR PrinterName[255];
4208 DWORD needed = 0, number = 0;
4209 DWORD used, i, left;
4210 PBYTE pi, buf;
4212 if(lpbPrinters)
4213 memset(lpbPrinters, 0, cbBuf);
4214 if(lpdwReturned)
4215 *lpdwReturned = 0;
4216 if(lpdwNeeded)
4217 *lpdwNeeded = 0;
4219 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4220 if(dwType == PRINTER_ENUM_DEFAULT)
4221 return TRUE;
4223 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4224 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4225 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4226 if (!dwType) {
4227 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4228 *lpdwNeeded = 0;
4229 *lpdwReturned = 0;
4230 return TRUE;
4235 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4236 FIXME("dwType = %08x\n", dwType);
4237 SetLastError(ERROR_INVALID_FLAGS);
4238 return FALSE;
4241 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4242 ERROR_SUCCESS) {
4243 ERR("Can't create Printers key\n");
4244 return FALSE;
4247 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4248 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4249 RegCloseKey(hkeyPrinters);
4250 ERR("Can't query Printers key\n");
4251 return FALSE;
4253 TRACE("Found %d printers\n", number);
4255 switch(dwLevel) {
4256 case 1:
4257 used = number * sizeof(PRINTER_INFO_1W);
4258 break;
4259 case 2:
4260 used = number * sizeof(PRINTER_INFO_2W);
4261 break;
4262 case 4:
4263 used = number * sizeof(PRINTER_INFO_4W);
4264 break;
4265 case 5:
4266 used = number * sizeof(PRINTER_INFO_5W);
4267 break;
4269 default:
4270 SetLastError(ERROR_INVALID_LEVEL);
4271 RegCloseKey(hkeyPrinters);
4272 return FALSE;
4274 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4276 for(i = 0; i < number; i++) {
4277 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4278 ERROR_SUCCESS) {
4279 ERR("Can't enum key number %d\n", i);
4280 RegCloseKey(hkeyPrinters);
4281 return FALSE;
4283 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4284 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4285 ERROR_SUCCESS) {
4286 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4287 RegCloseKey(hkeyPrinters);
4288 return FALSE;
4291 if(cbBuf > used) {
4292 buf = lpbPrinters + used;
4293 left = cbBuf - used;
4294 } else {
4295 buf = NULL;
4296 left = 0;
4299 switch(dwLevel) {
4300 case 1:
4301 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4302 left, &needed, unicode);
4303 used += needed;
4304 if(pi) pi += sizeof(PRINTER_INFO_1W);
4305 break;
4306 case 2:
4307 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4308 left, &needed, unicode);
4309 used += needed;
4310 if(pi) pi += sizeof(PRINTER_INFO_2W);
4311 break;
4312 case 4:
4313 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4314 left, &needed, unicode);
4315 used += needed;
4316 if(pi) pi += sizeof(PRINTER_INFO_4W);
4317 break;
4318 case 5:
4319 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4320 left, &needed, unicode);
4321 used += needed;
4322 if(pi) pi += sizeof(PRINTER_INFO_5W);
4323 break;
4324 default:
4325 ERR("Shouldn't be here!\n");
4326 RegCloseKey(hkeyPrinter);
4327 RegCloseKey(hkeyPrinters);
4328 return FALSE;
4330 RegCloseKey(hkeyPrinter);
4332 RegCloseKey(hkeyPrinters);
4334 if(lpdwNeeded)
4335 *lpdwNeeded = used;
4337 if(used > cbBuf) {
4338 if(lpbPrinters)
4339 memset(lpbPrinters, 0, cbBuf);
4340 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4341 return FALSE;
4343 if(lpdwReturned)
4344 *lpdwReturned = number;
4345 SetLastError(ERROR_SUCCESS);
4346 return TRUE;
4350 /******************************************************************
4351 * EnumPrintersW [WINSPOOL.@]
4353 * Enumerates the available printers, print servers and print
4354 * providers, depending on the specified flags, name and level.
4356 * RETURNS:
4358 * If level is set to 1:
4359 * Returns an array of PRINTER_INFO_1 data structures in the
4360 * lpbPrinters buffer.
4362 * If level is set to 2:
4363 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4364 * Returns an array of PRINTER_INFO_2 data structures in the
4365 * lpbPrinters buffer. Note that according to MSDN also an
4366 * OpenPrinter should be performed on every remote printer.
4368 * If level is set to 4 (officially WinNT only):
4369 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4370 * Fast: Only the registry is queried to retrieve printer names,
4371 * no connection to the driver is made.
4372 * Returns an array of PRINTER_INFO_4 data structures in the
4373 * lpbPrinters buffer.
4375 * If level is set to 5 (officially WinNT4/Win9x only):
4376 * Fast: Only the registry is queried to retrieve printer names,
4377 * no connection to the driver is made.
4378 * Returns an array of PRINTER_INFO_5 data structures in the
4379 * lpbPrinters buffer.
4381 * If level set to 3 or 6+:
4382 * returns zero (failure!)
4384 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4385 * for information.
4387 * BUGS:
4388 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4389 * - Only levels 2, 4 and 5 are implemented at the moment.
4390 * - 16-bit printer drivers are not enumerated.
4391 * - Returned amount of bytes used/needed does not match the real Windoze
4392 * implementation (as in this implementation, all strings are part
4393 * of the buffer, whereas Win32 keeps them somewhere else)
4394 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4396 * NOTE:
4397 * - In a regular Wine installation, no registry settings for printers
4398 * exist, which makes this function return an empty list.
4400 BOOL WINAPI EnumPrintersW(
4401 DWORD dwType, /* [in] Types of print objects to enumerate */
4402 LPWSTR lpszName, /* [in] name of objects to enumerate */
4403 DWORD dwLevel, /* [in] type of printer info structure */
4404 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4405 DWORD cbBuf, /* [in] max size of buffer in bytes */
4406 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4407 LPDWORD lpdwReturned /* [out] number of entries returned */
4410 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4411 lpdwNeeded, lpdwReturned, TRUE);
4414 /******************************************************************
4415 * EnumPrintersA [WINSPOOL.@]
4417 * See EnumPrintersW
4420 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4421 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4423 BOOL ret;
4424 UNICODE_STRING pNameU;
4425 LPWSTR pNameW;
4426 LPBYTE pPrintersW;
4428 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4429 pPrinters, cbBuf, pcbNeeded, pcReturned);
4431 pNameW = asciitounicode(&pNameU, pName);
4433 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4434 MS Office need this */
4435 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4437 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4439 RtlFreeUnicodeString(&pNameU);
4440 if (ret) {
4441 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4443 HeapFree(GetProcessHeap(), 0, pPrintersW);
4444 return ret;
4447 /*****************************************************************************
4448 * WINSPOOL_GetDriverInfoFromReg [internal]
4450 * Enters the information from the registry into the DRIVER_INFO struct
4452 * RETURNS
4453 * zero if the printer driver does not exist in the registry
4454 * (only if Level > 1) otherwise nonzero
4456 static BOOL WINSPOOL_GetDriverInfoFromReg(
4457 HKEY hkeyDrivers,
4458 LPWSTR DriverName,
4459 const printenv_t * env,
4460 DWORD Level,
4461 LPBYTE ptr, /* DRIVER_INFO */
4462 LPBYTE pDriverStrings, /* strings buffer */
4463 DWORD cbBuf, /* size of string buffer */
4464 LPDWORD pcbNeeded, /* space needed for str. */
4465 BOOL unicode) /* type of strings */
4467 DWORD size, tmp;
4468 HKEY hkeyDriver;
4469 WCHAR driverdir[MAX_PATH];
4470 DWORD dirlen;
4471 LPBYTE strPtr = pDriverStrings;
4472 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4474 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4475 debugstr_w(DriverName), env,
4476 Level, di, pDriverStrings, cbBuf, unicode);
4478 if (di) ZeroMemory(di, di_sizeof[Level]);
4480 if (unicode) {
4481 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4482 if (*pcbNeeded <= cbBuf)
4483 strcpyW((LPWSTR)strPtr, DriverName);
4485 else
4487 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4488 if (*pcbNeeded <= cbBuf)
4489 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4492 /* pName for level 1 has a different offset! */
4493 if (Level == 1) {
4494 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4495 return TRUE;
4498 /* .cVersion and .pName for level > 1 */
4499 if (di) {
4500 di->cVersion = env->driverversion;
4501 di->pName = (LPWSTR) strPtr;
4502 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4505 /* Reserve Space for the largest subdir and a Backslash*/
4506 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4507 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4508 /* Should never Fail */
4509 return FALSE;
4511 lstrcatW(driverdir, env->versionsubdir);
4512 lstrcatW(driverdir, backslashW);
4514 /* dirlen must not include the terminating zero */
4515 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4516 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4518 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4519 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4520 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4521 return FALSE;
4524 /* pEnvironment */
4525 if (unicode)
4526 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4527 else
4528 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4530 *pcbNeeded += size;
4531 if (*pcbNeeded <= cbBuf) {
4532 if (unicode) {
4533 lstrcpyW((LPWSTR)strPtr, env->envname);
4535 else
4537 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4539 if (di) di->pEnvironment = (LPWSTR)strPtr;
4540 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4543 /* .pDriverPath is the Graphics rendering engine.
4544 The full Path is required to avoid a crash in some apps */
4545 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4546 *pcbNeeded += size;
4547 if (*pcbNeeded <= cbBuf)
4548 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4550 if (di) di->pDriverPath = (LPWSTR)strPtr;
4551 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4554 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4555 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4556 *pcbNeeded += size;
4557 if (*pcbNeeded <= cbBuf)
4558 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4560 if (di) di->pDataFile = (LPWSTR)strPtr;
4561 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4564 /* .pConfigFile is the Driver user Interface */
4565 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4566 *pcbNeeded += size;
4567 if (*pcbNeeded <= cbBuf)
4568 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4570 if (di) di->pConfigFile = (LPWSTR)strPtr;
4571 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4574 if (Level == 2 ) {
4575 RegCloseKey(hkeyDriver);
4576 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4577 return TRUE;
4580 if (Level == 5 ) {
4581 RegCloseKey(hkeyDriver);
4582 FIXME("level 5: incomplete\n");
4583 return TRUE;
4586 /* .pHelpFile */
4587 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4588 *pcbNeeded += size;
4589 if (*pcbNeeded <= cbBuf)
4590 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4592 if (di) di->pHelpFile = (LPWSTR)strPtr;
4593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4596 /* .pDependentFiles */
4597 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4598 *pcbNeeded += size;
4599 if (*pcbNeeded <= cbBuf)
4600 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4602 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4603 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4605 else if (GetVersion() & 0x80000000) {
4606 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4607 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4608 *pcbNeeded += size;
4609 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4611 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4615 /* .pMonitorName is the optional Language Monitor */
4616 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4617 *pcbNeeded += size;
4618 if (*pcbNeeded <= cbBuf)
4619 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4621 if (di) di->pMonitorName = (LPWSTR)strPtr;
4622 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4625 /* .pDefaultDataType */
4626 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4627 *pcbNeeded += size;
4628 if(*pcbNeeded <= cbBuf)
4629 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4631 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4632 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4635 if (Level == 3 ) {
4636 RegCloseKey(hkeyDriver);
4637 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4638 return TRUE;
4641 /* .pszzPreviousNames */
4642 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4643 *pcbNeeded += size;
4644 if(*pcbNeeded <= cbBuf)
4645 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4647 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4648 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4651 if (Level == 4 ) {
4652 RegCloseKey(hkeyDriver);
4653 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4654 return TRUE;
4657 /* support is missing, but not important enough for a FIXME */
4658 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4660 /* .pszMfgName */
4661 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4662 *pcbNeeded += size;
4663 if(*pcbNeeded <= cbBuf)
4664 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4666 if (di) di->pszMfgName = (LPWSTR)strPtr;
4667 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4670 /* .pszOEMUrl */
4671 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4672 *pcbNeeded += size;
4673 if(*pcbNeeded <= cbBuf)
4674 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4676 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4677 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4680 /* .pszHardwareID */
4681 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4682 *pcbNeeded += size;
4683 if(*pcbNeeded <= cbBuf)
4684 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4686 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4687 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4690 /* .pszProvider */
4691 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4692 *pcbNeeded += size;
4693 if(*pcbNeeded <= cbBuf)
4694 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4696 if (di) di->pszProvider = (LPWSTR)strPtr;
4697 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4700 if (Level == 6 ) {
4701 RegCloseKey(hkeyDriver);
4702 return TRUE;
4705 /* support is missing, but not important enough for a FIXME */
4706 TRACE("level 8: incomplete\n");
4708 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4709 RegCloseKey(hkeyDriver);
4710 return TRUE;
4713 /*****************************************************************************
4714 * WINSPOOL_GetPrinterDriver
4716 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4717 DWORD Level, LPBYTE pDriverInfo,
4718 DWORD cbBuf, LPDWORD pcbNeeded,
4719 BOOL unicode)
4721 LPCWSTR name;
4722 WCHAR DriverName[100];
4723 DWORD ret, type, size, needed = 0;
4724 LPBYTE ptr = NULL;
4725 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4726 const printenv_t * env;
4728 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4729 Level,pDriverInfo,cbBuf, pcbNeeded);
4732 if (!(name = get_opened_printer_name(hPrinter))) {
4733 SetLastError(ERROR_INVALID_HANDLE);
4734 return FALSE;
4737 if (Level < 1 || Level == 7 || Level > 8) {
4738 SetLastError(ERROR_INVALID_LEVEL);
4739 return FALSE;
4742 env = validate_envW(pEnvironment);
4743 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4745 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4746 ERROR_SUCCESS) {
4747 ERR("Can't create Printers key\n");
4748 return FALSE;
4750 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4751 != ERROR_SUCCESS) {
4752 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4753 RegCloseKey(hkeyPrinters);
4754 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4755 return FALSE;
4757 size = sizeof(DriverName);
4758 DriverName[0] = 0;
4759 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4760 (LPBYTE)DriverName, &size);
4761 RegCloseKey(hkeyPrinter);
4762 RegCloseKey(hkeyPrinters);
4763 if(ret != ERROR_SUCCESS) {
4764 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4765 return FALSE;
4768 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4769 if(!hkeyDrivers) {
4770 ERR("Can't create Drivers key\n");
4771 return FALSE;
4774 size = di_sizeof[Level];
4775 if ((size <= cbBuf) && pDriverInfo)
4776 ptr = pDriverInfo + size;
4778 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4779 env, Level, pDriverInfo, ptr,
4780 (cbBuf < size) ? 0 : cbBuf - size,
4781 &needed, unicode)) {
4782 RegCloseKey(hkeyDrivers);
4783 return FALSE;
4786 RegCloseKey(hkeyDrivers);
4788 if(pcbNeeded) *pcbNeeded = size + needed;
4789 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4790 if(cbBuf >= needed) return TRUE;
4791 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4792 return FALSE;
4795 /*****************************************************************************
4796 * GetPrinterDriverA [WINSPOOL.@]
4798 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4799 DWORD Level, LPBYTE pDriverInfo,
4800 DWORD cbBuf, LPDWORD pcbNeeded)
4802 BOOL ret;
4803 UNICODE_STRING pEnvW;
4804 PWSTR pwstrEnvW;
4806 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4807 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4808 cbBuf, pcbNeeded, FALSE);
4809 RtlFreeUnicodeString(&pEnvW);
4810 return ret;
4812 /*****************************************************************************
4813 * GetPrinterDriverW [WINSPOOL.@]
4815 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4816 DWORD Level, LPBYTE pDriverInfo,
4817 DWORD cbBuf, LPDWORD pcbNeeded)
4819 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4820 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4823 /*****************************************************************************
4824 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4826 * Return the PATH for the Printer-Drivers (UNICODE)
4828 * PARAMS
4829 * pName [I] Servername (NT only) or NULL (local Computer)
4830 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4831 * Level [I] Structure-Level (must be 1)
4832 * pDriverDirectory [O] PTR to Buffer that receives the Result
4833 * cbBuf [I] Size of Buffer at pDriverDirectory
4834 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4835 * required for pDriverDirectory
4837 * RETURNS
4838 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4839 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4840 * if cbBuf is too small
4842 * Native Values returned in pDriverDirectory on Success:
4843 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4844 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4845 *| win9x(Windows 4.0): "%winsysdir%"
4847 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4849 * FIXME
4850 *- Only NULL or "" is supported for pName
4853 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4854 DWORD Level, LPBYTE pDriverDirectory,
4855 DWORD cbBuf, LPDWORD pcbNeeded)
4857 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4858 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4860 if ((backend == NULL) && !load_backend()) return FALSE;
4862 if (Level != 1) {
4863 /* (Level != 1) is ignored in win9x */
4864 SetLastError(ERROR_INVALID_LEVEL);
4865 return FALSE;
4867 if (pcbNeeded == NULL) {
4868 /* (pcbNeeded == NULL) is ignored in win9x */
4869 SetLastError(RPC_X_NULL_REF_POINTER);
4870 return FALSE;
4873 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4874 pDriverDirectory, cbBuf, pcbNeeded);
4879 /*****************************************************************************
4880 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4882 * Return the PATH for the Printer-Drivers (ANSI)
4884 * See GetPrinterDriverDirectoryW.
4886 * NOTES
4887 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4890 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4891 DWORD Level, LPBYTE pDriverDirectory,
4892 DWORD cbBuf, LPDWORD pcbNeeded)
4894 UNICODE_STRING nameW, environmentW;
4895 BOOL ret;
4896 DWORD pcbNeededW;
4897 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4898 WCHAR *driverDirectoryW = NULL;
4900 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4901 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4903 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4905 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4906 else nameW.Buffer = NULL;
4907 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4908 else environmentW.Buffer = NULL;
4910 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4911 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4912 if (ret) {
4913 DWORD needed;
4914 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4915 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4916 if(pcbNeeded)
4917 *pcbNeeded = needed;
4918 ret = (needed <= cbBuf) ? TRUE : FALSE;
4919 } else
4920 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4922 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4924 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4925 RtlFreeUnicodeString(&environmentW);
4926 RtlFreeUnicodeString(&nameW);
4928 return ret;
4931 /*****************************************************************************
4932 * AddPrinterDriverA [WINSPOOL.@]
4934 * See AddPrinterDriverW.
4937 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4939 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4940 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4943 /******************************************************************************
4944 * AddPrinterDriverW (WINSPOOL.@)
4946 * Install a Printer Driver
4948 * PARAMS
4949 * pName [I] Servername or NULL (local Computer)
4950 * level [I] Level for the supplied DRIVER_INFO_*W struct
4951 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4953 * RESULTS
4954 * Success: TRUE
4955 * Failure: FALSE
4958 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4960 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4961 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4964 /*****************************************************************************
4965 * AddPrintProcessorA [WINSPOOL.@]
4967 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4968 LPSTR pPrintProcessorName)
4970 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4971 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4972 return FALSE;
4975 /*****************************************************************************
4976 * AddPrintProcessorW [WINSPOOL.@]
4978 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4979 LPWSTR pPrintProcessorName)
4981 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4982 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4983 return FALSE;
4986 /*****************************************************************************
4987 * AddPrintProvidorA [WINSPOOL.@]
4989 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4991 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4992 return FALSE;
4995 /*****************************************************************************
4996 * AddPrintProvidorW [WINSPOOL.@]
4998 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5000 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5001 return FALSE;
5004 /*****************************************************************************
5005 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5007 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5008 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5010 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5011 pDevModeOutput, pDevModeInput);
5012 return 0;
5015 /*****************************************************************************
5016 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5018 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5019 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5021 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5022 pDevModeOutput, pDevModeInput);
5023 return 0;
5026 /*****************************************************************************
5027 * PrinterProperties [WINSPOOL.@]
5029 * Displays a dialog to set the properties of the printer.
5031 * RETURNS
5032 * nonzero on success or zero on failure
5034 * BUGS
5035 * implemented as stub only
5037 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5038 HANDLE hPrinter /* [in] handle to printer object */
5040 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5041 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5042 return FALSE;
5045 /*****************************************************************************
5046 * EnumJobsA [WINSPOOL.@]
5049 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5050 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5051 LPDWORD pcReturned)
5053 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5054 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5056 if(pcbNeeded) *pcbNeeded = 0;
5057 if(pcReturned) *pcReturned = 0;
5058 return FALSE;
5062 /*****************************************************************************
5063 * EnumJobsW [WINSPOOL.@]
5066 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5067 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5068 LPDWORD pcReturned)
5070 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5071 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5073 if(pcbNeeded) *pcbNeeded = 0;
5074 if(pcReturned) *pcReturned = 0;
5075 return FALSE;
5078 /*****************************************************************************
5079 * WINSPOOL_EnumPrinterDrivers [internal]
5081 * Delivers information about all printer drivers installed on the
5082 * localhost or a given server
5084 * RETURNS
5085 * nonzero on success or zero on failure. If the buffer for the returned
5086 * information is too small the function will return an error
5088 * BUGS
5089 * - only implemented for localhost, foreign hosts will return an error
5091 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5092 DWORD Level, LPBYTE pDriverInfo,
5093 DWORD cbBuf, LPDWORD pcbNeeded,
5094 LPDWORD pcReturned, BOOL unicode)
5096 { HKEY hkeyDrivers;
5097 DWORD i, needed, number = 0, size = 0;
5098 WCHAR DriverNameW[255];
5099 PBYTE ptr;
5100 const printenv_t * env;
5102 TRACE("%s,%s,%d,%p,%d,%d\n",
5103 debugstr_w(pName), debugstr_w(pEnvironment),
5104 Level, pDriverInfo, cbBuf, unicode);
5106 /* check for local drivers */
5107 if((pName) && (pName[0])) {
5108 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5109 SetLastError(ERROR_ACCESS_DENIED);
5110 return FALSE;
5113 env = validate_envW(pEnvironment);
5114 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5116 /* check input parameter */
5117 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5118 SetLastError(ERROR_INVALID_LEVEL);
5119 return FALSE;
5122 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5123 SetLastError(RPC_X_NULL_REF_POINTER);
5124 return FALSE;
5127 /* initialize return values */
5128 if(pDriverInfo)
5129 memset( pDriverInfo, 0, cbBuf);
5130 *pcbNeeded = 0;
5131 *pcReturned = 0;
5133 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5134 if(!hkeyDrivers) {
5135 ERR("Can't open Drivers key\n");
5136 return FALSE;
5139 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5140 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5141 RegCloseKey(hkeyDrivers);
5142 ERR("Can't query Drivers key\n");
5143 return FALSE;
5145 TRACE("Found %d Drivers\n", number);
5147 /* get size of single struct
5148 * unicode and ascii structure have the same size
5150 size = di_sizeof[Level];
5152 /* calculate required buffer size */
5153 *pcbNeeded = size * number;
5155 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5156 i < number;
5157 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5158 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5159 != ERROR_SUCCESS) {
5160 ERR("Can't enum key number %d\n", i);
5161 RegCloseKey(hkeyDrivers);
5162 return FALSE;
5164 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5165 env, Level, ptr,
5166 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5167 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5168 &needed, unicode)) {
5169 RegCloseKey(hkeyDrivers);
5170 return FALSE;
5172 (*pcbNeeded) += needed;
5175 RegCloseKey(hkeyDrivers);
5177 if(cbBuf < *pcbNeeded){
5178 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5179 return FALSE;
5182 *pcReturned = number;
5183 return TRUE;
5186 /*****************************************************************************
5187 * EnumPrinterDriversW [WINSPOOL.@]
5189 * see function EnumPrinterDrivers for RETURNS, BUGS
5191 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5192 LPBYTE pDriverInfo, DWORD cbBuf,
5193 LPDWORD pcbNeeded, LPDWORD pcReturned)
5195 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5196 cbBuf, pcbNeeded, pcReturned, TRUE);
5199 /*****************************************************************************
5200 * EnumPrinterDriversA [WINSPOOL.@]
5202 * see function EnumPrinterDrivers for RETURNS, BUGS
5204 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5205 LPBYTE pDriverInfo, DWORD cbBuf,
5206 LPDWORD pcbNeeded, LPDWORD pcReturned)
5207 { BOOL ret;
5208 UNICODE_STRING pNameW, pEnvironmentW;
5209 PWSTR pwstrNameW, pwstrEnvironmentW;
5211 pwstrNameW = asciitounicode(&pNameW, pName);
5212 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5214 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5215 Level, pDriverInfo, cbBuf, pcbNeeded,
5216 pcReturned, FALSE);
5217 RtlFreeUnicodeString(&pNameW);
5218 RtlFreeUnicodeString(&pEnvironmentW);
5220 return ret;
5223 /******************************************************************************
5224 * EnumPortsA (WINSPOOL.@)
5226 * See EnumPortsW.
5229 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5230 LPDWORD pcbNeeded, LPDWORD pcReturned)
5232 BOOL res;
5233 LPBYTE bufferW = NULL;
5234 LPWSTR nameW = NULL;
5235 DWORD needed = 0;
5236 DWORD numentries = 0;
5237 INT len;
5239 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5240 cbBuf, pcbNeeded, pcReturned);
5242 /* convert servername to unicode */
5243 if (pName) {
5244 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5245 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5246 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5248 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5249 needed = cbBuf * sizeof(WCHAR);
5250 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5251 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5253 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5254 if (pcbNeeded) needed = *pcbNeeded;
5255 /* HeapReAlloc return NULL, when bufferW was NULL */
5256 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5257 HeapAlloc(GetProcessHeap(), 0, needed);
5259 /* Try again with the large Buffer */
5260 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5262 needed = pcbNeeded ? *pcbNeeded : 0;
5263 numentries = pcReturned ? *pcReturned : 0;
5266 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5267 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5269 if (res) {
5270 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5271 DWORD entrysize = 0;
5272 DWORD index;
5273 LPSTR ptr;
5274 LPPORT_INFO_2W pi2w;
5275 LPPORT_INFO_2A pi2a;
5277 needed = 0;
5278 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5280 /* First pass: calculate the size for all Entries */
5281 pi2w = (LPPORT_INFO_2W) bufferW;
5282 pi2a = (LPPORT_INFO_2A) pPorts;
5283 index = 0;
5284 while (index < numentries) {
5285 index++;
5286 needed += entrysize; /* PORT_INFO_?A */
5287 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5289 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5290 NULL, 0, NULL, NULL);
5291 if (Level > 1) {
5292 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5293 NULL, 0, NULL, NULL);
5294 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5295 NULL, 0, NULL, NULL);
5297 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5298 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5299 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5302 /* check for errors and quit on failure */
5303 if (cbBuf < needed) {
5304 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5305 res = FALSE;
5306 goto cleanup;
5308 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5309 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5310 cbBuf -= len ; /* free Bytes in the user-Buffer */
5311 pi2w = (LPPORT_INFO_2W) bufferW;
5312 pi2a = (LPPORT_INFO_2A) pPorts;
5313 index = 0;
5314 /* Second Pass: Fill the User Buffer (if we have one) */
5315 while ((index < numentries) && pPorts) {
5316 index++;
5317 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5318 pi2a->pPortName = ptr;
5319 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5320 ptr, cbBuf , NULL, NULL);
5321 ptr += len;
5322 cbBuf -= len;
5323 if (Level > 1) {
5324 pi2a->pMonitorName = ptr;
5325 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5326 ptr, cbBuf, NULL, NULL);
5327 ptr += len;
5328 cbBuf -= len;
5330 pi2a->pDescription = ptr;
5331 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5332 ptr, cbBuf, NULL, NULL);
5333 ptr += len;
5334 cbBuf -= len;
5336 pi2a->fPortType = pi2w->fPortType;
5337 pi2a->Reserved = 0; /* documented: "must be zero" */
5340 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5341 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5342 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5346 cleanup:
5347 if (pcbNeeded) *pcbNeeded = needed;
5348 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5350 HeapFree(GetProcessHeap(), 0, nameW);
5351 HeapFree(GetProcessHeap(), 0, bufferW);
5353 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5354 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5356 return (res);
5360 /******************************************************************************
5361 * EnumPortsW (WINSPOOL.@)
5363 * Enumerate available Ports
5365 * PARAMS
5366 * pName [I] Servername or NULL (local Computer)
5367 * Level [I] Structure-Level (1 or 2)
5368 * pPorts [O] PTR to Buffer that receives the Result
5369 * cbBuf [I] Size of Buffer at pPorts
5370 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5371 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5373 * RETURNS
5374 * Success: TRUE
5375 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5378 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5381 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5382 cbBuf, pcbNeeded, pcReturned);
5384 if ((backend == NULL) && !load_backend()) return FALSE;
5386 /* Level is not checked in win9x */
5387 if (!Level || (Level > 2)) {
5388 WARN("level (%d) is ignored in win9x\n", Level);
5389 SetLastError(ERROR_INVALID_LEVEL);
5390 return FALSE;
5392 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5393 SetLastError(RPC_X_NULL_REF_POINTER);
5394 return FALSE;
5397 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5400 /******************************************************************************
5401 * GetDefaultPrinterW (WINSPOOL.@)
5403 * FIXME
5404 * This function must read the value from data 'device' of key
5405 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5407 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5409 BOOL retval = TRUE;
5410 DWORD insize, len;
5411 WCHAR *buffer, *ptr;
5413 if (!namesize)
5415 SetLastError(ERROR_INVALID_PARAMETER);
5416 return FALSE;
5419 /* make the buffer big enough for the stuff from the profile/registry,
5420 * the content must fit into the local buffer to compute the correct
5421 * size even if the extern buffer is too small or not given.
5422 * (20 for ,driver,port) */
5423 insize = *namesize;
5424 len = max(100, (insize + 20));
5425 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5427 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5429 SetLastError (ERROR_FILE_NOT_FOUND);
5430 retval = FALSE;
5431 goto end;
5433 TRACE("%s\n", debugstr_w(buffer));
5435 if ((ptr = strchrW(buffer, ',')) == NULL)
5437 SetLastError(ERROR_INVALID_NAME);
5438 retval = FALSE;
5439 goto end;
5442 *ptr = 0;
5443 *namesize = strlenW(buffer) + 1;
5444 if(!name || (*namesize > insize))
5446 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5447 retval = FALSE;
5448 goto end;
5450 strcpyW(name, buffer);
5452 end:
5453 HeapFree( GetProcessHeap(), 0, buffer);
5454 return retval;
5458 /******************************************************************************
5459 * GetDefaultPrinterA (WINSPOOL.@)
5461 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5463 BOOL retval = TRUE;
5464 DWORD insize = 0;
5465 WCHAR *bufferW = NULL;
5467 if (!namesize)
5469 SetLastError(ERROR_INVALID_PARAMETER);
5470 return FALSE;
5473 if(name && *namesize) {
5474 insize = *namesize;
5475 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5478 if(!GetDefaultPrinterW( bufferW, namesize)) {
5479 retval = FALSE;
5480 goto end;
5483 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5484 NULL, NULL);
5485 if (!*namesize)
5487 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5488 retval = FALSE;
5490 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5492 end:
5493 HeapFree( GetProcessHeap(), 0, bufferW);
5494 return retval;
5498 /******************************************************************************
5499 * SetDefaultPrinterW (WINSPOOL.204)
5501 * Set the Name of the Default Printer
5503 * PARAMS
5504 * pszPrinter [I] Name of the Printer or NULL
5506 * RETURNS
5507 * Success: True
5508 * Failure: FALSE
5510 * NOTES
5511 * When the Parameter is NULL or points to an Empty String and
5512 * a Default Printer was already present, then this Function changes nothing.
5513 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5514 * the First enumerated local Printer is used.
5517 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5520 TRACE("(%s)\n", debugstr_w(pszPrinter));
5522 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5523 return FALSE;
5526 /******************************************************************************
5527 * SetDefaultPrinterA (WINSPOOL.202)
5529 * See SetDefaultPrinterW.
5532 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5535 TRACE("(%s)\n", debugstr_a(pszPrinter));
5537 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5538 return FALSE;
5542 /******************************************************************************
5543 * SetPrinterDataExA (WINSPOOL.@)
5545 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5546 LPCSTR pValueName, DWORD Type,
5547 LPBYTE pData, DWORD cbData)
5549 HKEY hkeyPrinter, hkeySubkey;
5550 DWORD ret;
5552 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5553 debugstr_a(pValueName), Type, pData, cbData);
5555 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5556 != ERROR_SUCCESS)
5557 return ret;
5559 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5560 != ERROR_SUCCESS) {
5561 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5562 RegCloseKey(hkeyPrinter);
5563 return ret;
5565 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5566 RegCloseKey(hkeySubkey);
5567 RegCloseKey(hkeyPrinter);
5568 return ret;
5571 /******************************************************************************
5572 * SetPrinterDataExW (WINSPOOL.@)
5574 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5575 LPCWSTR pValueName, DWORD Type,
5576 LPBYTE pData, DWORD cbData)
5578 HKEY hkeyPrinter, hkeySubkey;
5579 DWORD ret;
5581 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5582 debugstr_w(pValueName), Type, pData, cbData);
5584 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5585 != ERROR_SUCCESS)
5586 return ret;
5588 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5589 != ERROR_SUCCESS) {
5590 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5591 RegCloseKey(hkeyPrinter);
5592 return ret;
5594 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5595 RegCloseKey(hkeySubkey);
5596 RegCloseKey(hkeyPrinter);
5597 return ret;
5600 /******************************************************************************
5601 * SetPrinterDataA (WINSPOOL.@)
5603 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5604 LPBYTE pData, DWORD cbData)
5606 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5607 pData, cbData);
5610 /******************************************************************************
5611 * SetPrinterDataW (WINSPOOL.@)
5613 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5614 LPBYTE pData, DWORD cbData)
5616 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5617 pData, cbData);
5620 /******************************************************************************
5621 * GetPrinterDataExA (WINSPOOL.@)
5623 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5624 LPCSTR pValueName, LPDWORD pType,
5625 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5627 HKEY hkeyPrinter, hkeySubkey;
5628 DWORD ret;
5630 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5631 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5632 pcbNeeded);
5634 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5635 != ERROR_SUCCESS)
5636 return ret;
5638 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5639 != ERROR_SUCCESS) {
5640 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5641 RegCloseKey(hkeyPrinter);
5642 return ret;
5644 *pcbNeeded = nSize;
5645 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5646 RegCloseKey(hkeySubkey);
5647 RegCloseKey(hkeyPrinter);
5648 return ret;
5651 /******************************************************************************
5652 * GetPrinterDataExW (WINSPOOL.@)
5654 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5655 LPCWSTR pValueName, LPDWORD pType,
5656 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5658 HKEY hkeyPrinter, hkeySubkey;
5659 DWORD ret;
5661 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5662 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5663 pcbNeeded);
5665 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5666 != ERROR_SUCCESS)
5667 return ret;
5669 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5670 != ERROR_SUCCESS) {
5671 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5672 RegCloseKey(hkeyPrinter);
5673 return ret;
5675 *pcbNeeded = nSize;
5676 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5677 RegCloseKey(hkeySubkey);
5678 RegCloseKey(hkeyPrinter);
5679 return ret;
5682 /******************************************************************************
5683 * GetPrinterDataA (WINSPOOL.@)
5685 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5686 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5688 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5689 pData, nSize, pcbNeeded);
5692 /******************************************************************************
5693 * GetPrinterDataW (WINSPOOL.@)
5695 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5696 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5698 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5699 pData, nSize, pcbNeeded);
5702 /*******************************************************************************
5703 * EnumPrinterDataExW [WINSPOOL.@]
5705 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5706 LPBYTE pEnumValues, DWORD cbEnumValues,
5707 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5709 HKEY hkPrinter, hkSubKey;
5710 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5711 cbValueNameLen, cbMaxValueLen, cbValueLen,
5712 cbBufSize, dwType;
5713 LPWSTR lpValueName;
5714 HANDLE hHeap;
5715 PBYTE lpValue;
5716 PPRINTER_ENUM_VALUESW ppev;
5718 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5720 if (pKeyName == NULL || *pKeyName == 0)
5721 return ERROR_INVALID_PARAMETER;
5723 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5724 if (ret != ERROR_SUCCESS)
5726 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5727 hPrinter, ret);
5728 return ret;
5731 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5732 if (ret != ERROR_SUCCESS)
5734 r = RegCloseKey (hkPrinter);
5735 if (r != ERROR_SUCCESS)
5736 WARN ("RegCloseKey returned %i\n", r);
5737 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5738 debugstr_w (pKeyName), ret);
5739 return ret;
5742 ret = RegCloseKey (hkPrinter);
5743 if (ret != ERROR_SUCCESS)
5745 ERR ("RegCloseKey returned %i\n", ret);
5746 r = RegCloseKey (hkSubKey);
5747 if (r != ERROR_SUCCESS)
5748 WARN ("RegCloseKey returned %i\n", r);
5749 return ret;
5752 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5753 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5754 if (ret != ERROR_SUCCESS)
5756 r = RegCloseKey (hkSubKey);
5757 if (r != ERROR_SUCCESS)
5758 WARN ("RegCloseKey returned %i\n", r);
5759 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5760 return ret;
5763 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5764 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5766 if (cValues == 0) /* empty key */
5768 r = RegCloseKey (hkSubKey);
5769 if (r != ERROR_SUCCESS)
5770 WARN ("RegCloseKey returned %i\n", r);
5771 *pcbEnumValues = *pnEnumValues = 0;
5772 return ERROR_SUCCESS;
5775 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5777 hHeap = GetProcessHeap ();
5778 if (hHeap == NULL)
5780 ERR ("GetProcessHeap failed\n");
5781 r = RegCloseKey (hkSubKey);
5782 if (r != ERROR_SUCCESS)
5783 WARN ("RegCloseKey returned %i\n", r);
5784 return ERROR_OUTOFMEMORY;
5787 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5788 if (lpValueName == NULL)
5790 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5791 r = RegCloseKey (hkSubKey);
5792 if (r != ERROR_SUCCESS)
5793 WARN ("RegCloseKey returned %i\n", r);
5794 return ERROR_OUTOFMEMORY;
5797 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5798 if (lpValue == NULL)
5800 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5801 if (HeapFree (hHeap, 0, lpValueName) == 0)
5802 WARN ("HeapFree failed with code %i\n", GetLastError ());
5803 r = RegCloseKey (hkSubKey);
5804 if (r != ERROR_SUCCESS)
5805 WARN ("RegCloseKey returned %i\n", r);
5806 return ERROR_OUTOFMEMORY;
5809 TRACE ("pass 1: calculating buffer required for all names and values\n");
5811 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5813 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5815 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5817 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5818 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5819 NULL, NULL, lpValue, &cbValueLen);
5820 if (ret != ERROR_SUCCESS)
5822 if (HeapFree (hHeap, 0, lpValue) == 0)
5823 WARN ("HeapFree failed with code %i\n", GetLastError ());
5824 if (HeapFree (hHeap, 0, lpValueName) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5826 r = RegCloseKey (hkSubKey);
5827 if (r != ERROR_SUCCESS)
5828 WARN ("RegCloseKey returned %i\n", r);
5829 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5830 return ret;
5833 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5834 debugstr_w (lpValueName), dwIndex,
5835 cbValueNameLen + 1, cbValueLen);
5837 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5838 cbBufSize += cbValueLen;
5841 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5843 *pcbEnumValues = cbBufSize;
5844 *pnEnumValues = cValues;
5846 if (cbEnumValues < cbBufSize) /* buffer too small */
5848 if (HeapFree (hHeap, 0, lpValue) == 0)
5849 WARN ("HeapFree failed with code %i\n", GetLastError ());
5850 if (HeapFree (hHeap, 0, lpValueName) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5852 r = RegCloseKey (hkSubKey);
5853 if (r != ERROR_SUCCESS)
5854 WARN ("RegCloseKey returned %i\n", r);
5855 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5856 return ERROR_MORE_DATA;
5859 TRACE ("pass 2: copying all names and values to buffer\n");
5861 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5862 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5864 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5866 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5867 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5868 NULL, &dwType, lpValue, &cbValueLen);
5869 if (ret != ERROR_SUCCESS)
5871 if (HeapFree (hHeap, 0, lpValue) == 0)
5872 WARN ("HeapFree failed with code %i\n", GetLastError ());
5873 if (HeapFree (hHeap, 0, lpValueName) == 0)
5874 WARN ("HeapFree failed with code %i\n", GetLastError ());
5875 r = RegCloseKey (hkSubKey);
5876 if (r != ERROR_SUCCESS)
5877 WARN ("RegCloseKey returned %i\n", r);
5878 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5879 return ret;
5882 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5883 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5884 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5885 pEnumValues += cbValueNameLen;
5887 /* return # of *bytes* (including trailing \0), not # of chars */
5888 ppev[dwIndex].cbValueName = cbValueNameLen;
5890 ppev[dwIndex].dwType = dwType;
5892 memcpy (pEnumValues, lpValue, cbValueLen);
5893 ppev[dwIndex].pData = pEnumValues;
5894 pEnumValues += cbValueLen;
5896 ppev[dwIndex].cbData = cbValueLen;
5898 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5899 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5902 if (HeapFree (hHeap, 0, lpValue) == 0)
5904 ret = GetLastError ();
5905 ERR ("HeapFree failed with code %i\n", ret);
5906 if (HeapFree (hHeap, 0, lpValueName) == 0)
5907 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 r = RegCloseKey (hkSubKey);
5909 if (r != ERROR_SUCCESS)
5910 WARN ("RegCloseKey returned %i\n", r);
5911 return ret;
5914 if (HeapFree (hHeap, 0, lpValueName) == 0)
5916 ret = GetLastError ();
5917 ERR ("HeapFree failed with code %i\n", ret);
5918 r = RegCloseKey (hkSubKey);
5919 if (r != ERROR_SUCCESS)
5920 WARN ("RegCloseKey returned %i\n", r);
5921 return ret;
5924 ret = RegCloseKey (hkSubKey);
5925 if (ret != ERROR_SUCCESS)
5927 ERR ("RegCloseKey returned %i\n", ret);
5928 return ret;
5931 return ERROR_SUCCESS;
5934 /*******************************************************************************
5935 * EnumPrinterDataExA [WINSPOOL.@]
5937 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5938 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5939 * what Windows 2000 SP1 does.
5942 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5943 LPBYTE pEnumValues, DWORD cbEnumValues,
5944 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5946 INT len;
5947 LPWSTR pKeyNameW;
5948 DWORD ret, dwIndex, dwBufSize;
5949 HANDLE hHeap;
5950 LPSTR pBuffer;
5952 TRACE ("%p %s\n", hPrinter, pKeyName);
5954 if (pKeyName == NULL || *pKeyName == 0)
5955 return ERROR_INVALID_PARAMETER;
5957 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5958 if (len == 0)
5960 ret = GetLastError ();
5961 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5962 return ret;
5965 hHeap = GetProcessHeap ();
5966 if (hHeap == NULL)
5968 ERR ("GetProcessHeap failed\n");
5969 return ERROR_OUTOFMEMORY;
5972 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5973 if (pKeyNameW == NULL)
5975 ERR ("Failed to allocate %i bytes from process heap\n",
5976 (LONG)(len * sizeof (WCHAR)));
5977 return ERROR_OUTOFMEMORY;
5980 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5982 ret = GetLastError ();
5983 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5984 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5985 WARN ("HeapFree failed with code %i\n", GetLastError ());
5986 return ret;
5989 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5990 pcbEnumValues, pnEnumValues);
5991 if (ret != ERROR_SUCCESS)
5993 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5994 WARN ("HeapFree failed with code %i\n", GetLastError ());
5995 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5996 return ret;
5999 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6001 ret = GetLastError ();
6002 ERR ("HeapFree failed with code %i\n", ret);
6003 return ret;
6006 if (*pnEnumValues == 0) /* empty key */
6007 return ERROR_SUCCESS;
6009 dwBufSize = 0;
6010 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6012 PPRINTER_ENUM_VALUESW ppev =
6013 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6015 if (dwBufSize < ppev->cbValueName)
6016 dwBufSize = ppev->cbValueName;
6018 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6019 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6020 dwBufSize = ppev->cbData;
6023 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6025 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6026 if (pBuffer == NULL)
6028 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6029 return ERROR_OUTOFMEMORY;
6032 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6034 PPRINTER_ENUM_VALUESW ppev =
6035 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6037 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6038 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6039 NULL);
6040 if (len == 0)
6042 ret = GetLastError ();
6043 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6044 if (HeapFree (hHeap, 0, pBuffer) == 0)
6045 WARN ("HeapFree failed with code %i\n", GetLastError ());
6046 return ret;
6049 memcpy (ppev->pValueName, pBuffer, len);
6051 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6053 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6054 ppev->dwType != REG_MULTI_SZ)
6055 continue;
6057 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6058 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6059 if (len == 0)
6061 ret = GetLastError ();
6062 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6063 if (HeapFree (hHeap, 0, pBuffer) == 0)
6064 WARN ("HeapFree failed with code %i\n", GetLastError ());
6065 return ret;
6068 memcpy (ppev->pData, pBuffer, len);
6070 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6071 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6074 if (HeapFree (hHeap, 0, pBuffer) == 0)
6076 ret = GetLastError ();
6077 ERR ("HeapFree failed with code %i\n", ret);
6078 return ret;
6081 return ERROR_SUCCESS;
6084 /******************************************************************************
6085 * AbortPrinter (WINSPOOL.@)
6087 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6089 FIXME("(%p), stub!\n", hPrinter);
6090 return TRUE;
6093 /******************************************************************************
6094 * AddPortA (WINSPOOL.@)
6096 * See AddPortW.
6099 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6101 LPWSTR nameW = NULL;
6102 LPWSTR monitorW = NULL;
6103 DWORD len;
6104 BOOL res;
6106 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6108 if (pName) {
6109 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6110 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6111 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6114 if (pMonitorName) {
6115 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6116 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6117 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6119 res = AddPortW(nameW, hWnd, monitorW);
6120 HeapFree(GetProcessHeap(), 0, nameW);
6121 HeapFree(GetProcessHeap(), 0, monitorW);
6122 return res;
6125 /******************************************************************************
6126 * AddPortW (WINSPOOL.@)
6128 * Add a Port for a specific Monitor
6130 * PARAMS
6131 * pName [I] Servername or NULL (local Computer)
6132 * hWnd [I] Handle to parent Window for the Dialog-Box
6133 * pMonitorName [I] Name of the Monitor that manage the Port
6135 * RETURNS
6136 * Success: TRUE
6137 * Failure: FALSE
6140 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6142 monitor_t * pm;
6143 monitor_t * pui;
6144 DWORD res;
6146 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6148 if (pName && pName[0]) {
6149 SetLastError(ERROR_INVALID_PARAMETER);
6150 return FALSE;
6153 if (!pMonitorName) {
6154 SetLastError(RPC_X_NULL_REF_POINTER);
6155 return FALSE;
6158 /* an empty Monitorname is Invalid */
6159 if (!pMonitorName[0]) {
6160 SetLastError(ERROR_NOT_SUPPORTED);
6161 return FALSE;
6164 pm = monitor_load(pMonitorName, NULL);
6165 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6166 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6167 TRACE("got %d with %u\n", res, GetLastError());
6168 res = TRUE;
6170 else
6172 pui = monitor_loadui(pm);
6173 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6174 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6175 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6176 TRACE("got %d with %u\n", res, GetLastError());
6177 res = TRUE;
6179 else
6181 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6182 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6184 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6185 SetLastError(ERROR_NOT_SUPPORTED);
6186 res = FALSE;
6188 monitor_unload(pui);
6190 monitor_unload(pm);
6191 TRACE("returning %d with %u\n", res, GetLastError());
6192 return res;
6195 /******************************************************************************
6196 * AddPortExA (WINSPOOL.@)
6198 * See AddPortExW.
6201 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6203 PORT_INFO_2W pi2W;
6204 PORT_INFO_2A * pi2A;
6205 LPWSTR nameW = NULL;
6206 LPWSTR monitorW = NULL;
6207 DWORD len;
6208 BOOL res;
6210 pi2A = (PORT_INFO_2A *) pBuffer;
6212 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6213 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6215 if ((level < 1) || (level > 2)) {
6216 SetLastError(ERROR_INVALID_LEVEL);
6217 return FALSE;
6220 if (!pi2A) {
6221 SetLastError(ERROR_INVALID_PARAMETER);
6222 return FALSE;
6225 if (pName) {
6226 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6227 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6228 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6231 if (pMonitorName) {
6232 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6233 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6234 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6237 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6239 if (pi2A->pPortName) {
6240 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6241 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6242 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6245 if (level > 1) {
6246 if (pi2A->pMonitorName) {
6247 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6248 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6249 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6252 if (pi2A->pDescription) {
6253 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6254 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6255 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6257 pi2W.fPortType = pi2A->fPortType;
6258 pi2W.Reserved = pi2A->Reserved;
6261 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6263 HeapFree(GetProcessHeap(), 0, nameW);
6264 HeapFree(GetProcessHeap(), 0, monitorW);
6265 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6266 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6267 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6268 return res;
6272 /******************************************************************************
6273 * AddPortExW (WINSPOOL.@)
6275 * Add a Port for a specific Monitor, without presenting a user interface
6277 * PARAMS
6278 * pName [I] Servername or NULL (local Computer)
6279 * level [I] Structure-Level (1 or 2) for pBuffer
6280 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6281 * pMonitorName [I] Name of the Monitor that manage the Port
6283 * RETURNS
6284 * Success: TRUE
6285 * Failure: FALSE
6288 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6290 PORT_INFO_2W * pi2;
6291 monitor_t * pm;
6292 DWORD res = FALSE;
6294 pi2 = (PORT_INFO_2W *) pBuffer;
6296 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6297 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6298 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6299 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6302 if ((level < 1) || (level > 2)) {
6303 SetLastError(ERROR_INVALID_LEVEL);
6304 return FALSE;
6307 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6308 SetLastError(ERROR_INVALID_PARAMETER);
6309 return FALSE;
6312 /* load the Monitor */
6313 pm = monitor_load(pMonitorName, NULL);
6314 if (!pm) {
6315 SetLastError(ERROR_INVALID_PARAMETER);
6316 return FALSE;
6319 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6320 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6321 TRACE("got %u with %u\n", res, GetLastError());
6323 else
6325 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6327 monitor_unload(pm);
6328 return res;
6331 /******************************************************************************
6332 * AddPrinterConnectionA (WINSPOOL.@)
6334 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6336 FIXME("%s\n", debugstr_a(pName));
6337 return FALSE;
6340 /******************************************************************************
6341 * AddPrinterConnectionW (WINSPOOL.@)
6343 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6345 FIXME("%s\n", debugstr_w(pName));
6346 return FALSE;
6349 /******************************************************************************
6350 * AddPrinterDriverExW (WINSPOOL.@)
6352 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6354 * PARAMS
6355 * pName [I] Servername or NULL (local Computer)
6356 * level [I] Level for the supplied DRIVER_INFO_*W struct
6357 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6358 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6360 * RESULTS
6361 * Success: TRUE
6362 * Failure: FALSE
6365 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6367 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6369 if ((backend == NULL) && !load_backend()) return FALSE;
6371 if (level < 2 || level == 5 || level == 7 || level > 8) {
6372 SetLastError(ERROR_INVALID_LEVEL);
6373 return FALSE;
6376 if (!pDriverInfo) {
6377 SetLastError(ERROR_INVALID_PARAMETER);
6378 return FALSE;
6381 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6384 /******************************************************************************
6385 * AddPrinterDriverExA (WINSPOOL.@)
6387 * See AddPrinterDriverExW.
6390 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6392 DRIVER_INFO_8A *diA;
6393 DRIVER_INFO_8W diW;
6394 LPWSTR nameW = NULL;
6395 DWORD lenA;
6396 DWORD len;
6397 DWORD res = FALSE;
6399 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6401 diA = (DRIVER_INFO_8A *) pDriverInfo;
6402 ZeroMemory(&diW, sizeof(diW));
6404 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6405 SetLastError(ERROR_INVALID_LEVEL);
6406 return FALSE;
6409 if (diA == NULL) {
6410 SetLastError(ERROR_INVALID_PARAMETER);
6411 return FALSE;
6414 /* convert servername to unicode */
6415 if (pName) {
6416 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6417 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6418 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6421 /* common fields */
6422 diW.cVersion = diA->cVersion;
6424 if (diA->pName) {
6425 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6426 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6427 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6430 if (diA->pEnvironment) {
6431 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6432 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6433 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6436 if (diA->pDriverPath) {
6437 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6438 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6439 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6442 if (diA->pDataFile) {
6443 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6444 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6445 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6448 if (diA->pConfigFile) {
6449 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6450 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6451 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6454 if ((Level > 2) && diA->pDependentFiles) {
6455 lenA = multi_sz_lenA(diA->pDependentFiles);
6456 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6457 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6458 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6461 if ((Level > 2) && diA->pMonitorName) {
6462 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6463 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6464 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6467 if ((Level > 3) && diA->pDefaultDataType) {
6468 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6469 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6470 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6473 if ((Level > 3) && diA->pszzPreviousNames) {
6474 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6475 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6476 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6477 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6480 if ((Level > 5) && diA->pszMfgName) {
6481 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6482 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6483 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6486 if ((Level > 5) && diA->pszOEMUrl) {
6487 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6488 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6489 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6492 if ((Level > 5) && diA->pszHardwareID) {
6493 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6494 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6495 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6498 if ((Level > 5) && diA->pszProvider) {
6499 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6500 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6501 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6504 if (Level > 7) {
6505 FIXME("level %u is incomplete\n", Level);
6508 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6509 TRACE("got %u with %u\n", res, GetLastError());
6510 HeapFree(GetProcessHeap(), 0, nameW);
6511 HeapFree(GetProcessHeap(), 0, diW.pName);
6512 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6513 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6514 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6515 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6516 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6517 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6518 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6519 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6520 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6521 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6522 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6523 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6525 TRACE("=> %u with %u\n", res, GetLastError());
6526 return res;
6529 /******************************************************************************
6530 * ConfigurePortA (WINSPOOL.@)
6532 * See ConfigurePortW.
6535 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6537 LPWSTR nameW = NULL;
6538 LPWSTR portW = NULL;
6539 INT len;
6540 DWORD res;
6542 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6544 /* convert servername to unicode */
6545 if (pName) {
6546 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6547 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6548 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6551 /* convert portname to unicode */
6552 if (pPortName) {
6553 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6554 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6555 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6558 res = ConfigurePortW(nameW, hWnd, portW);
6559 HeapFree(GetProcessHeap(), 0, nameW);
6560 HeapFree(GetProcessHeap(), 0, portW);
6561 return res;
6564 /******************************************************************************
6565 * ConfigurePortW (WINSPOOL.@)
6567 * Display the Configuration-Dialog for a specific Port
6569 * PARAMS
6570 * pName [I] Servername or NULL (local Computer)
6571 * hWnd [I] Handle to parent Window for the Dialog-Box
6572 * pPortName [I] Name of the Port, that should be configured
6574 * RETURNS
6575 * Success: TRUE
6576 * Failure: FALSE
6579 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6581 monitor_t * pm;
6582 monitor_t * pui;
6583 DWORD res;
6585 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6587 if (pName && pName[0]) {
6588 SetLastError(ERROR_INVALID_PARAMETER);
6589 return FALSE;
6592 if (!pPortName) {
6593 SetLastError(RPC_X_NULL_REF_POINTER);
6594 return FALSE;
6597 /* an empty Portname is Invalid, but can popup a Dialog */
6598 if (!pPortName[0]) {
6599 SetLastError(ERROR_NOT_SUPPORTED);
6600 return FALSE;
6603 pm = monitor_load_by_port(pPortName);
6604 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6605 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6606 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6607 TRACE("got %d with %u\n", res, GetLastError());
6609 else
6611 pui = monitor_loadui(pm);
6612 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6613 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6614 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6615 TRACE("got %d with %u\n", res, GetLastError());
6617 else
6619 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6620 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6622 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6623 SetLastError(ERROR_NOT_SUPPORTED);
6624 res = FALSE;
6626 monitor_unload(pui);
6628 monitor_unload(pm);
6630 TRACE("returning %d with %u\n", res, GetLastError());
6631 return res;
6634 /******************************************************************************
6635 * ConnectToPrinterDlg (WINSPOOL.@)
6637 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6639 FIXME("%p %x\n", hWnd, Flags);
6640 return NULL;
6643 /******************************************************************************
6644 * DeletePrinterConnectionA (WINSPOOL.@)
6646 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6648 FIXME("%s\n", debugstr_a(pName));
6649 return TRUE;
6652 /******************************************************************************
6653 * DeletePrinterConnectionW (WINSPOOL.@)
6655 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6657 FIXME("%s\n", debugstr_w(pName));
6658 return TRUE;
6661 /******************************************************************************
6662 * DeletePrinterDriverExW (WINSPOOL.@)
6664 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6665 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6667 HKEY hkey_drivers;
6668 BOOL ret = FALSE;
6670 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6671 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6673 if(pName && pName[0])
6675 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6676 SetLastError(ERROR_INVALID_PARAMETER);
6677 return FALSE;
6680 if(dwDeleteFlag)
6682 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6683 SetLastError(ERROR_INVALID_PARAMETER);
6684 return FALSE;
6687 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6689 if(!hkey_drivers)
6691 ERR("Can't open drivers key\n");
6692 return FALSE;
6695 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6696 ret = TRUE;
6698 RegCloseKey(hkey_drivers);
6700 return ret;
6703 /******************************************************************************
6704 * DeletePrinterDriverExA (WINSPOOL.@)
6706 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6707 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6709 UNICODE_STRING NameW, EnvW, DriverW;
6710 BOOL ret;
6712 asciitounicode(&NameW, pName);
6713 asciitounicode(&EnvW, pEnvironment);
6714 asciitounicode(&DriverW, pDriverName);
6716 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6718 RtlFreeUnicodeString(&DriverW);
6719 RtlFreeUnicodeString(&EnvW);
6720 RtlFreeUnicodeString(&NameW);
6722 return ret;
6725 /******************************************************************************
6726 * DeletePrinterDataExW (WINSPOOL.@)
6728 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6729 LPCWSTR pValueName)
6731 FIXME("%p %s %s\n", hPrinter,
6732 debugstr_w(pKeyName), debugstr_w(pValueName));
6733 return ERROR_INVALID_PARAMETER;
6736 /******************************************************************************
6737 * DeletePrinterDataExA (WINSPOOL.@)
6739 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6740 LPCSTR pValueName)
6742 FIXME("%p %s %s\n", hPrinter,
6743 debugstr_a(pKeyName), debugstr_a(pValueName));
6744 return ERROR_INVALID_PARAMETER;
6747 /******************************************************************************
6748 * DeletePrintProcessorA (WINSPOOL.@)
6750 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6752 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6753 debugstr_a(pPrintProcessorName));
6754 return TRUE;
6757 /******************************************************************************
6758 * DeletePrintProcessorW (WINSPOOL.@)
6760 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6762 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6763 debugstr_w(pPrintProcessorName));
6764 return TRUE;
6767 /******************************************************************************
6768 * DeletePrintProvidorA (WINSPOOL.@)
6770 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6772 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6773 debugstr_a(pPrintProviderName));
6774 return TRUE;
6777 /******************************************************************************
6778 * DeletePrintProvidorW (WINSPOOL.@)
6780 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6782 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6783 debugstr_w(pPrintProviderName));
6784 return TRUE;
6787 /******************************************************************************
6788 * EnumFormsA (WINSPOOL.@)
6790 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6791 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6793 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6794 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6795 return FALSE;
6798 /******************************************************************************
6799 * EnumFormsW (WINSPOOL.@)
6801 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6802 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6804 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6805 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6806 return FALSE;
6809 /*****************************************************************************
6810 * EnumMonitorsA [WINSPOOL.@]
6812 * See EnumMonitorsW.
6815 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6816 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6818 BOOL res;
6819 LPBYTE bufferW = NULL;
6820 LPWSTR nameW = NULL;
6821 DWORD needed = 0;
6822 DWORD numentries = 0;
6823 INT len;
6825 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6826 cbBuf, pcbNeeded, pcReturned);
6828 /* convert servername to unicode */
6829 if (pName) {
6830 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6831 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6832 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6834 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6835 needed = cbBuf * sizeof(WCHAR);
6836 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6837 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6839 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6840 if (pcbNeeded) needed = *pcbNeeded;
6841 /* HeapReAlloc return NULL, when bufferW was NULL */
6842 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6843 HeapAlloc(GetProcessHeap(), 0, needed);
6845 /* Try again with the large Buffer */
6846 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6848 numentries = pcReturned ? *pcReturned : 0;
6849 needed = 0;
6851 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6852 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6854 if (res) {
6855 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6856 DWORD entrysize = 0;
6857 DWORD index;
6858 LPSTR ptr;
6859 LPMONITOR_INFO_2W mi2w;
6860 LPMONITOR_INFO_2A mi2a;
6862 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6863 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6865 /* First pass: calculate the size for all Entries */
6866 mi2w = (LPMONITOR_INFO_2W) bufferW;
6867 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6868 index = 0;
6869 while (index < numentries) {
6870 index++;
6871 needed += entrysize; /* MONITOR_INFO_?A */
6872 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6874 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6875 NULL, 0, NULL, NULL);
6876 if (Level > 1) {
6877 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6878 NULL, 0, NULL, NULL);
6879 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6880 NULL, 0, NULL, NULL);
6882 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6883 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6884 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6887 /* check for errors and quit on failure */
6888 if (cbBuf < needed) {
6889 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6890 res = FALSE;
6891 goto emA_cleanup;
6893 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6894 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6895 cbBuf -= len ; /* free Bytes in the user-Buffer */
6896 mi2w = (LPMONITOR_INFO_2W) bufferW;
6897 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6898 index = 0;
6899 /* Second Pass: Fill the User Buffer (if we have one) */
6900 while ((index < numentries) && pMonitors) {
6901 index++;
6902 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6903 mi2a->pName = ptr;
6904 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6905 ptr, cbBuf , NULL, NULL);
6906 ptr += len;
6907 cbBuf -= len;
6908 if (Level > 1) {
6909 mi2a->pEnvironment = ptr;
6910 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6911 ptr, cbBuf, NULL, NULL);
6912 ptr += len;
6913 cbBuf -= len;
6915 mi2a->pDLLName = ptr;
6916 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6917 ptr, cbBuf, NULL, NULL);
6918 ptr += len;
6919 cbBuf -= len;
6921 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6922 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6923 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6926 emA_cleanup:
6927 if (pcbNeeded) *pcbNeeded = needed;
6928 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6930 HeapFree(GetProcessHeap(), 0, nameW);
6931 HeapFree(GetProcessHeap(), 0, bufferW);
6933 TRACE("returning %d with %d (%d byte for %d entries)\n",
6934 (res), GetLastError(), needed, numentries);
6936 return (res);
6940 /*****************************************************************************
6941 * EnumMonitorsW [WINSPOOL.@]
6943 * Enumerate available Port-Monitors
6945 * PARAMS
6946 * pName [I] Servername or NULL (local Computer)
6947 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6948 * pMonitors [O] PTR to Buffer that receives the Result
6949 * cbBuf [I] Size of Buffer at pMonitors
6950 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6951 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6953 * RETURNS
6954 * Success: TRUE
6955 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6958 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6959 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6962 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6963 cbBuf, pcbNeeded, pcReturned);
6965 if ((backend == NULL) && !load_backend()) return FALSE;
6967 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6968 SetLastError(RPC_X_NULL_REF_POINTER);
6969 return FALSE;
6972 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6975 /******************************************************************************
6976 * SpoolerInit (WINSPOOL.@)
6978 * Initialize the Spooler
6980 * RETURNS
6981 * Success: TRUE
6982 * Failure: FALSE
6984 * NOTES
6985 * The function fails on windows, when the spooler service is not running
6988 BOOL WINAPI SpoolerInit(void)
6991 if ((backend == NULL) && !load_backend()) return FALSE;
6992 return TRUE;
6995 /******************************************************************************
6996 * XcvDataW (WINSPOOL.@)
6998 * Execute commands in the Printmonitor DLL
7000 * PARAMS
7001 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7002 * pszDataName [i] Name of the command to execute
7003 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7004 * cbInputData [i] Size in Bytes of Buffer at pInputData
7005 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7006 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7007 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7008 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7010 * RETURNS
7011 * Success: TRUE
7012 * Failure: FALSE
7014 * NOTES
7015 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7016 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7018 * Minimal List of commands, that a Printmonitor DLL should support:
7020 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7021 *| "AddPort" : Add a Port
7022 *| "DeletePort": Delete a Port
7024 * Many Printmonitors support additional commands. Examples for localspl.dll:
7025 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7026 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7029 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7030 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7031 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7033 opened_printer_t *printer;
7035 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7036 pInputData, cbInputData, pOutputData,
7037 cbOutputData, pcbOutputNeeded, pdwStatus);
7039 printer = get_opened_printer(hXcv);
7040 if (!printer || (!printer->hXcv)) {
7041 SetLastError(ERROR_INVALID_HANDLE);
7042 return FALSE;
7045 if (!pcbOutputNeeded) {
7046 SetLastError(ERROR_INVALID_PARAMETER);
7047 return FALSE;
7050 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7051 SetLastError(RPC_X_NULL_REF_POINTER);
7052 return FALSE;
7055 *pcbOutputNeeded = 0;
7057 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7058 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7060 return TRUE;
7063 /*****************************************************************************
7064 * EnumPrinterDataA [WINSPOOL.@]
7067 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7068 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7069 DWORD cbData, LPDWORD pcbData )
7071 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7072 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7073 return ERROR_NO_MORE_ITEMS;
7076 /*****************************************************************************
7077 * EnumPrinterDataW [WINSPOOL.@]
7080 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7081 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7082 DWORD cbData, LPDWORD pcbData )
7084 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7085 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7086 return ERROR_NO_MORE_ITEMS;
7089 /*****************************************************************************
7090 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7093 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7094 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7095 LPDWORD pcbNeeded, LPDWORD pcReturned)
7097 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7098 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7099 pcbNeeded, pcReturned);
7100 return FALSE;
7103 /*****************************************************************************
7104 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7107 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7108 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7109 LPDWORD pcbNeeded, LPDWORD pcReturned)
7111 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7112 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7113 pcbNeeded, pcReturned);
7114 return FALSE;
7117 /*****************************************************************************
7118 * EnumPrintProcessorsA [WINSPOOL.@]
7121 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7122 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7124 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7125 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7126 return FALSE;
7129 /*****************************************************************************
7130 * EnumPrintProcessorsW [WINSPOOL.@]
7133 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7134 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7136 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7137 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7138 cbBuf, pcbNeeded, pcbReturned);
7139 return FALSE;
7142 /*****************************************************************************
7143 * ExtDeviceMode [WINSPOOL.@]
7146 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7147 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7148 DWORD fMode)
7150 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7151 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7152 debugstr_a(pProfile), fMode);
7153 return -1;
7156 /*****************************************************************************
7157 * FindClosePrinterChangeNotification [WINSPOOL.@]
7160 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7162 FIXME("Stub: %p\n", hChange);
7163 return TRUE;
7166 /*****************************************************************************
7167 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7170 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7171 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7173 FIXME("Stub: %p %x %x %p\n",
7174 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7175 return INVALID_HANDLE_VALUE;
7178 /*****************************************************************************
7179 * FindNextPrinterChangeNotification [WINSPOOL.@]
7182 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7183 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7185 FIXME("Stub: %p %p %p %p\n",
7186 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7187 return FALSE;
7190 /*****************************************************************************
7191 * FreePrinterNotifyInfo [WINSPOOL.@]
7194 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7196 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7197 return TRUE;
7200 /*****************************************************************************
7201 * string_to_buf
7203 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7204 * ansi depending on the unicode parameter.
7206 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7208 if(!str)
7210 *size = 0;
7211 return TRUE;
7214 if(unicode)
7216 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7217 if(*size <= cb)
7219 memcpy(ptr, str, *size);
7220 return TRUE;
7222 return FALSE;
7224 else
7226 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7227 if(*size <= cb)
7229 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7230 return TRUE;
7232 return FALSE;
7236 /*****************************************************************************
7237 * get_job_info_1
7239 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7240 LPDWORD pcbNeeded, BOOL unicode)
7242 DWORD size, left = cbBuf;
7243 BOOL space = (cbBuf > 0);
7244 LPBYTE ptr = buf;
7246 *pcbNeeded = 0;
7248 if(space)
7250 ji1->JobId = job->job_id;
7253 string_to_buf(job->document_title, ptr, left, &size, unicode);
7254 if(space && size <= left)
7256 ji1->pDocument = (LPWSTR)ptr;
7257 ptr += size;
7258 left -= size;
7260 else
7261 space = FALSE;
7262 *pcbNeeded += size;
7264 return space;
7267 /*****************************************************************************
7268 * get_job_info_2
7270 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7271 LPDWORD pcbNeeded, BOOL unicode)
7273 DWORD size, left = cbBuf;
7274 BOOL space = (cbBuf > 0);
7275 LPBYTE ptr = buf;
7277 *pcbNeeded = 0;
7279 if(space)
7281 ji2->JobId = job->job_id;
7284 string_to_buf(job->document_title, ptr, left, &size, unicode);
7285 if(space && size <= left)
7287 ji2->pDocument = (LPWSTR)ptr;
7288 ptr += size;
7289 left -= size;
7291 else
7292 space = FALSE;
7293 *pcbNeeded += size;
7295 return space;
7298 /*****************************************************************************
7299 * get_job_info
7301 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7302 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7304 BOOL ret = FALSE;
7305 DWORD needed = 0, size;
7306 job_t *job;
7307 LPBYTE ptr = pJob;
7309 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7311 EnterCriticalSection(&printer_handles_cs);
7312 job = get_job(hPrinter, JobId);
7313 if(!job)
7314 goto end;
7316 switch(Level)
7318 case 1:
7319 size = sizeof(JOB_INFO_1W);
7320 if(cbBuf >= size)
7322 cbBuf -= size;
7323 ptr += size;
7324 memset(pJob, 0, size);
7326 else
7327 cbBuf = 0;
7328 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7329 needed += size;
7330 break;
7332 case 2:
7333 size = sizeof(JOB_INFO_2W);
7334 if(cbBuf >= size)
7336 cbBuf -= size;
7337 ptr += size;
7338 memset(pJob, 0, size);
7340 else
7341 cbBuf = 0;
7342 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7343 needed += size;
7344 break;
7346 case 3:
7347 size = sizeof(JOB_INFO_3);
7348 if(cbBuf >= size)
7350 cbBuf -= size;
7351 memset(pJob, 0, size);
7352 ret = TRUE;
7354 else
7355 cbBuf = 0;
7356 needed = size;
7357 break;
7359 default:
7360 SetLastError(ERROR_INVALID_LEVEL);
7361 goto end;
7363 if(pcbNeeded)
7364 *pcbNeeded = needed;
7365 end:
7366 LeaveCriticalSection(&printer_handles_cs);
7367 return ret;
7370 /*****************************************************************************
7371 * GetJobA [WINSPOOL.@]
7374 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7375 DWORD cbBuf, LPDWORD pcbNeeded)
7377 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7380 /*****************************************************************************
7381 * GetJobW [WINSPOOL.@]
7384 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7385 DWORD cbBuf, LPDWORD pcbNeeded)
7387 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7390 /*****************************************************************************
7391 * schedule_lpr
7393 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7395 char *unixname, *queue, *cmd;
7396 char fmt[] = "lpr -P%s %s";
7397 DWORD len;
7398 int r;
7400 if(!(unixname = wine_get_unix_file_name(filename)))
7401 return FALSE;
7403 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7404 queue = HeapAlloc(GetProcessHeap(), 0, len);
7405 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7407 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7408 sprintf(cmd, fmt, queue, unixname);
7410 TRACE("printing with: %s\n", cmd);
7411 r = system(cmd);
7413 HeapFree(GetProcessHeap(), 0, cmd);
7414 HeapFree(GetProcessHeap(), 0, queue);
7415 HeapFree(GetProcessHeap(), 0, unixname);
7416 return (r == 0);
7419 /*****************************************************************************
7420 * schedule_cups
7422 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7424 #ifdef SONAME_LIBCUPS
7425 if(pcupsPrintFile)
7427 char *unixname, *queue, *unix_doc_title;
7428 DWORD len;
7429 BOOL ret;
7431 if(!(unixname = wine_get_unix_file_name(filename)))
7432 return FALSE;
7434 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7435 queue = HeapAlloc(GetProcessHeap(), 0, len);
7436 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7438 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7439 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7440 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7442 TRACE("printing via cups\n");
7443 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7444 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7445 HeapFree(GetProcessHeap(), 0, queue);
7446 HeapFree(GetProcessHeap(), 0, unixname);
7447 return ret;
7449 else
7450 #endif
7452 return schedule_lpr(printer_name, filename);
7456 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7458 LPWSTR filename;
7460 switch(msg)
7462 case WM_INITDIALOG:
7463 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7464 return TRUE;
7466 case WM_COMMAND:
7467 if(HIWORD(wparam) == BN_CLICKED)
7469 if(LOWORD(wparam) == IDOK)
7471 HANDLE hf;
7472 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7473 LPWSTR *output;
7475 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7476 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7478 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7480 WCHAR caption[200], message[200];
7481 int mb_ret;
7483 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7484 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7485 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7486 if(mb_ret == IDCANCEL)
7488 HeapFree(GetProcessHeap(), 0, filename);
7489 return TRUE;
7492 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7493 if(hf == INVALID_HANDLE_VALUE)
7495 WCHAR caption[200], message[200];
7497 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7498 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7499 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7500 HeapFree(GetProcessHeap(), 0, filename);
7501 return TRUE;
7503 CloseHandle(hf);
7504 DeleteFileW(filename);
7505 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7506 *output = filename;
7507 EndDialog(hwnd, IDOK);
7508 return TRUE;
7510 if(LOWORD(wparam) == IDCANCEL)
7512 EndDialog(hwnd, IDCANCEL);
7513 return TRUE;
7516 return FALSE;
7518 return FALSE;
7521 /*****************************************************************************
7522 * get_filename
7524 static BOOL get_filename(LPWSTR *filename)
7526 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7527 file_dlg_proc, (LPARAM)filename) == IDOK;
7530 /*****************************************************************************
7531 * schedule_file
7533 static BOOL schedule_file(LPCWSTR filename)
7535 LPWSTR output = NULL;
7537 if(get_filename(&output))
7539 BOOL r;
7540 TRACE("copy to %s\n", debugstr_w(output));
7541 r = CopyFileW(filename, output, FALSE);
7542 HeapFree(GetProcessHeap(), 0, output);
7543 return r;
7545 return FALSE;
7548 /*****************************************************************************
7549 * schedule_pipe
7551 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7553 #ifdef HAVE_FORK
7554 char *unixname, *cmdA;
7555 DWORD len;
7556 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7557 BOOL ret = FALSE;
7558 char buf[1024];
7560 if(!(unixname = wine_get_unix_file_name(filename)))
7561 return FALSE;
7563 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7564 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7565 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7567 TRACE("printing with: %s\n", cmdA);
7569 if((file_fd = open(unixname, O_RDONLY)) == -1)
7570 goto end;
7572 if (pipe(fds))
7574 ERR("pipe() failed!\n");
7575 goto end;
7578 if (fork() == 0)
7580 close(0);
7581 dup2(fds[0], 0);
7582 close(fds[1]);
7584 /* reset signals that we previously set to SIG_IGN */
7585 signal(SIGPIPE, SIG_DFL);
7586 signal(SIGCHLD, SIG_DFL);
7588 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7589 _exit(1);
7592 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7593 write(fds[1], buf, no_read);
7595 ret = TRUE;
7597 end:
7598 if(file_fd != -1) close(file_fd);
7599 if(fds[0] != -1) close(fds[0]);
7600 if(fds[1] != -1) close(fds[1]);
7602 HeapFree(GetProcessHeap(), 0, cmdA);
7603 HeapFree(GetProcessHeap(), 0, unixname);
7604 return ret;
7605 #else
7606 return FALSE;
7607 #endif
7610 /*****************************************************************************
7611 * schedule_unixfile
7613 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7615 int in_fd, out_fd, no_read;
7616 char buf[1024];
7617 BOOL ret = FALSE;
7618 char *unixname, *outputA;
7619 DWORD len;
7621 if(!(unixname = wine_get_unix_file_name(filename)))
7622 return FALSE;
7624 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7625 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7626 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7628 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7629 in_fd = open(unixname, O_RDONLY);
7630 if(out_fd == -1 || in_fd == -1)
7631 goto end;
7633 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7634 write(out_fd, buf, no_read);
7636 ret = TRUE;
7637 end:
7638 if(in_fd != -1) close(in_fd);
7639 if(out_fd != -1) close(out_fd);
7640 HeapFree(GetProcessHeap(), 0, outputA);
7641 HeapFree(GetProcessHeap(), 0, unixname);
7642 return ret;
7645 /*****************************************************************************
7646 * ScheduleJob [WINSPOOL.@]
7649 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7651 opened_printer_t *printer;
7652 BOOL ret = FALSE;
7653 struct list *cursor, *cursor2;
7655 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7656 EnterCriticalSection(&printer_handles_cs);
7657 printer = get_opened_printer(hPrinter);
7658 if(!printer)
7659 goto end;
7661 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7663 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7664 HANDLE hf;
7666 if(job->job_id != dwJobID) continue;
7668 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7669 if(hf != INVALID_HANDLE_VALUE)
7671 PRINTER_INFO_5W *pi5;
7672 DWORD needed;
7673 HKEY hkey;
7674 WCHAR output[1024];
7675 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7676 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7678 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7679 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7680 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7681 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7682 debugstr_w(pi5->pPortName));
7684 output[0] = 0;
7686 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7687 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7689 DWORD type, count = sizeof(output);
7690 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7691 RegCloseKey(hkey);
7693 if(output[0] == '|')
7695 ret = schedule_pipe(output + 1, job->filename);
7697 else if(output[0])
7699 ret = schedule_unixfile(output, job->filename);
7701 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7703 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7705 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7707 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7709 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7711 ret = schedule_file(job->filename);
7713 else
7715 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7717 HeapFree(GetProcessHeap(), 0, pi5);
7718 CloseHandle(hf);
7719 DeleteFileW(job->filename);
7721 list_remove(cursor);
7722 HeapFree(GetProcessHeap(), 0, job->document_title);
7723 HeapFree(GetProcessHeap(), 0, job->filename);
7724 HeapFree(GetProcessHeap(), 0, job);
7725 break;
7727 end:
7728 LeaveCriticalSection(&printer_handles_cs);
7729 return ret;
7732 /*****************************************************************************
7733 * StartDocDlgA [WINSPOOL.@]
7735 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7737 UNICODE_STRING usBuffer;
7738 DOCINFOW docW;
7739 LPWSTR retW;
7740 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7741 LPSTR ret = NULL;
7743 docW.cbSize = sizeof(docW);
7744 if (doc->lpszDocName)
7746 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7747 if (!(docW.lpszDocName = docnameW)) return NULL;
7749 if (doc->lpszOutput)
7751 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7752 if (!(docW.lpszOutput = outputW)) return NULL;
7754 if (doc->lpszDatatype)
7756 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7757 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7759 docW.fwType = doc->fwType;
7761 retW = StartDocDlgW(hPrinter, &docW);
7763 if(retW)
7765 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7766 ret = HeapAlloc(GetProcessHeap(), 0, len);
7767 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7768 HeapFree(GetProcessHeap(), 0, retW);
7771 HeapFree(GetProcessHeap(), 0, datatypeW);
7772 HeapFree(GetProcessHeap(), 0, outputW);
7773 HeapFree(GetProcessHeap(), 0, docnameW);
7775 return ret;
7778 /*****************************************************************************
7779 * StartDocDlgW [WINSPOOL.@]
7781 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7782 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7783 * port is "FILE:". Also returns the full path if passed a relative path.
7785 * The caller should free the returned string from the process heap.
7787 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7789 LPWSTR ret = NULL;
7790 DWORD len, attr;
7792 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7794 PRINTER_INFO_5W *pi5;
7795 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7796 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7797 return NULL;
7798 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7799 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7800 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7802 HeapFree(GetProcessHeap(), 0, pi5);
7803 return NULL;
7805 HeapFree(GetProcessHeap(), 0, pi5);
7808 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7810 LPWSTR name;
7812 if (get_filename(&name))
7814 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7816 HeapFree(GetProcessHeap(), 0, name);
7817 return NULL;
7819 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7820 GetFullPathNameW(name, len, ret, NULL);
7821 HeapFree(GetProcessHeap(), 0, name);
7823 return ret;
7826 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7827 return NULL;
7829 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7830 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7832 attr = GetFileAttributesW(ret);
7833 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7835 HeapFree(GetProcessHeap(), 0, ret);
7836 ret = NULL;
7838 return ret;