push d1f5df181c120dbe494f7c89b454752c2e0dcc04
[wine/hacks.git] / dlls / winspool.drv / info.c
blobbc688f49332760df7ba8fac8f0ee3e8dc21fcf30
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2008 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_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(cupsGetDests) *pcupsGetDests;
464 static typeof(cupsGetPPD) *pcupsGetPPD;
465 static typeof(cupsPrintFile) *pcupsPrintFile;
466 static void *cupshandle;
468 static BOOL CUPS_LoadPrinters(void)
470 int i, nrofdests;
471 BOOL hadprinter = FALSE, haddefault = FALSE;
472 cups_dest_t *dests;
473 PRINTER_INFO_2A pinfo2a;
474 char *port,*devline;
475 HKEY hkeyPrinter, hkeyPrinters, hkey;
476 char loaderror[256];
478 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
479 if (!cupshandle) {
480 TRACE("%s\n", loaderror);
481 return FALSE;
483 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
485 #define DYNCUPS(x) \
486 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
487 if (!p##x) return FALSE;
489 DYNCUPS(cupsGetPPD);
490 DYNCUPS(cupsGetDests);
491 DYNCUPS(cupsPrintFile);
492 #undef DYNCUPS
494 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
495 ERROR_SUCCESS) {
496 ERR("Can't create Printers key\n");
497 return FALSE;
500 nrofdests = pcupsGetDests(&dests);
501 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
502 for (i=0;i<nrofdests;i++) {
503 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
504 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
505 sprintf(port,"LPR:%s", dests[i].name);
506 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
507 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
508 sprintf(devline, "WINEPS.DRV,%s", port);
509 WriteProfileStringA("devices", dests[i].name, devline);
510 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
511 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
512 RegCloseKey(hkey);
515 lstrcatA(devline, ",15,45");
516 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
517 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
518 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
519 RegCloseKey(hkey);
522 HeapFree(GetProcessHeap(), 0, devline);
524 TRACE("Printer %d: %s\n", i, dests[i].name);
525 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
526 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
527 and continue */
528 TRACE("Printer already exists\n");
529 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
530 RegCloseKey(hkeyPrinter);
531 } else {
532 static CHAR data_type[] = "RAW",
533 print_proc[] = "WinPrint",
534 comment[] = "WINEPS Printer using CUPS",
535 location[] = "<physical location of printer>",
536 params[] = "<parameters?>",
537 share_name[] = "<share name?>",
538 sep_file[] = "<sep file?>";
540 add_printer_driver(dests[i].name);
542 memset(&pinfo2a,0,sizeof(pinfo2a));
543 pinfo2a.pPrinterName = dests[i].name;
544 pinfo2a.pDatatype = data_type;
545 pinfo2a.pPrintProcessor = print_proc;
546 pinfo2a.pDriverName = dests[i].name;
547 pinfo2a.pComment = comment;
548 pinfo2a.pLocation = location;
549 pinfo2a.pPortName = port;
550 pinfo2a.pParameters = params;
551 pinfo2a.pShareName = share_name;
552 pinfo2a.pSepFile = sep_file;
554 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
555 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
556 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
559 HeapFree(GetProcessHeap(),0,port);
561 hadprinter = TRUE;
562 if (dests[i].is_default) {
563 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
564 haddefault = TRUE;
567 if (hadprinter & !haddefault)
568 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
569 RegCloseKey(hkeyPrinters);
570 return hadprinter;
572 #endif
574 static BOOL
575 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
576 PRINTER_INFO_2A pinfo2a;
577 char *e,*s,*name,*prettyname,*devname;
578 BOOL ret = FALSE, set_default = FALSE;
579 char *port = NULL, *devline,*env_default;
580 HKEY hkeyPrinter, hkeyPrinters, hkey;
582 while (isspace(*pent)) pent++;
583 s = strchr(pent,':');
584 if(s) *s='\0';
585 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
586 strcpy(name,pent);
587 if(s) {
588 *s=':';
589 pent = s;
590 } else
591 pent = "";
593 TRACE("name=%s entry=%s\n",name, pent);
595 if(ispunct(*name)) { /* a tc entry, not a real printer */
596 TRACE("skipping tc entry\n");
597 goto end;
600 if(strstr(pent,":server")) { /* server only version so skip */
601 TRACE("skipping server entry\n");
602 goto end;
605 /* Determine whether this is a postscript printer. */
607 ret = TRUE;
608 env_default = getenv("PRINTER");
609 prettyname = name;
610 /* Get longest name, usually the one at the right for later display. */
611 while((s=strchr(prettyname,'|'))) {
612 *s = '\0';
613 e = s;
614 while(isspace(*--e)) *e = '\0';
615 TRACE("\t%s\n", debugstr_a(prettyname));
616 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
617 for(prettyname = s+1; isspace(*prettyname); prettyname++)
620 e = prettyname + strlen(prettyname);
621 while(isspace(*--e)) *e = '\0';
622 TRACE("\t%s\n", debugstr_a(prettyname));
623 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
625 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
626 * if it is too long, we use it as comment below. */
627 devname = prettyname;
628 if (strlen(devname)>=CCHDEVICENAME-1)
629 devname = name;
630 if (strlen(devname)>=CCHDEVICENAME-1) {
631 ret = FALSE;
632 goto end;
635 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
636 sprintf(port,"LPR:%s",name);
638 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
639 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
640 sprintf(devline, "WINEPS.DRV,%s", port);
641 WriteProfileStringA("devices", devname, devline);
642 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
643 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
644 RegCloseKey(hkey);
647 lstrcatA(devline, ",15,45");
648 WriteProfileStringA("PrinterPorts", devname, devline);
649 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
650 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
651 RegCloseKey(hkey);
654 HeapFree(GetProcessHeap(),0,devline);
656 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
657 ERROR_SUCCESS) {
658 ERR("Can't create Printers key\n");
659 ret = FALSE;
660 goto end;
662 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
663 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
664 and continue */
665 TRACE("Printer already exists\n");
666 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
667 RegCloseKey(hkeyPrinter);
668 } else {
669 static CHAR data_type[] = "RAW",
670 print_proc[] = "WinPrint",
671 comment[] = "WINEPS Printer using LPR",
672 params[] = "<parameters?>",
673 share_name[] = "<share name?>",
674 sep_file[] = "<sep file?>";
676 add_printer_driver(devname);
678 memset(&pinfo2a,0,sizeof(pinfo2a));
679 pinfo2a.pPrinterName = devname;
680 pinfo2a.pDatatype = data_type;
681 pinfo2a.pPrintProcessor = print_proc;
682 pinfo2a.pDriverName = devname;
683 pinfo2a.pComment = comment;
684 pinfo2a.pLocation = prettyname;
685 pinfo2a.pPortName = port;
686 pinfo2a.pParameters = params;
687 pinfo2a.pShareName = share_name;
688 pinfo2a.pSepFile = sep_file;
690 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
691 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
692 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
695 RegCloseKey(hkeyPrinters);
697 if (isfirst || set_default)
698 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
700 end:
701 HeapFree(GetProcessHeap(), 0, port);
702 HeapFree(GetProcessHeap(), 0, name);
703 return ret;
706 static BOOL
707 PRINTCAP_LoadPrinters(void) {
708 BOOL hadprinter = FALSE;
709 char buf[200];
710 FILE *f;
711 char *pent = NULL;
712 BOOL had_bash = FALSE;
714 f = fopen("/etc/printcap","r");
715 if (!f)
716 return FALSE;
718 while(fgets(buf,sizeof(buf),f)) {
719 char *start, *end;
721 end=strchr(buf,'\n');
722 if (end) *end='\0';
724 start = buf;
725 while(isspace(*start)) start++;
726 if(*start == '#' || *start == '\0')
727 continue;
729 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
730 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
731 HeapFree(GetProcessHeap(),0,pent);
732 pent = NULL;
735 if (end && *--end == '\\') {
736 *end = '\0';
737 had_bash = TRUE;
738 } else
739 had_bash = FALSE;
741 if (pent) {
742 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
743 strcat(pent,start);
744 } else {
745 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
746 strcpy(pent,start);
750 if(pent) {
751 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
752 HeapFree(GetProcessHeap(),0,pent);
754 fclose(f);
755 return hadprinter;
758 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
760 if (value)
761 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
762 (lstrlenW(value) + 1) * sizeof(WCHAR));
763 else
764 return ERROR_FILE_NOT_FOUND;
767 /******************************************************************
768 * monitor_unload [internal]
770 * release a printmonitor and unload it from memory, when needed
773 static void monitor_unload(monitor_t * pm)
775 if (pm == NULL) return;
776 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
778 EnterCriticalSection(&monitor_handles_cs);
780 if (pm->refcount) pm->refcount--;
782 if (pm->refcount == 0) {
783 list_remove(&pm->entry);
784 FreeLibrary(pm->hdll);
785 HeapFree(GetProcessHeap(), 0, pm->name);
786 HeapFree(GetProcessHeap(), 0, pm->dllname);
787 HeapFree(GetProcessHeap(), 0, pm);
789 LeaveCriticalSection(&monitor_handles_cs);
792 /******************************************************************
793 * monitor_unloadall [internal]
795 * release all printmonitors and unload them from memory, when needed
798 static void monitor_unloadall(void)
800 monitor_t * pm;
801 monitor_t * next;
803 EnterCriticalSection(&monitor_handles_cs);
804 /* iterate through the list, with safety against removal */
805 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
807 monitor_unload(pm);
809 LeaveCriticalSection(&monitor_handles_cs);
812 /******************************************************************
813 * monitor_load [internal]
815 * load a printmonitor, get the dllname from the registry, when needed
816 * initialize the monitor and dump found function-pointers
818 * On failure, SetLastError() is called and NULL is returned
821 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
823 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
824 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
825 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
826 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
827 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
829 monitor_t * pm = NULL;
830 monitor_t * cursor;
831 LPWSTR regroot = NULL;
832 LPWSTR driver = dllname;
834 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
835 /* Is the Monitor already loaded? */
836 EnterCriticalSection(&monitor_handles_cs);
838 if (name) {
839 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
841 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
842 pm = cursor;
843 break;
848 if (pm == NULL) {
849 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
850 if (pm == NULL) goto cleanup;
851 list_add_tail(&monitor_handles, &pm->entry);
853 pm->refcount++;
855 if (pm->name == NULL) {
856 /* Load the monitor */
857 LPMONITOREX pmonitorEx;
858 DWORD len;
860 if (name) {
861 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
862 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
865 if (regroot) {
866 lstrcpyW(regroot, MonitorsW);
867 lstrcatW(regroot, name);
868 /* Get the Driver from the Registry */
869 if (driver == NULL) {
870 HKEY hroot;
871 DWORD namesize;
872 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
873 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
874 &namesize) == ERROR_SUCCESS) {
875 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
876 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
878 RegCloseKey(hroot);
883 pm->name = strdupW(name);
884 pm->dllname = strdupW(driver);
886 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
887 monitor_unload(pm);
888 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
889 pm = NULL;
890 goto cleanup;
893 pm->hdll = LoadLibraryW(driver);
894 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
896 if (pm->hdll == NULL) {
897 monitor_unload(pm);
898 SetLastError(ERROR_MOD_NOT_FOUND);
899 pm = NULL;
900 goto cleanup;
903 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
904 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
905 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
906 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
907 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
910 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
911 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
912 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
913 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
914 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
916 if (pInitializePrintMonitorUI != NULL) {
917 pm->monitorUI = pInitializePrintMonitorUI();
918 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
919 if (pm->monitorUI) {
920 TRACE( "0x%08x: dwMonitorSize (%d)\n",
921 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
926 if (pInitializePrintMonitor && regroot) {
927 pmonitorEx = pInitializePrintMonitor(regroot);
928 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
929 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
931 if (pmonitorEx) {
932 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
933 pm->monitor = &(pmonitorEx->Monitor);
937 if (pm->monitor) {
938 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
942 if (!pm->monitor && regroot) {
943 if (pInitializePrintMonitor2 != NULL) {
944 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
946 if (pInitializeMonitorEx != NULL) {
947 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
949 if (pInitializeMonitor != NULL) {
950 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
953 if (!pm->monitor && !pm->monitorUI) {
954 monitor_unload(pm);
955 SetLastError(ERROR_PROC_NOT_FOUND);
956 pm = NULL;
959 cleanup:
960 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
961 pm->refcount++;
962 pm_localport = pm;
964 LeaveCriticalSection(&monitor_handles_cs);
965 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
966 HeapFree(GetProcessHeap(), 0, regroot);
967 TRACE("=> %p\n", pm);
968 return pm;
971 /******************************************************************
972 * monitor_loadall [internal]
974 * Load all registered monitors
977 static DWORD monitor_loadall(void)
979 monitor_t * pm;
980 DWORD registered = 0;
981 DWORD loaded = 0;
982 HKEY hmonitors;
983 WCHAR buffer[MAX_PATH];
984 DWORD id = 0;
986 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
987 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
988 NULL, NULL, NULL, NULL, NULL);
990 TRACE("%d monitors registered\n", registered);
992 EnterCriticalSection(&monitor_handles_cs);
993 while (id < registered) {
994 buffer[0] = '\0';
995 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
996 pm = monitor_load(buffer, NULL);
997 if (pm) loaded++;
998 id++;
1000 LeaveCriticalSection(&monitor_handles_cs);
1001 RegCloseKey(hmonitors);
1003 TRACE("%d monitors loaded\n", loaded);
1004 return loaded;
1007 /******************************************************************
1008 * monitor_loadui [internal]
1010 * load the userinterface-dll for a given portmonitor
1012 * On failure, NULL is returned
1015 static monitor_t * monitor_loadui(monitor_t * pm)
1017 monitor_t * pui = NULL;
1018 LPWSTR buffer[MAX_PATH];
1019 HANDLE hXcv;
1020 DWORD len;
1021 DWORD res;
1023 if (pm == NULL) return NULL;
1024 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1026 /* Try the Portmonitor first; works for many monitors */
1027 if (pm->monitorUI) {
1028 EnterCriticalSection(&monitor_handles_cs);
1029 pm->refcount++;
1030 LeaveCriticalSection(&monitor_handles_cs);
1031 return pm;
1034 /* query the userinterface-dllname from the Portmonitor */
1035 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1036 /* building (",XcvMonitor %s",pm->name) not needed yet */
1037 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1038 TRACE("got %u with %p\n", res, hXcv);
1039 if (res) {
1040 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1041 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1042 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1043 pm->monitor->pfnXcvClosePort(hXcv);
1046 return pui;
1050 /******************************************************************
1051 * monitor_load_by_port [internal]
1053 * load a printmonitor for a given port
1055 * On failure, NULL is returned
1058 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1060 HKEY hroot;
1061 HKEY hport;
1062 LPWSTR buffer;
1063 monitor_t * pm = NULL;
1064 DWORD registered = 0;
1065 DWORD id = 0;
1066 DWORD len;
1068 TRACE("(%s)\n", debugstr_w(portname));
1070 /* Try the Local Monitor first */
1071 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1072 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1073 /* found the portname */
1074 RegCloseKey(hroot);
1075 return monitor_load(LocalPortW, NULL);
1077 RegCloseKey(hroot);
1080 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1081 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1082 if (buffer == NULL) return NULL;
1084 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1085 EnterCriticalSection(&monitor_handles_cs);
1086 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1088 while ((pm == NULL) && (id < registered)) {
1089 buffer[0] = '\0';
1090 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1091 TRACE("testing %s\n", debugstr_w(buffer));
1092 len = lstrlenW(buffer);
1093 lstrcatW(buffer, bs_Ports_bsW);
1094 lstrcatW(buffer, portname);
1095 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1096 RegCloseKey(hport);
1097 buffer[len] = '\0'; /* use only the Monitor-Name */
1098 pm = monitor_load(buffer, NULL);
1100 id++;
1102 LeaveCriticalSection(&monitor_handles_cs);
1103 RegCloseKey(hroot);
1105 HeapFree(GetProcessHeap(), 0, buffer);
1106 return pm;
1109 /******************************************************************
1110 * enumerate the local Ports from all loaded monitors (internal)
1112 * returns the needed size (in bytes) for pPorts
1113 * and *lpreturned is set to number of entries returned in pPorts
1116 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1118 monitor_t * pm;
1119 LPWSTR ptr;
1120 LPPORT_INFO_2W cache;
1121 LPPORT_INFO_2W out;
1122 LPBYTE pi_buffer = NULL;
1123 DWORD pi_allocated = 0;
1124 DWORD pi_needed;
1125 DWORD pi_index;
1126 DWORD pi_returned;
1127 DWORD res;
1128 DWORD outindex = 0;
1129 DWORD needed;
1130 DWORD numentries;
1131 DWORD entrysize;
1134 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1135 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1137 numentries = *lpreturned; /* this is 0, when we scan the registry */
1138 needed = entrysize * numentries;
1139 ptr = (LPWSTR) &pPorts[needed];
1141 numentries = 0;
1142 needed = 0;
1144 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1146 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1147 pi_needed = 0;
1148 pi_returned = 0;
1149 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1150 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1151 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1152 HeapFree(GetProcessHeap(), 0, pi_buffer);
1153 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1154 pi_allocated = (pi_buffer) ? pi_needed : 0;
1155 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1157 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1158 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1160 numentries += pi_returned;
1161 needed += pi_needed;
1163 /* fill the output-buffer (pPorts), if we have one */
1164 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1165 pi_index = 0;
1166 while (pi_returned > pi_index) {
1167 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1168 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1169 out->pPortName = ptr;
1170 lstrcpyW(ptr, cache->pPortName);
1171 ptr += (lstrlenW(ptr)+1);
1172 if (level > 1) {
1173 out->pMonitorName = ptr;
1174 lstrcpyW(ptr, cache->pMonitorName);
1175 ptr += (lstrlenW(ptr)+1);
1177 out->pDescription = ptr;
1178 lstrcpyW(ptr, cache->pDescription);
1179 ptr += (lstrlenW(ptr)+1);
1180 out->fPortType = cache->fPortType;
1181 out->Reserved = cache->Reserved;
1183 pi_index++;
1184 outindex++;
1189 /* the temporary portinfo-buffer is no longer needed */
1190 HeapFree(GetProcessHeap(), 0, pi_buffer);
1192 *lpreturned = numentries;
1193 TRACE("need %d byte for %d entries\n", needed, numentries);
1194 return needed;
1197 /******************************************************************
1198 * get_servername_from_name (internal)
1200 * for an external server, a copy of the serverpart from the full name is returned
1203 static LPWSTR get_servername_from_name(LPCWSTR name)
1205 LPWSTR server;
1206 LPWSTR ptr;
1207 WCHAR buffer[MAX_PATH];
1208 DWORD len;
1210 if (name == NULL) return NULL;
1211 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1213 server = strdupW(&name[2]); /* skip over both backslash */
1214 if (server == NULL) return NULL;
1216 /* strip '\' and the printername */
1217 ptr = strchrW(server, '\\');
1218 if (ptr) ptr[0] = '\0';
1220 TRACE("found %s\n", debugstr_w(server));
1222 len = sizeof(buffer)/sizeof(buffer[0]);
1223 if (GetComputerNameW(buffer, &len)) {
1224 if (lstrcmpW(buffer, server) == 0) {
1225 /* The requested Servername is our computername */
1226 HeapFree(GetProcessHeap(), 0, server);
1227 return NULL;
1230 return server;
1233 /******************************************************************
1234 * get_basename_from_name (internal)
1236 * skip over the serverpart from the full name
1239 static LPCWSTR get_basename_from_name(LPCWSTR name)
1241 if (name == NULL) return NULL;
1242 if ((name[0] == '\\') && (name[1] == '\\')) {
1243 /* skip over the servername and search for the following '\' */
1244 name = strchrW(&name[2], '\\');
1245 if ((name) && (name[1])) {
1246 /* found a separator ('\') followed by a name:
1247 skip over the separator and return the rest */
1248 name++;
1250 else
1252 /* no basename present (we found only a servername) */
1253 return NULL;
1256 return name;
1259 /******************************************************************
1260 * get_opened_printer_entry
1261 * Get the first place empty in the opened printer table
1263 * ToDo:
1264 * - pDefault is ignored
1266 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1268 UINT_PTR handle = nb_printer_handles, i;
1269 jobqueue_t *queue = NULL;
1270 opened_printer_t *printer = NULL;
1271 LPWSTR servername;
1272 LPCWSTR printername;
1273 HKEY hkeyPrinters;
1274 HKEY hkeyPrinter;
1275 DWORD len;
1277 servername = get_servername_from_name(name);
1278 if (servername) {
1279 FIXME("server %s not supported\n", debugstr_w(servername));
1280 HeapFree(GetProcessHeap(), 0, servername);
1281 SetLastError(ERROR_INVALID_PRINTER_NAME);
1282 return NULL;
1285 printername = get_basename_from_name(name);
1286 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1288 /* an empty printername is invalid */
1289 if (printername && (!printername[0])) {
1290 SetLastError(ERROR_INVALID_PARAMETER);
1291 return NULL;
1294 EnterCriticalSection(&printer_handles_cs);
1296 for (i = 0; i < nb_printer_handles; i++)
1298 if (!printer_handles[i])
1300 if(handle == nb_printer_handles)
1301 handle = i;
1303 else
1305 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1306 queue = printer_handles[i]->queue;
1310 if (handle >= nb_printer_handles)
1312 opened_printer_t **new_array;
1313 if (printer_handles)
1314 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1315 (nb_printer_handles + 16) * sizeof(*new_array) );
1316 else
1317 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1318 (nb_printer_handles + 16) * sizeof(*new_array) );
1320 if (!new_array)
1322 handle = 0;
1323 goto end;
1325 printer_handles = new_array;
1326 nb_printer_handles += 16;
1329 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1331 handle = 0;
1332 goto end;
1336 /* clone the base name. This is NULL for the printserver */
1337 printer->printername = strdupW(printername);
1339 /* clone the full name */
1340 printer->name = strdupW(name);
1341 if (name && (!printer->name)) {
1342 handle = 0;
1343 goto end;
1346 if (printername) {
1347 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1348 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1349 /* OpenPrinter(",XcvMonitor " detected */
1350 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1351 printer->pm = monitor_load(&printername[len], NULL);
1352 if (printer->pm == NULL) {
1353 SetLastError(ERROR_UNKNOWN_PORT);
1354 handle = 0;
1355 goto end;
1358 else
1360 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1361 if (strncmpW( printername, XcvPortW, len) == 0) {
1362 /* OpenPrinter(",XcvPort " detected */
1363 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1364 printer->pm = monitor_load_by_port(&printername[len]);
1365 if (printer->pm == NULL) {
1366 SetLastError(ERROR_UNKNOWN_PORT);
1367 handle = 0;
1368 goto end;
1373 if (printer->pm) {
1374 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1375 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1376 pDefault ? pDefault->DesiredAccess : 0,
1377 &printer->hXcv);
1379 if (printer->hXcv == NULL) {
1380 SetLastError(ERROR_INVALID_PARAMETER);
1381 handle = 0;
1382 goto end;
1385 else
1387 /* Does the Printer exist? */
1388 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1389 ERR("Can't create Printers key\n");
1390 handle = 0;
1391 goto end;
1393 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1394 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1395 RegCloseKey(hkeyPrinters);
1396 SetLastError(ERROR_INVALID_PRINTER_NAME);
1397 handle = 0;
1398 goto end;
1400 RegCloseKey(hkeyPrinter);
1401 RegCloseKey(hkeyPrinters);
1404 else
1406 TRACE("using the local printserver\n");
1409 if(queue)
1410 printer->queue = queue;
1411 else
1413 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1414 if (!printer->queue) {
1415 handle = 0;
1416 goto end;
1418 list_init(&printer->queue->jobs);
1419 printer->queue->ref = 0;
1421 InterlockedIncrement(&printer->queue->ref);
1423 printer_handles[handle] = printer;
1424 handle++;
1425 end:
1426 LeaveCriticalSection(&printer_handles_cs);
1427 if (!handle && printer) {
1428 /* Something failed: Free all resources */
1429 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1430 monitor_unload(printer->pm);
1431 HeapFree(GetProcessHeap(), 0, printer->printername);
1432 HeapFree(GetProcessHeap(), 0, printer->name);
1433 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1434 HeapFree(GetProcessHeap(), 0, printer);
1437 return (HANDLE)handle;
1440 /******************************************************************
1441 * get_opened_printer
1442 * Get the pointer to the opened printer referred by the handle
1444 static opened_printer_t *get_opened_printer(HANDLE hprn)
1446 UINT_PTR idx = (UINT_PTR)hprn;
1447 opened_printer_t *ret = NULL;
1449 EnterCriticalSection(&printer_handles_cs);
1451 if ((idx > 0) && (idx <= nb_printer_handles)) {
1452 ret = printer_handles[idx - 1];
1454 LeaveCriticalSection(&printer_handles_cs);
1455 return ret;
1458 /******************************************************************
1459 * get_opened_printer_name
1460 * Get the pointer to the opened printer name referred by the handle
1462 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1464 opened_printer_t *printer = get_opened_printer(hprn);
1465 if(!printer) return NULL;
1466 return printer->name;
1469 /******************************************************************
1470 * WINSPOOL_GetOpenedPrinterRegKey
1473 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1475 LPCWSTR name = get_opened_printer_name(hPrinter);
1476 DWORD ret;
1477 HKEY hkeyPrinters;
1479 if(!name) return ERROR_INVALID_HANDLE;
1481 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1482 ERROR_SUCCESS)
1483 return ret;
1485 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1487 ERR("Can't find opened printer %s in registry\n",
1488 debugstr_w(name));
1489 RegCloseKey(hkeyPrinters);
1490 return ERROR_INVALID_PRINTER_NAME; /* ? */
1492 RegCloseKey(hkeyPrinters);
1493 return ERROR_SUCCESS;
1496 void WINSPOOL_LoadSystemPrinters(void)
1498 HKEY hkey, hkeyPrinters;
1499 HANDLE hprn;
1500 DWORD needed, num, i;
1501 WCHAR PrinterName[256];
1502 BOOL done = FALSE;
1504 /* This ensures that all printer entries have a valid Name value. If causes
1505 problems later if they don't. If one is found to be missed we create one
1506 and set it equal to the name of the key */
1507 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1508 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1509 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1510 for(i = 0; i < num; i++) {
1511 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1512 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1513 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1514 set_reg_szW(hkey, NameW, PrinterName);
1516 RegCloseKey(hkey);
1521 RegCloseKey(hkeyPrinters);
1524 /* We want to avoid calling AddPrinter on printers as much as
1525 possible, because on cups printers this will (eventually) lead
1526 to a call to cupsGetPPD which takes forever, even with non-cups
1527 printers AddPrinter takes a while. So we'll tag all printers that
1528 were automatically added last time around, if they still exist
1529 we'll leave them be otherwise we'll delete them. */
1530 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1531 if(needed) {
1532 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1533 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1534 for(i = 0; i < num; i++) {
1535 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1536 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1537 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1538 DWORD dw = 1;
1539 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1540 RegCloseKey(hkey);
1542 ClosePrinter(hprn);
1547 HeapFree(GetProcessHeap(), 0, pi);
1551 #ifdef SONAME_LIBCUPS
1552 done = CUPS_LoadPrinters();
1553 #endif
1555 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1556 PRINTCAP_LoadPrinters();
1558 /* Now enumerate the list again and delete any printers that are still tagged */
1559 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1560 if(needed) {
1561 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1562 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1563 for(i = 0; i < num; i++) {
1564 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1565 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1566 BOOL delete_driver = FALSE;
1567 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1568 DWORD dw, type, size = sizeof(dw);
1569 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1570 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1571 DeletePrinter(hprn);
1572 delete_driver = TRUE;
1574 RegCloseKey(hkey);
1576 ClosePrinter(hprn);
1577 if(delete_driver)
1578 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1583 HeapFree(GetProcessHeap(), 0, pi);
1586 return;
1590 /******************************************************************
1591 * get_job
1593 * Get the pointer to the specified job.
1594 * Should hold the printer_handles_cs before calling.
1596 static job_t *get_job(HANDLE hprn, DWORD JobId)
1598 opened_printer_t *printer = get_opened_printer(hprn);
1599 job_t *job;
1601 if(!printer) return NULL;
1602 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1604 if(job->job_id == JobId)
1605 return job;
1607 return NULL;
1610 /***********************************************************
1611 * DEVMODEcpyAtoW
1613 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1615 BOOL Formname;
1616 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1617 DWORD size;
1619 Formname = (dmA->dmSize > off_formname);
1620 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1621 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1622 dmW->dmDeviceName, CCHDEVICENAME);
1623 if(!Formname) {
1624 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1625 dmA->dmSize - CCHDEVICENAME);
1626 } else {
1627 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1628 off_formname - CCHDEVICENAME);
1629 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1630 dmW->dmFormName, CCHFORMNAME);
1631 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1632 (off_formname + CCHFORMNAME));
1634 dmW->dmSize = size;
1635 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1636 dmA->dmDriverExtra);
1637 return dmW;
1640 /***********************************************************
1641 * DEVMODEdupWtoA
1642 * Creates an ansi copy of supplied devmode
1644 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1646 LPDEVMODEA dmA;
1647 DWORD size;
1649 if (!dmW) return NULL;
1650 size = dmW->dmSize - CCHDEVICENAME -
1651 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1653 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1654 if (!dmA) return NULL;
1656 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1657 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1659 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1660 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1661 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1663 else
1665 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1666 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1667 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1668 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1670 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1673 dmA->dmSize = size;
1674 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1675 return dmA;
1678 /******************************************************************
1679 * convert_printerinfo_W_to_A [internal]
1682 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1683 DWORD level, DWORD outlen, DWORD numentries)
1685 DWORD id = 0;
1686 LPSTR ptr;
1687 INT len;
1689 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1691 len = pi_sizeof[level] * numentries;
1692 ptr = (LPSTR) out + len;
1693 outlen -= len;
1695 /* copy the numbers of all PRINTER_INFO_* first */
1696 memcpy(out, pPrintersW, len);
1698 while (id < numentries) {
1699 switch (level) {
1700 case 1:
1702 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1703 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1705 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1706 if (piW->pDescription) {
1707 piA->pDescription = ptr;
1708 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1709 ptr, outlen, NULL, NULL);
1710 ptr += len;
1711 outlen -= len;
1713 if (piW->pName) {
1714 piA->pName = ptr;
1715 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1716 ptr, outlen, NULL, NULL);
1717 ptr += len;
1718 outlen -= len;
1720 if (piW->pComment) {
1721 piA->pComment = ptr;
1722 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1723 ptr, outlen, NULL, NULL);
1724 ptr += len;
1725 outlen -= len;
1727 break;
1730 case 2:
1732 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1733 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1734 LPDEVMODEA dmA;
1736 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1737 if (piW->pServerName) {
1738 piA->pServerName = ptr;
1739 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1740 ptr, outlen, NULL, NULL);
1741 ptr += len;
1742 outlen -= len;
1744 if (piW->pPrinterName) {
1745 piA->pPrinterName = ptr;
1746 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1747 ptr, outlen, NULL, NULL);
1748 ptr += len;
1749 outlen -= len;
1751 if (piW->pShareName) {
1752 piA->pShareName = ptr;
1753 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1754 ptr, outlen, NULL, NULL);
1755 ptr += len;
1756 outlen -= len;
1758 if (piW->pPortName) {
1759 piA->pPortName = ptr;
1760 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1761 ptr, outlen, NULL, NULL);
1762 ptr += len;
1763 outlen -= len;
1765 if (piW->pDriverName) {
1766 piA->pDriverName = ptr;
1767 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1768 ptr, outlen, NULL, NULL);
1769 ptr += len;
1770 outlen -= len;
1772 if (piW->pComment) {
1773 piA->pComment = ptr;
1774 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1775 ptr, outlen, NULL, NULL);
1776 ptr += len;
1777 outlen -= len;
1779 if (piW->pLocation) {
1780 piA->pLocation = ptr;
1781 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1782 ptr, outlen, NULL, NULL);
1783 ptr += len;
1784 outlen -= len;
1787 dmA = DEVMODEdupWtoA(piW->pDevMode);
1788 if (dmA) {
1789 /* align DEVMODEA to a DWORD boundary */
1790 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1791 ptr += len;
1792 outlen -= len;
1794 piA->pDevMode = (LPDEVMODEA) ptr;
1795 len = dmA->dmSize + dmA->dmDriverExtra;
1796 memcpy(ptr, dmA, len);
1797 HeapFree(GetProcessHeap(), 0, dmA);
1799 ptr += len;
1800 outlen -= len;
1803 if (piW->pSepFile) {
1804 piA->pSepFile = ptr;
1805 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1806 ptr, outlen, NULL, NULL);
1807 ptr += len;
1808 outlen -= len;
1810 if (piW->pPrintProcessor) {
1811 piA->pPrintProcessor = ptr;
1812 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1813 ptr, outlen, NULL, NULL);
1814 ptr += len;
1815 outlen -= len;
1817 if (piW->pDatatype) {
1818 piA->pDatatype = ptr;
1819 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1820 ptr, outlen, NULL, NULL);
1821 ptr += len;
1822 outlen -= len;
1824 if (piW->pParameters) {
1825 piA->pParameters = ptr;
1826 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1827 ptr, outlen, NULL, NULL);
1828 ptr += len;
1829 outlen -= len;
1831 if (piW->pSecurityDescriptor) {
1832 piA->pSecurityDescriptor = NULL;
1833 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1835 break;
1838 case 4:
1840 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1841 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1843 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1845 if (piW->pPrinterName) {
1846 piA->pPrinterName = ptr;
1847 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1848 ptr, outlen, NULL, NULL);
1849 ptr += len;
1850 outlen -= len;
1852 if (piW->pServerName) {
1853 piA->pServerName = ptr;
1854 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1855 ptr, outlen, NULL, NULL);
1856 ptr += len;
1857 outlen -= len;
1859 break;
1862 case 5:
1864 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1865 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1867 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1869 if (piW->pPrinterName) {
1870 piA->pPrinterName = ptr;
1871 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1872 ptr, outlen, NULL, NULL);
1873 ptr += len;
1874 outlen -= len;
1876 if (piW->pPortName) {
1877 piA->pPortName = ptr;
1878 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1879 ptr, outlen, NULL, NULL);
1880 ptr += len;
1881 outlen -= len;
1883 break;
1886 default:
1887 FIXME("for level %u\n", level);
1889 pPrintersW += pi_sizeof[level];
1890 out += pi_sizeof[level];
1891 id++;
1895 /***********************************************************
1896 * PRINTER_INFO_2AtoW
1897 * Creates a unicode copy of PRINTER_INFO_2A on heap
1899 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1901 LPPRINTER_INFO_2W piW;
1902 UNICODE_STRING usBuffer;
1904 if(!piA) return NULL;
1905 piW = HeapAlloc(heap, 0, sizeof(*piW));
1906 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1908 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1909 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1910 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1911 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1912 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1913 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1914 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1915 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1916 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1917 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1918 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1919 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1920 return piW;
1923 /***********************************************************
1924 * FREE_PRINTER_INFO_2W
1925 * Free PRINTER_INFO_2W and all strings
1927 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1929 if(!piW) return;
1931 HeapFree(heap,0,piW->pServerName);
1932 HeapFree(heap,0,piW->pPrinterName);
1933 HeapFree(heap,0,piW->pShareName);
1934 HeapFree(heap,0,piW->pPortName);
1935 HeapFree(heap,0,piW->pDriverName);
1936 HeapFree(heap,0,piW->pComment);
1937 HeapFree(heap,0,piW->pLocation);
1938 HeapFree(heap,0,piW->pDevMode);
1939 HeapFree(heap,0,piW->pSepFile);
1940 HeapFree(heap,0,piW->pPrintProcessor);
1941 HeapFree(heap,0,piW->pDatatype);
1942 HeapFree(heap,0,piW->pParameters);
1943 HeapFree(heap,0,piW);
1944 return;
1947 /******************************************************************
1948 * DeviceCapabilities [WINSPOOL.@]
1949 * DeviceCapabilitiesA [WINSPOOL.@]
1952 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1953 LPSTR pOutput, LPDEVMODEA lpdm)
1955 INT ret;
1957 if (!GDI_CallDeviceCapabilities16)
1959 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1960 (LPCSTR)104 );
1961 if (!GDI_CallDeviceCapabilities16) return -1;
1963 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1965 /* If DC_PAPERSIZE map POINT16s to POINTs */
1966 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1967 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1968 POINT *pt = (POINT *)pOutput;
1969 INT i;
1970 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1971 for(i = 0; i < ret; i++, pt++)
1973 pt->x = tmp[i].x;
1974 pt->y = tmp[i].y;
1976 HeapFree( GetProcessHeap(), 0, tmp );
1978 return ret;
1982 /*****************************************************************************
1983 * DeviceCapabilitiesW [WINSPOOL.@]
1985 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1988 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1989 WORD fwCapability, LPWSTR pOutput,
1990 const DEVMODEW *pDevMode)
1992 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1993 LPSTR pDeviceA = strdupWtoA(pDevice);
1994 LPSTR pPortA = strdupWtoA(pPort);
1995 INT ret;
1997 if(pOutput && (fwCapability == DC_BINNAMES ||
1998 fwCapability == DC_FILEDEPENDENCIES ||
1999 fwCapability == DC_PAPERNAMES)) {
2000 /* These need A -> W translation */
2001 INT size = 0, i;
2002 LPSTR pOutputA;
2003 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2004 dmA);
2005 if(ret == -1)
2006 return ret;
2007 switch(fwCapability) {
2008 case DC_BINNAMES:
2009 size = 24;
2010 break;
2011 case DC_PAPERNAMES:
2012 case DC_FILEDEPENDENCIES:
2013 size = 64;
2014 break;
2016 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2017 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2018 dmA);
2019 for(i = 0; i < ret; i++)
2020 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2021 pOutput + (i * size), size);
2022 HeapFree(GetProcessHeap(), 0, pOutputA);
2023 } else {
2024 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2025 (LPSTR)pOutput, dmA);
2027 HeapFree(GetProcessHeap(),0,pPortA);
2028 HeapFree(GetProcessHeap(),0,pDeviceA);
2029 HeapFree(GetProcessHeap(),0,dmA);
2030 return ret;
2033 /******************************************************************
2034 * DocumentPropertiesA [WINSPOOL.@]
2036 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2038 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2039 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2040 LPDEVMODEA pDevModeInput,DWORD fMode )
2042 LPSTR lpName = pDeviceName;
2043 static CHAR port[] = "LPT1:";
2044 LONG ret;
2046 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2047 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2050 if(!pDeviceName) {
2051 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2052 if(!lpNameW) {
2053 ERR("no name from hPrinter?\n");
2054 SetLastError(ERROR_INVALID_HANDLE);
2055 return -1;
2057 lpName = strdupWtoA(lpNameW);
2060 if (!GDI_CallExtDeviceMode16)
2062 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2063 (LPCSTR)102 );
2064 if (!GDI_CallExtDeviceMode16) {
2065 ERR("No CallExtDeviceMode16?\n");
2066 return -1;
2069 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2070 pDevModeInput, NULL, fMode);
2072 if(!pDeviceName)
2073 HeapFree(GetProcessHeap(),0,lpName);
2074 return ret;
2078 /*****************************************************************************
2079 * DocumentPropertiesW (WINSPOOL.@)
2081 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2083 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2084 LPWSTR pDeviceName,
2085 LPDEVMODEW pDevModeOutput,
2086 LPDEVMODEW pDevModeInput, DWORD fMode)
2089 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2090 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2091 LPDEVMODEA pDevModeOutputA = NULL;
2092 LONG ret;
2094 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2095 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2096 fMode);
2097 if(pDevModeOutput) {
2098 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2099 if(ret < 0) return ret;
2100 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2102 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2103 pDevModeInputA, fMode);
2104 if(pDevModeOutput) {
2105 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2106 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2108 if(fMode == 0 && ret > 0)
2109 ret += (CCHDEVICENAME + CCHFORMNAME);
2110 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2111 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2112 return ret;
2115 /******************************************************************
2116 * OpenPrinterA [WINSPOOL.@]
2118 * See OpenPrinterW.
2121 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2122 LPPRINTER_DEFAULTSA pDefault)
2124 UNICODE_STRING lpPrinterNameW;
2125 UNICODE_STRING usBuffer;
2126 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2127 PWSTR pwstrPrinterNameW;
2128 BOOL ret;
2130 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2132 if(pDefault) {
2133 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2134 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2135 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2136 pDefaultW = &DefaultW;
2138 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2139 if(pDefault) {
2140 RtlFreeUnicodeString(&usBuffer);
2141 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2143 RtlFreeUnicodeString(&lpPrinterNameW);
2144 return ret;
2147 /******************************************************************
2148 * OpenPrinterW [WINSPOOL.@]
2150 * Open a Printer / Printserver or a Printer-Object
2152 * PARAMS
2153 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2154 * phPrinter [O] The resulting Handle is stored here
2155 * pDefault [I] PTR to Default Printer Settings or NULL
2157 * RETURNS
2158 * Success: TRUE
2159 * Failure: FALSE
2161 * NOTES
2162 * lpPrinterName is one of:
2163 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2164 *| Printer: "PrinterName"
2165 *| Printer-Object: "PrinterName,Job xxx"
2166 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2167 *| XcvPort: "Servername,XcvPort PortName"
2169 * BUGS
2170 *| Printer-Object not supported
2171 *| pDefaults is ignored
2174 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2177 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2178 if (pDefault) {
2179 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2180 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2183 if(!phPrinter) {
2184 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2185 SetLastError(ERROR_INVALID_PARAMETER);
2186 return FALSE;
2189 /* Get the unique handle of the printer or Printserver */
2190 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2191 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2192 return (*phPrinter != 0);
2195 /******************************************************************
2196 * AddMonitorA [WINSPOOL.@]
2198 * See AddMonitorW.
2201 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2203 LPWSTR nameW = NULL;
2204 INT len;
2205 BOOL res;
2206 LPMONITOR_INFO_2A mi2a;
2207 MONITOR_INFO_2W mi2w;
2209 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2210 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2211 debugstr_a(mi2a ? mi2a->pName : NULL),
2212 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2213 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2215 if (Level != 2) {
2216 SetLastError(ERROR_INVALID_LEVEL);
2217 return FALSE;
2220 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2221 if (mi2a == NULL) {
2222 return FALSE;
2225 if (pName) {
2226 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2227 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2228 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2231 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2232 if (mi2a->pName) {
2233 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2234 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2235 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2237 if (mi2a->pEnvironment) {
2238 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2239 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2240 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2242 if (mi2a->pDLLName) {
2243 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2244 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2245 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2248 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2250 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2251 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2252 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2254 HeapFree(GetProcessHeap(), 0, nameW);
2255 return (res);
2258 /******************************************************************************
2259 * AddMonitorW [WINSPOOL.@]
2261 * Install a Printmonitor
2263 * PARAMS
2264 * pName [I] Servername or NULL (local Computer)
2265 * Level [I] Structure-Level (Must be 2)
2266 * pMonitors [I] PTR to MONITOR_INFO_2
2268 * RETURNS
2269 * Success: TRUE
2270 * Failure: FALSE
2272 * NOTES
2273 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2276 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2278 LPMONITOR_INFO_2W mi2w;
2280 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2281 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2282 debugstr_w(mi2w ? mi2w->pName : NULL),
2283 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2284 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2286 if ((backend == NULL) && !load_backend()) return FALSE;
2288 if (Level != 2) {
2289 SetLastError(ERROR_INVALID_LEVEL);
2290 return FALSE;
2293 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2294 if (mi2w == NULL) {
2295 return FALSE;
2298 return backend->fpAddMonitor(pName, Level, pMonitors);
2301 /******************************************************************
2302 * DeletePrinterDriverA [WINSPOOL.@]
2305 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2307 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2310 /******************************************************************
2311 * DeletePrinterDriverW [WINSPOOL.@]
2314 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2316 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2319 /******************************************************************
2320 * DeleteMonitorA [WINSPOOL.@]
2322 * See DeleteMonitorW.
2325 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2327 LPWSTR nameW = NULL;
2328 LPWSTR EnvironmentW = NULL;
2329 LPWSTR MonitorNameW = NULL;
2330 BOOL res;
2331 INT len;
2333 if (pName) {
2334 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2335 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2336 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2339 if (pEnvironment) {
2340 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2341 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2342 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2344 if (pMonitorName) {
2345 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2346 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2347 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2350 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2352 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2353 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2354 HeapFree(GetProcessHeap(), 0, nameW);
2355 return (res);
2358 /******************************************************************
2359 * DeleteMonitorW [WINSPOOL.@]
2361 * Delete a specific Printmonitor from a Printing-Environment
2363 * PARAMS
2364 * pName [I] Servername or NULL (local Computer)
2365 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2366 * pMonitorName [I] Name of the Monitor, that should be deleted
2368 * RETURNS
2369 * Success: TRUE
2370 * Failure: FALSE
2372 * NOTES
2373 * pEnvironment is ignored in Windows for the local Computer.
2376 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2379 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2380 debugstr_w(pMonitorName));
2382 if ((backend == NULL) && !load_backend()) return FALSE;
2384 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2388 /******************************************************************
2389 * DeletePortA [WINSPOOL.@]
2391 * See DeletePortW.
2394 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2396 LPWSTR nameW = NULL;
2397 LPWSTR portW = NULL;
2398 INT len;
2399 DWORD res;
2401 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2403 /* convert servername to unicode */
2404 if (pName) {
2405 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2406 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2407 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2410 /* convert portname to unicode */
2411 if (pPortName) {
2412 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2413 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2414 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2417 res = DeletePortW(nameW, hWnd, portW);
2418 HeapFree(GetProcessHeap(), 0, nameW);
2419 HeapFree(GetProcessHeap(), 0, portW);
2420 return res;
2423 /******************************************************************
2424 * DeletePortW [WINSPOOL.@]
2426 * Delete a specific Port
2428 * PARAMS
2429 * pName [I] Servername or NULL (local Computer)
2430 * hWnd [I] Handle to parent Window for the Dialog-Box
2431 * pPortName [I] Name of the Port, that should be deleted
2433 * RETURNS
2434 * Success: TRUE
2435 * Failure: FALSE
2438 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2440 monitor_t * pm;
2441 monitor_t * pui;
2442 DWORD res;
2444 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2446 if (pName && pName[0]) {
2447 SetLastError(ERROR_INVALID_PARAMETER);
2448 return FALSE;
2451 if (!pPortName) {
2452 SetLastError(RPC_X_NULL_REF_POINTER);
2453 return FALSE;
2456 /* an empty Portname is Invalid */
2457 if (!pPortName[0]) {
2458 SetLastError(ERROR_NOT_SUPPORTED);
2459 return FALSE;
2462 pm = monitor_load_by_port(pPortName);
2463 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2464 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2465 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2466 TRACE("got %d with %u\n", res, GetLastError());
2468 else
2470 pui = monitor_loadui(pm);
2471 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2472 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2473 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2474 TRACE("got %d with %u\n", res, GetLastError());
2476 else
2478 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2479 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2481 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2482 SetLastError(ERROR_NOT_SUPPORTED);
2483 res = FALSE;
2485 monitor_unload(pui);
2487 monitor_unload(pm);
2489 TRACE("returning %d with %u\n", res, GetLastError());
2490 return res;
2493 /******************************************************************************
2494 * SetPrinterW [WINSPOOL.@]
2496 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2498 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2500 return FALSE;
2503 /******************************************************************************
2504 * WritePrinter [WINSPOOL.@]
2506 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2508 opened_printer_t *printer;
2509 BOOL ret = FALSE;
2511 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2513 EnterCriticalSection(&printer_handles_cs);
2514 printer = get_opened_printer(hPrinter);
2515 if(!printer)
2517 SetLastError(ERROR_INVALID_HANDLE);
2518 goto end;
2521 if(!printer->doc)
2523 SetLastError(ERROR_SPL_NO_STARTDOC);
2524 goto end;
2527 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2528 end:
2529 LeaveCriticalSection(&printer_handles_cs);
2530 return ret;
2533 /*****************************************************************************
2534 * AddFormA [WINSPOOL.@]
2536 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2538 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2539 return 1;
2542 /*****************************************************************************
2543 * AddFormW [WINSPOOL.@]
2545 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2547 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2548 return 1;
2551 /*****************************************************************************
2552 * AddJobA [WINSPOOL.@]
2554 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2556 BOOL ret;
2557 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2558 DWORD needed;
2560 if(Level != 1) {
2561 SetLastError(ERROR_INVALID_LEVEL);
2562 return FALSE;
2565 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2567 if(ret) {
2568 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2569 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2570 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2571 if(*pcbNeeded > cbBuf) {
2572 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2573 ret = FALSE;
2574 } else {
2575 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2576 addjobA->JobId = addjobW->JobId;
2577 addjobA->Path = (char *)(addjobA + 1);
2578 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2581 return ret;
2584 /*****************************************************************************
2585 * AddJobW [WINSPOOL.@]
2587 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2589 opened_printer_t *printer;
2590 job_t *job;
2591 BOOL ret = FALSE;
2592 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2593 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2594 WCHAR path[MAX_PATH], filename[MAX_PATH];
2595 DWORD len;
2596 ADDJOB_INFO_1W *addjob;
2598 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2600 EnterCriticalSection(&printer_handles_cs);
2602 printer = get_opened_printer(hPrinter);
2604 if(!printer) {
2605 SetLastError(ERROR_INVALID_HANDLE);
2606 goto end;
2609 if(Level != 1) {
2610 SetLastError(ERROR_INVALID_LEVEL);
2611 goto end;
2614 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2615 if(!job)
2616 goto end;
2618 job->job_id = InterlockedIncrement(&next_job_id);
2620 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2621 if(path[len - 1] != '\\')
2622 path[len++] = '\\';
2623 memcpy(path + len, spool_path, sizeof(spool_path));
2624 sprintfW(filename, fmtW, path, job->job_id);
2626 len = strlenW(filename);
2627 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2628 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2629 job->document_title = strdupW(default_doc_title);
2630 list_add_tail(&printer->queue->jobs, &job->entry);
2632 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2633 if(*pcbNeeded <= cbBuf) {
2634 addjob = (ADDJOB_INFO_1W*)pData;
2635 addjob->JobId = job->job_id;
2636 addjob->Path = (WCHAR *)(addjob + 1);
2637 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2638 ret = TRUE;
2639 } else
2640 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2642 end:
2643 LeaveCriticalSection(&printer_handles_cs);
2644 return ret;
2647 /*****************************************************************************
2648 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2650 * Return the PATH for the Print-Processors
2652 * See GetPrintProcessorDirectoryW.
2656 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2657 DWORD level, LPBYTE Info,
2658 DWORD cbBuf, LPDWORD pcbNeeded)
2660 LPWSTR serverW = NULL;
2661 LPWSTR envW = NULL;
2662 BOOL ret;
2663 INT len;
2665 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2666 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2669 if (server) {
2670 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2671 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2672 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2675 if (env) {
2676 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2677 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2678 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2681 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2682 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2684 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2685 cbBuf, pcbNeeded);
2687 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2688 cbBuf, NULL, NULL) > 0;
2691 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2692 HeapFree(GetProcessHeap(), 0, envW);
2693 HeapFree(GetProcessHeap(), 0, serverW);
2694 return ret;
2697 /*****************************************************************************
2698 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2700 * Return the PATH for the Print-Processors
2702 * PARAMS
2703 * server [I] Servername (NT only) or NULL (local Computer)
2704 * env [I] Printing-Environment (see below) or NULL (Default)
2705 * level [I] Structure-Level (must be 1)
2706 * Info [O] PTR to Buffer that receives the Result
2707 * cbBuf [I] Size of Buffer at "Info"
2708 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2709 * required for the Buffer at "Info"
2711 * RETURNS
2712 * Success: TRUE and in pcbNeeded the Bytes used in Info
2713 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2714 * if cbBuf is too small
2716 * Native Values returned in Info on Success:
2717 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2718 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2719 *| win9x(Windows 4.0): "%winsysdir%"
2721 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2723 * BUGS
2724 * Only NULL or "" is supported for server
2727 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2728 DWORD level, LPBYTE Info,
2729 DWORD cbBuf, LPDWORD pcbNeeded)
2731 DWORD needed;
2732 const printenv_t * env_t;
2734 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2735 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2737 if(server != NULL && server[0]) {
2738 FIXME("server not supported: %s\n", debugstr_w(server));
2739 SetLastError(ERROR_INVALID_PARAMETER);
2740 return FALSE;
2743 env_t = validate_envW(env);
2744 if(!env_t) return FALSE; /* environment invalid or unsupported */
2746 if(level != 1) {
2747 WARN("(Level: %d) is ignored in win9x\n", level);
2748 SetLastError(ERROR_INVALID_LEVEL);
2749 return FALSE;
2752 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2753 needed = GetSystemDirectoryW(NULL, 0);
2754 /* add the Size for the Subdirectories */
2755 needed += lstrlenW(spoolprtprocsW);
2756 needed += lstrlenW(env_t->subdir);
2757 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2759 if(pcbNeeded) *pcbNeeded = needed;
2760 TRACE ("required: 0x%x/%d\n", needed, needed);
2761 if (needed > cbBuf) {
2762 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2763 return FALSE;
2765 if(pcbNeeded == NULL) {
2766 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2767 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2768 SetLastError(RPC_X_NULL_REF_POINTER);
2769 return FALSE;
2771 if(Info == NULL) {
2772 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2773 SetLastError(RPC_X_NULL_REF_POINTER);
2774 return FALSE;
2777 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2778 /* add the Subdirectories */
2779 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2780 lstrcatW((LPWSTR) Info, env_t->subdir);
2781 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2782 return TRUE;
2785 /*****************************************************************************
2786 * WINSPOOL_OpenDriverReg [internal]
2788 * opens the registry for the printer drivers depending on the given input
2789 * variable pEnvironment
2791 * RETURNS:
2792 * the opened hkey on success
2793 * NULL on error
2795 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2797 HKEY retval = NULL;
2798 LPWSTR buffer;
2799 const printenv_t * env;
2801 TRACE("(%s, %d)\n",
2802 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2804 if (!pEnvironment || unicode) {
2805 /* pEnvironment was NULL or a Unicode-String: use it direct */
2806 env = validate_envW(pEnvironment);
2808 else
2810 /* pEnvironment was an ANSI-String: convert to unicode first */
2811 LPWSTR buffer;
2812 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2813 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2814 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2815 env = validate_envW(buffer);
2816 HeapFree(GetProcessHeap(), 0, buffer);
2818 if (!env) return NULL;
2820 buffer = HeapAlloc( GetProcessHeap(), 0,
2821 (strlenW(DriversW) + strlenW(env->envname) +
2822 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2823 if(buffer) {
2824 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2825 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2826 HeapFree(GetProcessHeap(), 0, buffer);
2828 return retval;
2831 /*****************************************************************************
2832 * AddPrinterW [WINSPOOL.@]
2834 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2836 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2837 LPDEVMODEA dmA;
2838 LPDEVMODEW dmW;
2839 HANDLE retval;
2840 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2841 LONG size;
2842 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2843 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2844 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2845 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2846 statusW[] = {'S','t','a','t','u','s',0},
2847 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2849 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2851 if(pName != NULL) {
2852 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2853 SetLastError(ERROR_INVALID_PARAMETER);
2854 return 0;
2856 if(Level != 2) {
2857 ERR("Level = %d, unsupported!\n", Level);
2858 SetLastError(ERROR_INVALID_LEVEL);
2859 return 0;
2861 if(!pPrinter) {
2862 SetLastError(ERROR_INVALID_PARAMETER);
2863 return 0;
2865 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2866 ERROR_SUCCESS) {
2867 ERR("Can't create Printers key\n");
2868 return 0;
2870 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2871 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2872 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2873 RegCloseKey(hkeyPrinter);
2874 RegCloseKey(hkeyPrinters);
2875 return 0;
2877 RegCloseKey(hkeyPrinter);
2879 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2880 if(!hkeyDrivers) {
2881 ERR("Can't create Drivers key\n");
2882 RegCloseKey(hkeyPrinters);
2883 return 0;
2885 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2886 ERROR_SUCCESS) {
2887 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2888 RegCloseKey(hkeyPrinters);
2889 RegCloseKey(hkeyDrivers);
2890 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2891 return 0;
2893 RegCloseKey(hkeyDriver);
2894 RegCloseKey(hkeyDrivers);
2896 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2897 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2898 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2899 RegCloseKey(hkeyPrinters);
2900 return 0;
2903 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2904 ERROR_SUCCESS) {
2905 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2906 SetLastError(ERROR_INVALID_PRINTER_NAME);
2907 RegCloseKey(hkeyPrinters);
2908 return 0;
2910 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2911 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2912 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2914 /* See if we can load the driver. We may need the devmode structure anyway
2916 * FIXME:
2917 * Note that DocumentPropertiesW will briefly try to open the printer we
2918 * just create to find a DEVMODEA struct (it will use the WINEPS default
2919 * one in case it is not there, so we are ok).
2921 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2923 if(size < 0) {
2924 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2925 size = sizeof(DEVMODEW);
2927 if(pi->pDevMode)
2928 dmW = pi->pDevMode;
2929 else
2931 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2932 dmW->dmSize = size;
2933 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2935 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2936 HeapFree(GetProcessHeap(),0,dmW);
2937 dmW=NULL;
2939 else
2941 /* set devmode to printer name */
2942 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2946 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2947 and we support these drivers. NT writes DEVMODEW so somehow
2948 we'll need to distinguish between these when we support NT
2949 drivers */
2950 if (dmW)
2952 dmA = DEVMODEdupWtoA(dmW);
2953 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2954 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2955 HeapFree(GetProcessHeap(), 0, dmA);
2956 if(!pi->pDevMode)
2957 HeapFree(GetProcessHeap(), 0, dmW);
2959 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2960 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2961 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2962 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2964 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2965 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2966 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2967 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2968 (LPBYTE)&pi->Priority, sizeof(DWORD));
2969 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2970 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2971 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2972 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2973 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2974 (LPBYTE)&pi->Status, sizeof(DWORD));
2975 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2976 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2978 RegCloseKey(hkeyPrinter);
2979 RegCloseKey(hkeyPrinters);
2980 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2981 ERR("OpenPrinter failing\n");
2982 return 0;
2984 return retval;
2987 /*****************************************************************************
2988 * AddPrinterA [WINSPOOL.@]
2990 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2992 UNICODE_STRING pNameW;
2993 PWSTR pwstrNameW;
2994 PRINTER_INFO_2W *piW;
2995 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2996 HANDLE ret;
2998 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2999 if(Level != 2) {
3000 ERR("Level = %d, unsupported!\n", Level);
3001 SetLastError(ERROR_INVALID_LEVEL);
3002 return 0;
3004 pwstrNameW = asciitounicode(&pNameW,pName);
3005 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3007 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3009 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3010 RtlFreeUnicodeString(&pNameW);
3011 return ret;
3015 /*****************************************************************************
3016 * ClosePrinter [WINSPOOL.@]
3018 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3020 UINT_PTR i = (UINT_PTR)hPrinter;
3021 opened_printer_t *printer = NULL;
3022 BOOL ret = FALSE;
3024 TRACE("(%p)\n", hPrinter);
3026 EnterCriticalSection(&printer_handles_cs);
3028 if ((i > 0) && (i <= nb_printer_handles))
3029 printer = printer_handles[i - 1];
3032 if(printer)
3034 struct list *cursor, *cursor2;
3036 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3037 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3038 printer->hXcv, debugstr_w(printer->name), printer->doc );
3040 if(printer->doc)
3041 EndDocPrinter(hPrinter);
3043 if(InterlockedDecrement(&printer->queue->ref) == 0)
3045 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3047 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3048 ScheduleJob(hPrinter, job->job_id);
3050 HeapFree(GetProcessHeap(), 0, printer->queue);
3052 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3053 monitor_unload(printer->pm);
3054 HeapFree(GetProcessHeap(), 0, printer->printername);
3055 HeapFree(GetProcessHeap(), 0, printer->name);
3056 HeapFree(GetProcessHeap(), 0, printer);
3057 printer_handles[i - 1] = NULL;
3058 ret = TRUE;
3060 LeaveCriticalSection(&printer_handles_cs);
3061 return ret;
3064 /*****************************************************************************
3065 * DeleteFormA [WINSPOOL.@]
3067 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3069 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3070 return 1;
3073 /*****************************************************************************
3074 * DeleteFormW [WINSPOOL.@]
3076 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3078 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3079 return 1;
3082 /*****************************************************************************
3083 * DeletePrinter [WINSPOOL.@]
3085 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3087 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3088 HKEY hkeyPrinters, hkey;
3090 if(!lpNameW) {
3091 SetLastError(ERROR_INVALID_HANDLE);
3092 return FALSE;
3094 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3095 RegDeleteTreeW(hkeyPrinters, lpNameW);
3096 RegCloseKey(hkeyPrinters);
3098 WriteProfileStringW(devicesW, lpNameW, NULL);
3099 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3101 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3102 RegDeleteValueW(hkey, lpNameW);
3103 RegCloseKey(hkey);
3106 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3107 RegDeleteValueW(hkey, lpNameW);
3108 RegCloseKey(hkey);
3110 return TRUE;
3113 /*****************************************************************************
3114 * SetPrinterA [WINSPOOL.@]
3116 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3117 DWORD Command)
3119 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3120 return FALSE;
3123 /*****************************************************************************
3124 * SetJobA [WINSPOOL.@]
3126 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3127 LPBYTE pJob, DWORD Command)
3129 BOOL ret;
3130 LPBYTE JobW;
3131 UNICODE_STRING usBuffer;
3133 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3135 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3136 are all ignored by SetJob, so we don't bother copying them */
3137 switch(Level)
3139 case 0:
3140 JobW = NULL;
3141 break;
3142 case 1:
3144 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3145 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3147 JobW = (LPBYTE)info1W;
3148 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3149 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3150 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3151 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3152 info1W->Status = info1A->Status;
3153 info1W->Priority = info1A->Priority;
3154 info1W->Position = info1A->Position;
3155 info1W->PagesPrinted = info1A->PagesPrinted;
3156 break;
3158 case 2:
3160 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3161 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3163 JobW = (LPBYTE)info2W;
3164 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3165 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3166 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3167 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3168 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3169 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3170 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3171 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3172 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3173 info2W->Status = info2A->Status;
3174 info2W->Priority = info2A->Priority;
3175 info2W->Position = info2A->Position;
3176 info2W->StartTime = info2A->StartTime;
3177 info2W->UntilTime = info2A->UntilTime;
3178 info2W->PagesPrinted = info2A->PagesPrinted;
3179 break;
3181 case 3:
3182 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3183 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3184 break;
3185 default:
3186 SetLastError(ERROR_INVALID_LEVEL);
3187 return FALSE;
3190 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3192 switch(Level)
3194 case 1:
3196 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3197 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3198 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3199 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3200 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3201 break;
3203 case 2:
3205 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3206 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3207 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3208 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3209 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3210 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3211 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3212 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3213 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3214 break;
3217 HeapFree(GetProcessHeap(), 0, JobW);
3219 return ret;
3222 /*****************************************************************************
3223 * SetJobW [WINSPOOL.@]
3225 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3226 LPBYTE pJob, DWORD Command)
3228 BOOL ret = FALSE;
3229 job_t *job;
3231 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3232 FIXME("Ignoring everything other than document title\n");
3234 EnterCriticalSection(&printer_handles_cs);
3235 job = get_job(hPrinter, JobId);
3236 if(!job)
3237 goto end;
3239 switch(Level)
3241 case 0:
3242 break;
3243 case 1:
3245 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3246 HeapFree(GetProcessHeap(), 0, job->document_title);
3247 job->document_title = strdupW(info1->pDocument);
3248 break;
3250 case 2:
3252 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3253 HeapFree(GetProcessHeap(), 0, job->document_title);
3254 job->document_title = strdupW(info2->pDocument);
3255 break;
3257 case 3:
3258 break;
3259 default:
3260 SetLastError(ERROR_INVALID_LEVEL);
3261 goto end;
3263 ret = TRUE;
3264 end:
3265 LeaveCriticalSection(&printer_handles_cs);
3266 return ret;
3269 /*****************************************************************************
3270 * EndDocPrinter [WINSPOOL.@]
3272 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3274 opened_printer_t *printer;
3275 BOOL ret = FALSE;
3276 TRACE("(%p)\n", hPrinter);
3278 EnterCriticalSection(&printer_handles_cs);
3280 printer = get_opened_printer(hPrinter);
3281 if(!printer)
3283 SetLastError(ERROR_INVALID_HANDLE);
3284 goto end;
3287 if(!printer->doc)
3289 SetLastError(ERROR_SPL_NO_STARTDOC);
3290 goto end;
3293 CloseHandle(printer->doc->hf);
3294 ScheduleJob(hPrinter, printer->doc->job_id);
3295 HeapFree(GetProcessHeap(), 0, printer->doc);
3296 printer->doc = NULL;
3297 ret = TRUE;
3298 end:
3299 LeaveCriticalSection(&printer_handles_cs);
3300 return ret;
3303 /*****************************************************************************
3304 * EndPagePrinter [WINSPOOL.@]
3306 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3308 FIXME("(%p): stub\n", hPrinter);
3309 return TRUE;
3312 /*****************************************************************************
3313 * StartDocPrinterA [WINSPOOL.@]
3315 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3317 UNICODE_STRING usBuffer;
3318 DOC_INFO_2W doc2W;
3319 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3320 DWORD ret;
3322 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3323 or one (DOC_INFO_3) extra DWORDs */
3325 switch(Level) {
3326 case 2:
3327 doc2W.JobId = doc2->JobId;
3328 /* fall through */
3329 case 3:
3330 doc2W.dwMode = doc2->dwMode;
3331 /* fall through */
3332 case 1:
3333 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3334 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3335 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3336 break;
3338 default:
3339 SetLastError(ERROR_INVALID_LEVEL);
3340 return FALSE;
3343 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3345 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3346 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3347 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3349 return ret;
3352 /*****************************************************************************
3353 * StartDocPrinterW [WINSPOOL.@]
3355 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3357 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3358 opened_printer_t *printer;
3359 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3360 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3361 JOB_INFO_1W job_info;
3362 DWORD needed, ret = 0;
3363 HANDLE hf;
3364 WCHAR *filename;
3366 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3367 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3368 debugstr_w(doc->pDatatype));
3370 if(Level < 1 || Level > 3)
3372 SetLastError(ERROR_INVALID_LEVEL);
3373 return 0;
3376 EnterCriticalSection(&printer_handles_cs);
3377 printer = get_opened_printer(hPrinter);
3378 if(!printer)
3380 SetLastError(ERROR_INVALID_HANDLE);
3381 goto end;
3384 if(printer->doc)
3386 SetLastError(ERROR_INVALID_PRINTER_STATE);
3387 goto end;
3390 /* Even if we're printing to a file we still add a print job, we'll
3391 just ignore the spool file name */
3393 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3395 ERR("AddJob failed gle %u\n", GetLastError());
3396 goto end;
3399 if(doc->pOutputFile)
3400 filename = doc->pOutputFile;
3401 else
3402 filename = addjob->Path;
3404 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3405 if(hf == INVALID_HANDLE_VALUE)
3406 goto end;
3408 memset(&job_info, 0, sizeof(job_info));
3409 job_info.pDocument = doc->pDocName;
3410 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3412 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3413 printer->doc->hf = hf;
3414 ret = printer->doc->job_id = addjob->JobId;
3415 end:
3416 LeaveCriticalSection(&printer_handles_cs);
3418 return ret;
3421 /*****************************************************************************
3422 * StartPagePrinter [WINSPOOL.@]
3424 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3426 FIXME("(%p): stub\n", hPrinter);
3427 return TRUE;
3430 /*****************************************************************************
3431 * GetFormA [WINSPOOL.@]
3433 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3434 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3436 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3437 Level,pForm,cbBuf,pcbNeeded);
3438 return FALSE;
3441 /*****************************************************************************
3442 * GetFormW [WINSPOOL.@]
3444 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3445 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3447 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3448 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3449 return FALSE;
3452 /*****************************************************************************
3453 * SetFormA [WINSPOOL.@]
3455 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3456 LPBYTE pForm)
3458 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3459 return FALSE;
3462 /*****************************************************************************
3463 * SetFormW [WINSPOOL.@]
3465 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3466 LPBYTE pForm)
3468 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3469 return FALSE;
3472 /*****************************************************************************
3473 * ReadPrinter [WINSPOOL.@]
3475 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3476 LPDWORD pNoBytesRead)
3478 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3479 return FALSE;
3482 /*****************************************************************************
3483 * ResetPrinterA [WINSPOOL.@]
3485 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3487 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3488 return FALSE;
3491 /*****************************************************************************
3492 * ResetPrinterW [WINSPOOL.@]
3494 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3496 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3497 return FALSE;
3500 /*****************************************************************************
3501 * WINSPOOL_GetDWORDFromReg
3503 * Return DWORD associated with ValueName from hkey.
3505 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3507 DWORD sz = sizeof(DWORD), type, value = 0;
3508 LONG ret;
3510 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3512 if(ret != ERROR_SUCCESS) {
3513 WARN("Got ret = %d on name %s\n", ret, ValueName);
3514 return 0;
3516 if(type != REG_DWORD) {
3517 ERR("Got type %d\n", type);
3518 return 0;
3520 return value;
3524 /*****************************************************************************
3525 * get_filename_from_reg [internal]
3527 * Get ValueName from hkey storing result in out
3528 * when the Value in the registry has only a filename, use driverdir as prefix
3529 * outlen is space left in out
3530 * String is stored either as unicode or ascii
3534 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3535 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3537 WCHAR filename[MAX_PATH];
3538 DWORD size;
3539 DWORD type;
3540 LONG ret;
3541 LPWSTR buffer = filename;
3542 LPWSTR ptr;
3544 *needed = 0;
3545 size = sizeof(filename);
3546 buffer[0] = '\0';
3547 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3548 if (ret == ERROR_MORE_DATA) {
3549 TRACE("need dynamic buffer: %u\n", size);
3550 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3551 if (!buffer) {
3552 /* No Memory is bad */
3553 return FALSE;
3555 buffer[0] = '\0';
3556 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3559 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3560 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3561 return FALSE;
3564 ptr = buffer;
3565 while (ptr) {
3566 /* do we have a full path ? */
3567 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3568 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3570 if (!ret) {
3571 /* we must build the full Path */
3572 *needed += dirlen;
3573 if ((out) && (outlen > dirlen)) {
3574 if (unicode) {
3575 lstrcpyW((LPWSTR)out, driverdir);
3577 else
3579 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3581 out += dirlen;
3582 outlen -= dirlen;
3584 else
3585 out = NULL;
3588 /* write the filename */
3589 if (unicode) {
3590 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3591 if ((out) && (outlen >= size)) {
3592 lstrcpyW((LPWSTR)out, ptr);
3593 out += size;
3594 outlen -= size;
3596 else
3597 out = NULL;
3599 else
3601 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3602 if ((out) && (outlen >= size)) {
3603 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3604 out += size;
3605 outlen -= size;
3607 else
3608 out = NULL;
3610 *needed += size;
3611 ptr += lstrlenW(ptr)+1;
3612 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3615 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3617 /* write the multisz-termination */
3618 if (type == REG_MULTI_SZ) {
3619 size = (unicode) ? sizeof(WCHAR) : 1;
3621 *needed += size;
3622 if (out && (outlen >= size)) {
3623 memset (out, 0, size);
3626 return TRUE;
3629 /*****************************************************************************
3630 * WINSPOOL_GetStringFromReg
3632 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3633 * String is stored either as unicode or ascii.
3634 * Bit of a hack here to get the ValueName if we want ascii.
3636 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3637 DWORD buflen, DWORD *needed,
3638 BOOL unicode)
3640 DWORD sz = buflen, type;
3641 LONG ret;
3643 if(unicode)
3644 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3645 else {
3646 LPSTR ValueNameA = strdupWtoA(ValueName);
3647 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3648 HeapFree(GetProcessHeap(),0,ValueNameA);
3650 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3651 WARN("Got ret = %d\n", ret);
3652 *needed = 0;
3653 return FALSE;
3655 /* add space for terminating '\0' */
3656 sz += unicode ? sizeof(WCHAR) : 1;
3657 *needed = sz;
3659 if (ptr)
3660 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3662 return TRUE;
3665 /*****************************************************************************
3666 * WINSPOOL_GetDefaultDevMode
3668 * Get a default DevMode values for wineps.
3669 * FIXME - use ppd.
3672 static void WINSPOOL_GetDefaultDevMode(
3673 LPBYTE ptr,
3674 DWORD buflen, DWORD *needed,
3675 BOOL unicode)
3677 DEVMODEA dm;
3678 static const char szwps[] = "wineps.drv";
3680 /* fill default DEVMODE - should be read from ppd... */
3681 ZeroMemory( &dm, sizeof(dm) );
3682 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3683 dm.dmSpecVersion = DM_SPECVERSION;
3684 dm.dmDriverVersion = 1;
3685 dm.dmSize = sizeof(DEVMODEA);
3686 dm.dmDriverExtra = 0;
3687 dm.dmFields =
3688 DM_ORIENTATION | DM_PAPERSIZE |
3689 DM_PAPERLENGTH | DM_PAPERWIDTH |
3690 DM_SCALE |
3691 DM_COPIES |
3692 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3693 DM_YRESOLUTION | DM_TTOPTION;
3695 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3696 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3697 dm.u1.s1.dmPaperLength = 2970;
3698 dm.u1.s1.dmPaperWidth = 2100;
3700 dm.u1.s1.dmScale = 100;
3701 dm.u1.s1.dmCopies = 1;
3702 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3703 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3704 /* dm.dmColor */
3705 /* dm.dmDuplex */
3706 dm.dmYResolution = 300; /* 300dpi */
3707 dm.dmTTOption = DMTT_BITMAP;
3708 /* dm.dmCollate */
3709 /* dm.dmFormName */
3710 /* dm.dmLogPixels */
3711 /* dm.dmBitsPerPel */
3712 /* dm.dmPelsWidth */
3713 /* dm.dmPelsHeight */
3714 /* dm.u2.dmDisplayFlags */
3715 /* dm.dmDisplayFrequency */
3716 /* dm.dmICMMethod */
3717 /* dm.dmICMIntent */
3718 /* dm.dmMediaType */
3719 /* dm.dmDitherType */
3720 /* dm.dmReserved1 */
3721 /* dm.dmReserved2 */
3722 /* dm.dmPanningWidth */
3723 /* dm.dmPanningHeight */
3725 if(unicode) {
3726 if(buflen >= sizeof(DEVMODEW)) {
3727 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3728 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3729 HeapFree(GetProcessHeap(),0,pdmW);
3731 *needed = sizeof(DEVMODEW);
3733 else
3735 if(buflen >= sizeof(DEVMODEA)) {
3736 memcpy(ptr, &dm, sizeof(DEVMODEA));
3738 *needed = sizeof(DEVMODEA);
3742 /*****************************************************************************
3743 * WINSPOOL_GetDevModeFromReg
3745 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3746 * DevMode is stored either as unicode or ascii.
3748 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3749 LPBYTE ptr,
3750 DWORD buflen, DWORD *needed,
3751 BOOL unicode)
3753 DWORD sz = buflen, type;
3754 LONG ret;
3756 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3757 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3758 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3759 if (sz < sizeof(DEVMODEA))
3761 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3762 return FALSE;
3764 /* ensures that dmSize is not erratically bogus if registry is invalid */
3765 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3766 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3767 if(unicode) {
3768 sz += (CCHDEVICENAME + CCHFORMNAME);
3769 if(buflen >= sz) {
3770 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3771 memcpy(ptr, dmW, sz);
3772 HeapFree(GetProcessHeap(),0,dmW);
3775 *needed = sz;
3776 return TRUE;
3779 /*********************************************************************
3780 * WINSPOOL_GetPrinter_1
3782 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3783 * The strings are either stored as unicode or ascii.
3785 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3786 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3787 BOOL unicode)
3789 DWORD size, left = cbBuf;
3790 BOOL space = (cbBuf > 0);
3791 LPBYTE ptr = buf;
3793 *pcbNeeded = 0;
3795 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3796 unicode)) {
3797 if(space && size <= left) {
3798 pi1->pName = (LPWSTR)ptr;
3799 ptr += size;
3800 left -= size;
3801 } else
3802 space = FALSE;
3803 *pcbNeeded += size;
3806 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3807 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3808 unicode)) {
3809 if(space && size <= left) {
3810 pi1->pDescription = (LPWSTR)ptr;
3811 ptr += size;
3812 left -= size;
3813 } else
3814 space = FALSE;
3815 *pcbNeeded += size;
3818 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3819 unicode)) {
3820 if(space && size <= left) {
3821 pi1->pComment = (LPWSTR)ptr;
3822 ptr += size;
3823 left -= size;
3824 } else
3825 space = FALSE;
3826 *pcbNeeded += size;
3829 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3831 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3832 memset(pi1, 0, sizeof(*pi1));
3834 return space;
3836 /*********************************************************************
3837 * WINSPOOL_GetPrinter_2
3839 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3840 * The strings are either stored as unicode or ascii.
3842 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3843 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3844 BOOL unicode)
3846 DWORD size, left = cbBuf;
3847 BOOL space = (cbBuf > 0);
3848 LPBYTE ptr = buf;
3850 *pcbNeeded = 0;
3852 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3853 unicode)) {
3854 if(space && size <= left) {
3855 pi2->pPrinterName = (LPWSTR)ptr;
3856 ptr += size;
3857 left -= size;
3858 } else
3859 space = FALSE;
3860 *pcbNeeded += size;
3862 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3863 unicode)) {
3864 if(space && size <= left) {
3865 pi2->pShareName = (LPWSTR)ptr;
3866 ptr += size;
3867 left -= size;
3868 } else
3869 space = FALSE;
3870 *pcbNeeded += size;
3872 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3873 unicode)) {
3874 if(space && size <= left) {
3875 pi2->pPortName = (LPWSTR)ptr;
3876 ptr += size;
3877 left -= size;
3878 } else
3879 space = FALSE;
3880 *pcbNeeded += size;
3882 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3883 &size, unicode)) {
3884 if(space && size <= left) {
3885 pi2->pDriverName = (LPWSTR)ptr;
3886 ptr += size;
3887 left -= size;
3888 } else
3889 space = FALSE;
3890 *pcbNeeded += size;
3892 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3893 unicode)) {
3894 if(space && size <= left) {
3895 pi2->pComment = (LPWSTR)ptr;
3896 ptr += size;
3897 left -= size;
3898 } else
3899 space = FALSE;
3900 *pcbNeeded += size;
3902 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3903 unicode)) {
3904 if(space && size <= left) {
3905 pi2->pLocation = (LPWSTR)ptr;
3906 ptr += size;
3907 left -= size;
3908 } else
3909 space = FALSE;
3910 *pcbNeeded += size;
3912 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3913 &size, unicode)) {
3914 if(space && size <= left) {
3915 pi2->pDevMode = (LPDEVMODEW)ptr;
3916 ptr += size;
3917 left -= size;
3918 } else
3919 space = FALSE;
3920 *pcbNeeded += size;
3922 else
3924 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3925 if(space && size <= left) {
3926 pi2->pDevMode = (LPDEVMODEW)ptr;
3927 ptr += size;
3928 left -= size;
3929 } else
3930 space = FALSE;
3931 *pcbNeeded += size;
3933 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3934 &size, unicode)) {
3935 if(space && size <= left) {
3936 pi2->pSepFile = (LPWSTR)ptr;
3937 ptr += size;
3938 left -= size;
3939 } else
3940 space = FALSE;
3941 *pcbNeeded += size;
3943 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3944 &size, unicode)) {
3945 if(space && size <= left) {
3946 pi2->pPrintProcessor = (LPWSTR)ptr;
3947 ptr += size;
3948 left -= size;
3949 } else
3950 space = FALSE;
3951 *pcbNeeded += size;
3953 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3954 &size, unicode)) {
3955 if(space && size <= left) {
3956 pi2->pDatatype = (LPWSTR)ptr;
3957 ptr += size;
3958 left -= size;
3959 } else
3960 space = FALSE;
3961 *pcbNeeded += size;
3963 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3964 &size, unicode)) {
3965 if(space && size <= left) {
3966 pi2->pParameters = (LPWSTR)ptr;
3967 ptr += size;
3968 left -= size;
3969 } else
3970 space = FALSE;
3971 *pcbNeeded += size;
3973 if(pi2) {
3974 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3975 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3976 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3977 "Default Priority");
3978 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3979 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3982 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3983 memset(pi2, 0, sizeof(*pi2));
3985 return space;
3988 /*********************************************************************
3989 * WINSPOOL_GetPrinter_4
3991 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3993 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3994 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3995 BOOL unicode)
3997 DWORD size, left = cbBuf;
3998 BOOL space = (cbBuf > 0);
3999 LPBYTE ptr = buf;
4001 *pcbNeeded = 0;
4003 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4004 unicode)) {
4005 if(space && size <= left) {
4006 pi4->pPrinterName = (LPWSTR)ptr;
4007 ptr += size;
4008 left -= size;
4009 } else
4010 space = FALSE;
4011 *pcbNeeded += size;
4013 if(pi4) {
4014 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4017 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4018 memset(pi4, 0, sizeof(*pi4));
4020 return space;
4023 /*********************************************************************
4024 * WINSPOOL_GetPrinter_5
4026 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4028 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4029 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4030 BOOL unicode)
4032 DWORD size, left = cbBuf;
4033 BOOL space = (cbBuf > 0);
4034 LPBYTE ptr = buf;
4036 *pcbNeeded = 0;
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4039 unicode)) {
4040 if(space && size <= left) {
4041 pi5->pPrinterName = (LPWSTR)ptr;
4042 ptr += size;
4043 left -= size;
4044 } else
4045 space = FALSE;
4046 *pcbNeeded += size;
4048 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4049 unicode)) {
4050 if(space && size <= left) {
4051 pi5->pPortName = (LPWSTR)ptr;
4052 ptr += size;
4053 left -= size;
4054 } else
4055 space = FALSE;
4056 *pcbNeeded += size;
4058 if(pi5) {
4059 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4060 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4061 "dnsTimeout");
4062 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4063 "txTimeout");
4066 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4067 memset(pi5, 0, sizeof(*pi5));
4069 return space;
4072 /*********************************************************************
4073 * WINSPOOL_GetPrinter_7
4075 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4077 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4078 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4080 DWORD size, left = cbBuf;
4081 BOOL space = (cbBuf > 0);
4082 LPBYTE ptr = buf;
4084 *pcbNeeded = 0;
4086 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4088 if (space && size <= left) {
4089 pi7->pszObjectGUID = (LPWSTR)ptr;
4090 ptr += size;
4091 left -= size;
4092 } else
4093 space = FALSE;
4094 *pcbNeeded += size;
4096 if (pi7) {
4097 /* We do not have a Directory Service */
4098 pi7->dwAction = DSPRINT_UNPUBLISH;
4101 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4102 memset(pi7, 0, sizeof(*pi7));
4104 return space;
4107 /*********************************************************************
4108 * WINSPOOL_GetPrinter_9
4110 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4111 * The strings are either stored as unicode or ascii.
4113 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4114 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4116 DWORD size;
4117 BOOL space = (cbBuf > 0);
4119 *pcbNeeded = 0;
4121 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4122 if(space && size <= cbBuf) {
4123 pi9->pDevMode = (LPDEVMODEW)buf;
4124 } else
4125 space = FALSE;
4126 *pcbNeeded += size;
4128 else
4130 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4131 if(space && size <= cbBuf) {
4132 pi9->pDevMode = (LPDEVMODEW)buf;
4133 } else
4134 space = FALSE;
4135 *pcbNeeded += size;
4138 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4139 memset(pi9, 0, sizeof(*pi9));
4141 return space;
4144 /*****************************************************************************
4145 * WINSPOOL_GetPrinter
4147 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4148 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4149 * just a collection of pointers to strings.
4151 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4152 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4154 LPCWSTR name;
4155 DWORD size, needed = 0;
4156 LPBYTE ptr = NULL;
4157 HKEY hkeyPrinter, hkeyPrinters;
4158 BOOL ret;
4160 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4162 if (!(name = get_opened_printer_name(hPrinter))) {
4163 SetLastError(ERROR_INVALID_HANDLE);
4164 return FALSE;
4167 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4168 ERROR_SUCCESS) {
4169 ERR("Can't create Printers key\n");
4170 return FALSE;
4172 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4174 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4175 RegCloseKey(hkeyPrinters);
4176 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4177 return FALSE;
4180 switch(Level) {
4181 case 2:
4183 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4185 size = sizeof(PRINTER_INFO_2W);
4186 if(size <= cbBuf) {
4187 ptr = pPrinter + size;
4188 cbBuf -= size;
4189 memset(pPrinter, 0, size);
4190 } else {
4191 pi2 = NULL;
4192 cbBuf = 0;
4194 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4195 unicode);
4196 needed += size;
4197 break;
4200 case 4:
4202 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4204 size = sizeof(PRINTER_INFO_4W);
4205 if(size <= cbBuf) {
4206 ptr = pPrinter + size;
4207 cbBuf -= size;
4208 memset(pPrinter, 0, size);
4209 } else {
4210 pi4 = NULL;
4211 cbBuf = 0;
4213 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4214 unicode);
4215 needed += size;
4216 break;
4220 case 5:
4222 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4224 size = sizeof(PRINTER_INFO_5W);
4225 if(size <= cbBuf) {
4226 ptr = pPrinter + size;
4227 cbBuf -= size;
4228 memset(pPrinter, 0, size);
4229 } else {
4230 pi5 = NULL;
4231 cbBuf = 0;
4234 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4235 unicode);
4236 needed += size;
4237 break;
4241 case 6:
4243 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4245 size = sizeof(PRINTER_INFO_6);
4246 if (size <= cbBuf) {
4247 /* FIXME: We do not update the status yet */
4248 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4249 ret = TRUE;
4250 } else {
4251 ret = FALSE;
4254 needed += size;
4255 break;
4258 case 7:
4260 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4262 size = sizeof(PRINTER_INFO_7W);
4263 if (size <= cbBuf) {
4264 ptr = pPrinter + size;
4265 cbBuf -= size;
4266 memset(pPrinter, 0, size);
4267 } else {
4268 pi7 = NULL;
4269 cbBuf = 0;
4272 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4273 needed += size;
4274 break;
4278 case 9:
4280 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4282 size = sizeof(PRINTER_INFO_9W);
4283 if(size <= cbBuf) {
4284 ptr = pPrinter + size;
4285 cbBuf -= size;
4286 memset(pPrinter, 0, size);
4287 } else {
4288 pi9 = NULL;
4289 cbBuf = 0;
4292 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4293 needed += size;
4294 break;
4298 default:
4299 FIXME("Unimplemented level %d\n", Level);
4300 SetLastError(ERROR_INVALID_LEVEL);
4301 RegCloseKey(hkeyPrinters);
4302 RegCloseKey(hkeyPrinter);
4303 return FALSE;
4306 RegCloseKey(hkeyPrinter);
4307 RegCloseKey(hkeyPrinters);
4309 TRACE("returning %d needed = %d\n", ret, needed);
4310 if(pcbNeeded) *pcbNeeded = needed;
4311 if(!ret)
4312 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4313 return ret;
4316 /*****************************************************************************
4317 * GetPrinterW [WINSPOOL.@]
4319 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4320 DWORD cbBuf, LPDWORD pcbNeeded)
4322 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4323 TRUE);
4326 /*****************************************************************************
4327 * GetPrinterA [WINSPOOL.@]
4329 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4330 DWORD cbBuf, LPDWORD pcbNeeded)
4332 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4333 FALSE);
4336 /*****************************************************************************
4337 * WINSPOOL_EnumPrinters
4339 * Implementation of EnumPrintersA|W
4341 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4342 DWORD dwLevel, LPBYTE lpbPrinters,
4343 DWORD cbBuf, LPDWORD lpdwNeeded,
4344 LPDWORD lpdwReturned, BOOL unicode)
4347 HKEY hkeyPrinters, hkeyPrinter;
4348 WCHAR PrinterName[255];
4349 DWORD needed = 0, number = 0;
4350 DWORD used, i, left;
4351 PBYTE pi, buf;
4353 if(lpbPrinters)
4354 memset(lpbPrinters, 0, cbBuf);
4355 if(lpdwReturned)
4356 *lpdwReturned = 0;
4357 if(lpdwNeeded)
4358 *lpdwNeeded = 0;
4360 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4361 if(dwType == PRINTER_ENUM_DEFAULT)
4362 return TRUE;
4364 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4365 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4366 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4367 if (!dwType) {
4368 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4369 *lpdwNeeded = 0;
4370 *lpdwReturned = 0;
4371 return TRUE;
4376 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4377 FIXME("dwType = %08x\n", dwType);
4378 SetLastError(ERROR_INVALID_FLAGS);
4379 return FALSE;
4382 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4383 ERROR_SUCCESS) {
4384 ERR("Can't create Printers key\n");
4385 return FALSE;
4388 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4389 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4390 RegCloseKey(hkeyPrinters);
4391 ERR("Can't query Printers key\n");
4392 return FALSE;
4394 TRACE("Found %d printers\n", number);
4396 switch(dwLevel) {
4397 case 1:
4398 used = number * sizeof(PRINTER_INFO_1W);
4399 break;
4400 case 2:
4401 used = number * sizeof(PRINTER_INFO_2W);
4402 break;
4403 case 4:
4404 used = number * sizeof(PRINTER_INFO_4W);
4405 break;
4406 case 5:
4407 used = number * sizeof(PRINTER_INFO_5W);
4408 break;
4410 default:
4411 SetLastError(ERROR_INVALID_LEVEL);
4412 RegCloseKey(hkeyPrinters);
4413 return FALSE;
4415 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4417 for(i = 0; i < number; i++) {
4418 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4419 ERROR_SUCCESS) {
4420 ERR("Can't enum key number %d\n", i);
4421 RegCloseKey(hkeyPrinters);
4422 return FALSE;
4424 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4425 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4426 ERROR_SUCCESS) {
4427 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4428 RegCloseKey(hkeyPrinters);
4429 return FALSE;
4432 if(cbBuf > used) {
4433 buf = lpbPrinters + used;
4434 left = cbBuf - used;
4435 } else {
4436 buf = NULL;
4437 left = 0;
4440 switch(dwLevel) {
4441 case 1:
4442 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4443 left, &needed, unicode);
4444 used += needed;
4445 if(pi) pi += sizeof(PRINTER_INFO_1W);
4446 break;
4447 case 2:
4448 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4449 left, &needed, unicode);
4450 used += needed;
4451 if(pi) pi += sizeof(PRINTER_INFO_2W);
4452 break;
4453 case 4:
4454 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4455 left, &needed, unicode);
4456 used += needed;
4457 if(pi) pi += sizeof(PRINTER_INFO_4W);
4458 break;
4459 case 5:
4460 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4461 left, &needed, unicode);
4462 used += needed;
4463 if(pi) pi += sizeof(PRINTER_INFO_5W);
4464 break;
4465 default:
4466 ERR("Shouldn't be here!\n");
4467 RegCloseKey(hkeyPrinter);
4468 RegCloseKey(hkeyPrinters);
4469 return FALSE;
4471 RegCloseKey(hkeyPrinter);
4473 RegCloseKey(hkeyPrinters);
4475 if(lpdwNeeded)
4476 *lpdwNeeded = used;
4478 if(used > cbBuf) {
4479 if(lpbPrinters)
4480 memset(lpbPrinters, 0, cbBuf);
4481 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4482 return FALSE;
4484 if(lpdwReturned)
4485 *lpdwReturned = number;
4486 SetLastError(ERROR_SUCCESS);
4487 return TRUE;
4491 /******************************************************************
4492 * EnumPrintersW [WINSPOOL.@]
4494 * Enumerates the available printers, print servers and print
4495 * providers, depending on the specified flags, name and level.
4497 * RETURNS:
4499 * If level is set to 1:
4500 * Returns an array of PRINTER_INFO_1 data structures in the
4501 * lpbPrinters buffer.
4503 * If level is set to 2:
4504 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4505 * Returns an array of PRINTER_INFO_2 data structures in the
4506 * lpbPrinters buffer. Note that according to MSDN also an
4507 * OpenPrinter should be performed on every remote printer.
4509 * If level is set to 4 (officially WinNT only):
4510 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4511 * Fast: Only the registry is queried to retrieve printer names,
4512 * no connection to the driver is made.
4513 * Returns an array of PRINTER_INFO_4 data structures in the
4514 * lpbPrinters buffer.
4516 * If level is set to 5 (officially WinNT4/Win9x only):
4517 * Fast: Only the registry is queried to retrieve printer names,
4518 * no connection to the driver is made.
4519 * Returns an array of PRINTER_INFO_5 data structures in the
4520 * lpbPrinters buffer.
4522 * If level set to 3 or 6+:
4523 * returns zero (failure!)
4525 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4526 * for information.
4528 * BUGS:
4529 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4530 * - Only levels 2, 4 and 5 are implemented at the moment.
4531 * - 16-bit printer drivers are not enumerated.
4532 * - Returned amount of bytes used/needed does not match the real Windoze
4533 * implementation (as in this implementation, all strings are part
4534 * of the buffer, whereas Win32 keeps them somewhere else)
4535 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4537 * NOTE:
4538 * - In a regular Wine installation, no registry settings for printers
4539 * exist, which makes this function return an empty list.
4541 BOOL WINAPI EnumPrintersW(
4542 DWORD dwType, /* [in] Types of print objects to enumerate */
4543 LPWSTR lpszName, /* [in] name of objects to enumerate */
4544 DWORD dwLevel, /* [in] type of printer info structure */
4545 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4546 DWORD cbBuf, /* [in] max size of buffer in bytes */
4547 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4548 LPDWORD lpdwReturned /* [out] number of entries returned */
4551 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4552 lpdwNeeded, lpdwReturned, TRUE);
4555 /******************************************************************
4556 * EnumPrintersA [WINSPOOL.@]
4558 * See EnumPrintersW
4561 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4562 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4564 BOOL ret;
4565 UNICODE_STRING pNameU;
4566 LPWSTR pNameW;
4567 LPBYTE pPrintersW;
4569 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4570 pPrinters, cbBuf, pcbNeeded, pcReturned);
4572 pNameW = asciitounicode(&pNameU, pName);
4574 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4575 MS Office need this */
4576 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4578 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4580 RtlFreeUnicodeString(&pNameU);
4581 if (ret) {
4582 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4584 HeapFree(GetProcessHeap(), 0, pPrintersW);
4585 return ret;
4588 /*****************************************************************************
4589 * WINSPOOL_GetDriverInfoFromReg [internal]
4591 * Enters the information from the registry into the DRIVER_INFO struct
4593 * RETURNS
4594 * zero if the printer driver does not exist in the registry
4595 * (only if Level > 1) otherwise nonzero
4597 static BOOL WINSPOOL_GetDriverInfoFromReg(
4598 HKEY hkeyDrivers,
4599 LPWSTR DriverName,
4600 const printenv_t * env,
4601 DWORD Level,
4602 LPBYTE ptr, /* DRIVER_INFO */
4603 LPBYTE pDriverStrings, /* strings buffer */
4604 DWORD cbBuf, /* size of string buffer */
4605 LPDWORD pcbNeeded, /* space needed for str. */
4606 BOOL unicode) /* type of strings */
4608 DWORD size, tmp;
4609 HKEY hkeyDriver;
4610 WCHAR driverdir[MAX_PATH];
4611 DWORD dirlen;
4612 LPBYTE strPtr = pDriverStrings;
4613 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4615 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4616 debugstr_w(DriverName), env,
4617 Level, di, pDriverStrings, cbBuf, unicode);
4619 if (di) ZeroMemory(di, di_sizeof[Level]);
4621 if (unicode) {
4622 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4623 if (*pcbNeeded <= cbBuf)
4624 strcpyW((LPWSTR)strPtr, DriverName);
4626 else
4628 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4629 if (*pcbNeeded <= cbBuf)
4630 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4633 /* pName for level 1 has a different offset! */
4634 if (Level == 1) {
4635 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4636 return TRUE;
4639 /* .cVersion and .pName for level > 1 */
4640 if (di) {
4641 di->cVersion = env->driverversion;
4642 di->pName = (LPWSTR) strPtr;
4643 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4646 /* Reserve Space for the largest subdir and a Backslash*/
4647 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4648 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4649 /* Should never Fail */
4650 return FALSE;
4652 lstrcatW(driverdir, env->versionsubdir);
4653 lstrcatW(driverdir, backslashW);
4655 /* dirlen must not include the terminating zero */
4656 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4657 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4659 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4660 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4661 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4662 return FALSE;
4665 /* pEnvironment */
4666 if (unicode)
4667 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4668 else
4669 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4671 *pcbNeeded += size;
4672 if (*pcbNeeded <= cbBuf) {
4673 if (unicode) {
4674 lstrcpyW((LPWSTR)strPtr, env->envname);
4676 else
4678 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4680 if (di) di->pEnvironment = (LPWSTR)strPtr;
4681 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4684 /* .pDriverPath is the Graphics rendering engine.
4685 The full Path is required to avoid a crash in some apps */
4686 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4687 *pcbNeeded += size;
4688 if (*pcbNeeded <= cbBuf)
4689 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4691 if (di) di->pDriverPath = (LPWSTR)strPtr;
4692 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4695 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4696 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4697 *pcbNeeded += size;
4698 if (*pcbNeeded <= cbBuf)
4699 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4701 if (di) di->pDataFile = (LPWSTR)strPtr;
4702 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4705 /* .pConfigFile is the Driver user Interface */
4706 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4707 *pcbNeeded += size;
4708 if (*pcbNeeded <= cbBuf)
4709 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4711 if (di) di->pConfigFile = (LPWSTR)strPtr;
4712 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4715 if (Level == 2 ) {
4716 RegCloseKey(hkeyDriver);
4717 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4718 return TRUE;
4721 if (Level == 5 ) {
4722 RegCloseKey(hkeyDriver);
4723 FIXME("level 5: incomplete\n");
4724 return TRUE;
4727 /* .pHelpFile */
4728 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4729 *pcbNeeded += size;
4730 if (*pcbNeeded <= cbBuf)
4731 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4733 if (di) di->pHelpFile = (LPWSTR)strPtr;
4734 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4737 /* .pDependentFiles */
4738 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4739 *pcbNeeded += size;
4740 if (*pcbNeeded <= cbBuf)
4741 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4743 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4744 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4746 else if (GetVersion() & 0x80000000) {
4747 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4748 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4749 *pcbNeeded += size;
4750 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4752 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4753 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4756 /* .pMonitorName is the optional Language Monitor */
4757 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4758 *pcbNeeded += size;
4759 if (*pcbNeeded <= cbBuf)
4760 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4762 if (di) di->pMonitorName = (LPWSTR)strPtr;
4763 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4766 /* .pDefaultDataType */
4767 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4768 *pcbNeeded += size;
4769 if(*pcbNeeded <= cbBuf)
4770 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4772 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4773 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4776 if (Level == 3 ) {
4777 RegCloseKey(hkeyDriver);
4778 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4779 return TRUE;
4782 /* .pszzPreviousNames */
4783 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4784 *pcbNeeded += size;
4785 if(*pcbNeeded <= cbBuf)
4786 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4788 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4789 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4792 if (Level == 4 ) {
4793 RegCloseKey(hkeyDriver);
4794 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4795 return TRUE;
4798 /* support is missing, but not important enough for a FIXME */
4799 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4801 /* .pszMfgName */
4802 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4803 *pcbNeeded += size;
4804 if(*pcbNeeded <= cbBuf)
4805 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4807 if (di) di->pszMfgName = (LPWSTR)strPtr;
4808 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4811 /* .pszOEMUrl */
4812 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4813 *pcbNeeded += size;
4814 if(*pcbNeeded <= cbBuf)
4815 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4817 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4818 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4821 /* .pszHardwareID */
4822 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4823 *pcbNeeded += size;
4824 if(*pcbNeeded <= cbBuf)
4825 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4827 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4828 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4831 /* .pszProvider */
4832 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4833 *pcbNeeded += size;
4834 if(*pcbNeeded <= cbBuf)
4835 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4837 if (di) di->pszProvider = (LPWSTR)strPtr;
4838 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4841 if (Level == 6 ) {
4842 RegCloseKey(hkeyDriver);
4843 return TRUE;
4846 /* support is missing, but not important enough for a FIXME */
4847 TRACE("level 8: incomplete\n");
4849 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4850 RegCloseKey(hkeyDriver);
4851 return TRUE;
4854 /*****************************************************************************
4855 * WINSPOOL_GetPrinterDriver
4857 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4858 DWORD Level, LPBYTE pDriverInfo,
4859 DWORD cbBuf, LPDWORD pcbNeeded,
4860 BOOL unicode)
4862 LPCWSTR name;
4863 WCHAR DriverName[100];
4864 DWORD ret, type, size, needed = 0;
4865 LPBYTE ptr = NULL;
4866 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4867 const printenv_t * env;
4869 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4870 Level,pDriverInfo,cbBuf, pcbNeeded);
4873 if (!(name = get_opened_printer_name(hPrinter))) {
4874 SetLastError(ERROR_INVALID_HANDLE);
4875 return FALSE;
4878 if (Level < 1 || Level == 7 || Level > 8) {
4879 SetLastError(ERROR_INVALID_LEVEL);
4880 return FALSE;
4883 env = validate_envW(pEnvironment);
4884 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4886 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4887 ERROR_SUCCESS) {
4888 ERR("Can't create Printers key\n");
4889 return FALSE;
4891 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4892 != ERROR_SUCCESS) {
4893 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4894 RegCloseKey(hkeyPrinters);
4895 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4896 return FALSE;
4898 size = sizeof(DriverName);
4899 DriverName[0] = 0;
4900 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4901 (LPBYTE)DriverName, &size);
4902 RegCloseKey(hkeyPrinter);
4903 RegCloseKey(hkeyPrinters);
4904 if(ret != ERROR_SUCCESS) {
4905 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4906 return FALSE;
4909 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4910 if(!hkeyDrivers) {
4911 ERR("Can't create Drivers key\n");
4912 return FALSE;
4915 size = di_sizeof[Level];
4916 if ((size <= cbBuf) && pDriverInfo)
4917 ptr = pDriverInfo + size;
4919 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4920 env, Level, pDriverInfo, ptr,
4921 (cbBuf < size) ? 0 : cbBuf - size,
4922 &needed, unicode)) {
4923 RegCloseKey(hkeyDrivers);
4924 return FALSE;
4927 RegCloseKey(hkeyDrivers);
4929 if(pcbNeeded) *pcbNeeded = size + needed;
4930 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4931 if(cbBuf >= needed) return TRUE;
4932 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4933 return FALSE;
4936 /*****************************************************************************
4937 * GetPrinterDriverA [WINSPOOL.@]
4939 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4940 DWORD Level, LPBYTE pDriverInfo,
4941 DWORD cbBuf, LPDWORD pcbNeeded)
4943 BOOL ret;
4944 UNICODE_STRING pEnvW;
4945 PWSTR pwstrEnvW;
4947 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4948 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4949 cbBuf, pcbNeeded, FALSE);
4950 RtlFreeUnicodeString(&pEnvW);
4951 return ret;
4953 /*****************************************************************************
4954 * GetPrinterDriverW [WINSPOOL.@]
4956 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4957 DWORD Level, LPBYTE pDriverInfo,
4958 DWORD cbBuf, LPDWORD pcbNeeded)
4960 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4961 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4964 /*****************************************************************************
4965 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4967 * Return the PATH for the Printer-Drivers (UNICODE)
4969 * PARAMS
4970 * pName [I] Servername (NT only) or NULL (local Computer)
4971 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4972 * Level [I] Structure-Level (must be 1)
4973 * pDriverDirectory [O] PTR to Buffer that receives the Result
4974 * cbBuf [I] Size of Buffer at pDriverDirectory
4975 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4976 * required for pDriverDirectory
4978 * RETURNS
4979 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4980 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4981 * if cbBuf is too small
4983 * Native Values returned in pDriverDirectory on Success:
4984 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4985 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4986 *| win9x(Windows 4.0): "%winsysdir%"
4988 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4990 * FIXME
4991 *- Only NULL or "" is supported for pName
4994 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4995 DWORD Level, LPBYTE pDriverDirectory,
4996 DWORD cbBuf, LPDWORD pcbNeeded)
4998 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4999 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5001 if ((backend == NULL) && !load_backend()) return FALSE;
5003 if (Level != 1) {
5004 /* (Level != 1) is ignored in win9x */
5005 SetLastError(ERROR_INVALID_LEVEL);
5006 return FALSE;
5008 if (pcbNeeded == NULL) {
5009 /* (pcbNeeded == NULL) is ignored in win9x */
5010 SetLastError(RPC_X_NULL_REF_POINTER);
5011 return FALSE;
5014 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5015 pDriverDirectory, cbBuf, pcbNeeded);
5020 /*****************************************************************************
5021 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5023 * Return the PATH for the Printer-Drivers (ANSI)
5025 * See GetPrinterDriverDirectoryW.
5027 * NOTES
5028 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5031 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5032 DWORD Level, LPBYTE pDriverDirectory,
5033 DWORD cbBuf, LPDWORD pcbNeeded)
5035 UNICODE_STRING nameW, environmentW;
5036 BOOL ret;
5037 DWORD pcbNeededW;
5038 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5039 WCHAR *driverDirectoryW = NULL;
5041 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5042 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5044 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5046 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5047 else nameW.Buffer = NULL;
5048 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5049 else environmentW.Buffer = NULL;
5051 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5052 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5053 if (ret) {
5054 DWORD needed;
5055 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5056 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5057 if(pcbNeeded)
5058 *pcbNeeded = needed;
5059 ret = (needed <= cbBuf) ? TRUE : FALSE;
5060 } else
5061 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5063 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5065 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5066 RtlFreeUnicodeString(&environmentW);
5067 RtlFreeUnicodeString(&nameW);
5069 return ret;
5072 /*****************************************************************************
5073 * AddPrinterDriverA [WINSPOOL.@]
5075 * See AddPrinterDriverW.
5078 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5080 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5081 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5084 /******************************************************************************
5085 * AddPrinterDriverW (WINSPOOL.@)
5087 * Install a Printer Driver
5089 * PARAMS
5090 * pName [I] Servername or NULL (local Computer)
5091 * level [I] Level for the supplied DRIVER_INFO_*W struct
5092 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5094 * RESULTS
5095 * Success: TRUE
5096 * Failure: FALSE
5099 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5101 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5102 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5105 /*****************************************************************************
5106 * AddPrintProcessorA [WINSPOOL.@]
5108 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5109 LPSTR pPrintProcessorName)
5111 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5112 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5113 return FALSE;
5116 /*****************************************************************************
5117 * AddPrintProcessorW [WINSPOOL.@]
5119 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5120 LPWSTR pPrintProcessorName)
5122 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5123 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5124 return FALSE;
5127 /*****************************************************************************
5128 * AddPrintProvidorA [WINSPOOL.@]
5130 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5132 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5133 return FALSE;
5136 /*****************************************************************************
5137 * AddPrintProvidorW [WINSPOOL.@]
5139 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5141 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5142 return FALSE;
5145 /*****************************************************************************
5146 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5148 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5149 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5151 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5152 pDevModeOutput, pDevModeInput);
5153 return 0;
5156 /*****************************************************************************
5157 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5159 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5160 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5162 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5163 pDevModeOutput, pDevModeInput);
5164 return 0;
5167 /*****************************************************************************
5168 * PrinterProperties [WINSPOOL.@]
5170 * Displays a dialog to set the properties of the printer.
5172 * RETURNS
5173 * nonzero on success or zero on failure
5175 * BUGS
5176 * implemented as stub only
5178 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5179 HANDLE hPrinter /* [in] handle to printer object */
5181 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5183 return FALSE;
5186 /*****************************************************************************
5187 * EnumJobsA [WINSPOOL.@]
5190 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5191 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5192 LPDWORD pcReturned)
5194 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5195 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5197 if(pcbNeeded) *pcbNeeded = 0;
5198 if(pcReturned) *pcReturned = 0;
5199 return FALSE;
5203 /*****************************************************************************
5204 * EnumJobsW [WINSPOOL.@]
5207 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5208 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5209 LPDWORD pcReturned)
5211 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5212 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5214 if(pcbNeeded) *pcbNeeded = 0;
5215 if(pcReturned) *pcReturned = 0;
5216 return FALSE;
5219 /*****************************************************************************
5220 * WINSPOOL_EnumPrinterDrivers [internal]
5222 * Delivers information about all printer drivers installed on the
5223 * localhost or a given server
5225 * RETURNS
5226 * nonzero on success or zero on failure. If the buffer for the returned
5227 * information is too small the function will return an error
5229 * BUGS
5230 * - only implemented for localhost, foreign hosts will return an error
5232 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5233 DWORD Level, LPBYTE pDriverInfo,
5234 DWORD cbBuf, LPDWORD pcbNeeded,
5235 LPDWORD pcReturned, BOOL unicode)
5237 { HKEY hkeyDrivers;
5238 DWORD i, needed, number = 0, size = 0;
5239 WCHAR DriverNameW[255];
5240 PBYTE ptr;
5241 const printenv_t * env;
5243 TRACE("%s,%s,%d,%p,%d,%d\n",
5244 debugstr_w(pName), debugstr_w(pEnvironment),
5245 Level, pDriverInfo, cbBuf, unicode);
5247 /* check for local drivers */
5248 if((pName) && (pName[0])) {
5249 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5250 SetLastError(ERROR_ACCESS_DENIED);
5251 return FALSE;
5254 env = validate_envW(pEnvironment);
5255 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5257 /* check input parameter */
5258 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5259 SetLastError(ERROR_INVALID_LEVEL);
5260 return FALSE;
5263 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5264 SetLastError(RPC_X_NULL_REF_POINTER);
5265 return FALSE;
5268 /* initialize return values */
5269 if(pDriverInfo)
5270 memset( pDriverInfo, 0, cbBuf);
5271 *pcbNeeded = 0;
5272 *pcReturned = 0;
5274 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5275 if(!hkeyDrivers) {
5276 ERR("Can't open Drivers key\n");
5277 return FALSE;
5280 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5281 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5282 RegCloseKey(hkeyDrivers);
5283 ERR("Can't query Drivers key\n");
5284 return FALSE;
5286 TRACE("Found %d Drivers\n", number);
5288 /* get size of single struct
5289 * unicode and ascii structure have the same size
5291 size = di_sizeof[Level];
5293 /* calculate required buffer size */
5294 *pcbNeeded = size * number;
5296 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5297 i < number;
5298 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5299 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5300 != ERROR_SUCCESS) {
5301 ERR("Can't enum key number %d\n", i);
5302 RegCloseKey(hkeyDrivers);
5303 return FALSE;
5305 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5306 env, Level, ptr,
5307 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5308 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5309 &needed, unicode)) {
5310 RegCloseKey(hkeyDrivers);
5311 return FALSE;
5313 (*pcbNeeded) += needed;
5316 RegCloseKey(hkeyDrivers);
5318 if(cbBuf < *pcbNeeded){
5319 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5320 return FALSE;
5323 *pcReturned = number;
5324 return TRUE;
5327 /*****************************************************************************
5328 * EnumPrinterDriversW [WINSPOOL.@]
5330 * see function EnumPrinterDrivers for RETURNS, BUGS
5332 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5333 LPBYTE pDriverInfo, DWORD cbBuf,
5334 LPDWORD pcbNeeded, LPDWORD pcReturned)
5336 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5337 cbBuf, pcbNeeded, pcReturned, TRUE);
5340 /*****************************************************************************
5341 * EnumPrinterDriversA [WINSPOOL.@]
5343 * see function EnumPrinterDrivers for RETURNS, BUGS
5345 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5346 LPBYTE pDriverInfo, DWORD cbBuf,
5347 LPDWORD pcbNeeded, LPDWORD pcReturned)
5348 { BOOL ret;
5349 UNICODE_STRING pNameW, pEnvironmentW;
5350 PWSTR pwstrNameW, pwstrEnvironmentW;
5352 pwstrNameW = asciitounicode(&pNameW, pName);
5353 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5355 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5356 Level, pDriverInfo, cbBuf, pcbNeeded,
5357 pcReturned, FALSE);
5358 RtlFreeUnicodeString(&pNameW);
5359 RtlFreeUnicodeString(&pEnvironmentW);
5361 return ret;
5364 /******************************************************************************
5365 * EnumPortsA (WINSPOOL.@)
5367 * See EnumPortsW.
5370 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5371 LPDWORD pcbNeeded, LPDWORD pcReturned)
5373 BOOL res;
5374 LPBYTE bufferW = NULL;
5375 LPWSTR nameW = NULL;
5376 DWORD needed = 0;
5377 DWORD numentries = 0;
5378 INT len;
5380 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5381 cbBuf, pcbNeeded, pcReturned);
5383 /* convert servername to unicode */
5384 if (pName) {
5385 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5386 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5387 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5389 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5390 needed = cbBuf * sizeof(WCHAR);
5391 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5392 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5394 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5395 if (pcbNeeded) needed = *pcbNeeded;
5396 /* HeapReAlloc return NULL, when bufferW was NULL */
5397 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5398 HeapAlloc(GetProcessHeap(), 0, needed);
5400 /* Try again with the large Buffer */
5401 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5403 needed = pcbNeeded ? *pcbNeeded : 0;
5404 numentries = pcReturned ? *pcReturned : 0;
5407 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5408 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5410 if (res) {
5411 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5412 DWORD entrysize = 0;
5413 DWORD index;
5414 LPSTR ptr;
5415 LPPORT_INFO_2W pi2w;
5416 LPPORT_INFO_2A pi2a;
5418 needed = 0;
5419 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5421 /* First pass: calculate the size for all Entries */
5422 pi2w = (LPPORT_INFO_2W) bufferW;
5423 pi2a = (LPPORT_INFO_2A) pPorts;
5424 index = 0;
5425 while (index < numentries) {
5426 index++;
5427 needed += entrysize; /* PORT_INFO_?A */
5428 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5430 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5431 NULL, 0, NULL, NULL);
5432 if (Level > 1) {
5433 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5434 NULL, 0, NULL, NULL);
5435 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5436 NULL, 0, NULL, NULL);
5438 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5439 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5440 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5443 /* check for errors and quit on failure */
5444 if (cbBuf < needed) {
5445 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5446 res = FALSE;
5447 goto cleanup;
5449 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5450 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5451 cbBuf -= len ; /* free Bytes in the user-Buffer */
5452 pi2w = (LPPORT_INFO_2W) bufferW;
5453 pi2a = (LPPORT_INFO_2A) pPorts;
5454 index = 0;
5455 /* Second Pass: Fill the User Buffer (if we have one) */
5456 while ((index < numentries) && pPorts) {
5457 index++;
5458 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5459 pi2a->pPortName = ptr;
5460 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5461 ptr, cbBuf , NULL, NULL);
5462 ptr += len;
5463 cbBuf -= len;
5464 if (Level > 1) {
5465 pi2a->pMonitorName = ptr;
5466 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5467 ptr, cbBuf, NULL, NULL);
5468 ptr += len;
5469 cbBuf -= len;
5471 pi2a->pDescription = ptr;
5472 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5473 ptr, cbBuf, NULL, NULL);
5474 ptr += len;
5475 cbBuf -= len;
5477 pi2a->fPortType = pi2w->fPortType;
5478 pi2a->Reserved = 0; /* documented: "must be zero" */
5481 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5482 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5483 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5487 cleanup:
5488 if (pcbNeeded) *pcbNeeded = needed;
5489 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5491 HeapFree(GetProcessHeap(), 0, nameW);
5492 HeapFree(GetProcessHeap(), 0, bufferW);
5494 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5495 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5497 return (res);
5501 /******************************************************************************
5502 * EnumPortsW (WINSPOOL.@)
5504 * Enumerate available Ports
5506 * PARAMS
5507 * name [I] Servername or NULL (local Computer)
5508 * level [I] Structure-Level (1 or 2)
5509 * buffer [O] PTR to Buffer that receives the Result
5510 * bufsize [I] Size of Buffer at buffer
5511 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5512 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5514 * RETURNS
5515 * Success: TRUE
5516 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5520 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5522 DWORD needed = 0;
5523 DWORD numentries = 0;
5524 BOOL res = FALSE;
5526 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5527 cbBuf, pcbNeeded, pcReturned);
5529 if (pName && (pName[0])) {
5530 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5531 SetLastError(ERROR_ACCESS_DENIED);
5532 goto emP_cleanup;
5535 /* Level is not checked in win9x */
5536 if (!Level || (Level > 2)) {
5537 WARN("level (%d) is ignored in win9x\n", Level);
5538 SetLastError(ERROR_INVALID_LEVEL);
5539 goto emP_cleanup;
5541 if (!pcbNeeded) {
5542 SetLastError(RPC_X_NULL_REF_POINTER);
5543 goto emP_cleanup;
5546 EnterCriticalSection(&monitor_handles_cs);
5547 monitor_loadall();
5549 /* Scan all local Ports */
5550 numentries = 0;
5551 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5553 /* we calculated the needed buffersize. now do the error-checks */
5554 if (cbBuf < needed) {
5555 monitor_unloadall();
5556 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5557 goto emP_cleanup_cs;
5559 else if (!pPorts || !pcReturned) {
5560 monitor_unloadall();
5561 SetLastError(RPC_X_NULL_REF_POINTER);
5562 goto emP_cleanup_cs;
5565 /* Fill the Buffer */
5566 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5567 res = TRUE;
5568 monitor_unloadall();
5570 emP_cleanup_cs:
5571 LeaveCriticalSection(&monitor_handles_cs);
5573 emP_cleanup:
5574 if (pcbNeeded) *pcbNeeded = needed;
5575 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5577 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5578 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5580 return (res);
5583 /******************************************************************************
5584 * GetDefaultPrinterW (WINSPOOL.@)
5586 * FIXME
5587 * This function must read the value from data 'device' of key
5588 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5590 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5592 BOOL retval = TRUE;
5593 DWORD insize, len;
5594 WCHAR *buffer, *ptr;
5596 if (!namesize)
5598 SetLastError(ERROR_INVALID_PARAMETER);
5599 return FALSE;
5602 /* make the buffer big enough for the stuff from the profile/registry,
5603 * the content must fit into the local buffer to compute the correct
5604 * size even if the extern buffer is too small or not given.
5605 * (20 for ,driver,port) */
5606 insize = *namesize;
5607 len = max(100, (insize + 20));
5608 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5610 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5612 SetLastError (ERROR_FILE_NOT_FOUND);
5613 retval = FALSE;
5614 goto end;
5616 TRACE("%s\n", debugstr_w(buffer));
5618 if ((ptr = strchrW(buffer, ',')) == NULL)
5620 SetLastError(ERROR_INVALID_NAME);
5621 retval = FALSE;
5622 goto end;
5625 *ptr = 0;
5626 *namesize = strlenW(buffer) + 1;
5627 if(!name || (*namesize > insize))
5629 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5630 retval = FALSE;
5631 goto end;
5633 strcpyW(name, buffer);
5635 end:
5636 HeapFree( GetProcessHeap(), 0, buffer);
5637 return retval;
5641 /******************************************************************************
5642 * GetDefaultPrinterA (WINSPOOL.@)
5644 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5646 BOOL retval = TRUE;
5647 DWORD insize = 0;
5648 WCHAR *bufferW = NULL;
5650 if (!namesize)
5652 SetLastError(ERROR_INVALID_PARAMETER);
5653 return FALSE;
5656 if(name && *namesize) {
5657 insize = *namesize;
5658 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5661 if(!GetDefaultPrinterW( bufferW, namesize)) {
5662 retval = FALSE;
5663 goto end;
5666 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5667 NULL, NULL);
5668 if (!*namesize)
5670 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5671 retval = FALSE;
5673 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5675 end:
5676 HeapFree( GetProcessHeap(), 0, bufferW);
5677 return retval;
5681 /******************************************************************************
5682 * SetDefaultPrinterW (WINSPOOL.204)
5684 * Set the Name of the Default Printer
5686 * PARAMS
5687 * pszPrinter [I] Name of the Printer or NULL
5689 * RETURNS
5690 * Success: True
5691 * Failure: FALSE
5693 * NOTES
5694 * When the Parameter is NULL or points to an Empty String and
5695 * a Default Printer was already present, then this Function changes nothing.
5696 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5697 * the First enumerated local Printer is used.
5700 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5703 TRACE("(%s)\n", debugstr_w(pszPrinter));
5705 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5706 return FALSE;
5709 /******************************************************************************
5710 * SetDefaultPrinterA (WINSPOOL.202)
5712 * See SetDefaultPrinterW.
5715 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5718 TRACE("(%s)\n", debugstr_a(pszPrinter));
5720 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5721 return FALSE;
5725 /******************************************************************************
5726 * SetPrinterDataExA (WINSPOOL.@)
5728 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5729 LPCSTR pValueName, DWORD Type,
5730 LPBYTE pData, DWORD cbData)
5732 HKEY hkeyPrinter, hkeySubkey;
5733 DWORD ret;
5735 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5736 debugstr_a(pValueName), Type, pData, cbData);
5738 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5739 != ERROR_SUCCESS)
5740 return ret;
5742 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5743 != ERROR_SUCCESS) {
5744 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5745 RegCloseKey(hkeyPrinter);
5746 return ret;
5748 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5749 RegCloseKey(hkeySubkey);
5750 RegCloseKey(hkeyPrinter);
5751 return ret;
5754 /******************************************************************************
5755 * SetPrinterDataExW (WINSPOOL.@)
5757 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5758 LPCWSTR pValueName, DWORD Type,
5759 LPBYTE pData, DWORD cbData)
5761 HKEY hkeyPrinter, hkeySubkey;
5762 DWORD ret;
5764 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5765 debugstr_w(pValueName), Type, pData, cbData);
5767 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5768 != ERROR_SUCCESS)
5769 return ret;
5771 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5772 != ERROR_SUCCESS) {
5773 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5774 RegCloseKey(hkeyPrinter);
5775 return ret;
5777 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5778 RegCloseKey(hkeySubkey);
5779 RegCloseKey(hkeyPrinter);
5780 return ret;
5783 /******************************************************************************
5784 * SetPrinterDataA (WINSPOOL.@)
5786 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5787 LPBYTE pData, DWORD cbData)
5789 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5790 pData, cbData);
5793 /******************************************************************************
5794 * SetPrinterDataW (WINSPOOL.@)
5796 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5797 LPBYTE pData, DWORD cbData)
5799 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5800 pData, cbData);
5803 /******************************************************************************
5804 * GetPrinterDataExA (WINSPOOL.@)
5806 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5807 LPCSTR pValueName, LPDWORD pType,
5808 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5810 HKEY hkeyPrinter, hkeySubkey;
5811 DWORD ret;
5813 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5814 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5815 pcbNeeded);
5817 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5818 != ERROR_SUCCESS)
5819 return ret;
5821 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5822 != ERROR_SUCCESS) {
5823 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5824 RegCloseKey(hkeyPrinter);
5825 return ret;
5827 *pcbNeeded = nSize;
5828 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5829 RegCloseKey(hkeySubkey);
5830 RegCloseKey(hkeyPrinter);
5831 return ret;
5834 /******************************************************************************
5835 * GetPrinterDataExW (WINSPOOL.@)
5837 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5838 LPCWSTR pValueName, LPDWORD pType,
5839 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5841 HKEY hkeyPrinter, hkeySubkey;
5842 DWORD ret;
5844 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5845 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5846 pcbNeeded);
5848 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5849 != ERROR_SUCCESS)
5850 return ret;
5852 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5853 != ERROR_SUCCESS) {
5854 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5855 RegCloseKey(hkeyPrinter);
5856 return ret;
5858 *pcbNeeded = nSize;
5859 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5860 RegCloseKey(hkeySubkey);
5861 RegCloseKey(hkeyPrinter);
5862 return ret;
5865 /******************************************************************************
5866 * GetPrinterDataA (WINSPOOL.@)
5868 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5869 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5871 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5872 pData, nSize, pcbNeeded);
5875 /******************************************************************************
5876 * GetPrinterDataW (WINSPOOL.@)
5878 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5879 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5881 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5882 pData, nSize, pcbNeeded);
5885 /*******************************************************************************
5886 * EnumPrinterDataExW [WINSPOOL.@]
5888 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5889 LPBYTE pEnumValues, DWORD cbEnumValues,
5890 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5892 HKEY hkPrinter, hkSubKey;
5893 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5894 cbValueNameLen, cbMaxValueLen, cbValueLen,
5895 cbBufSize, dwType;
5896 LPWSTR lpValueName;
5897 HANDLE hHeap;
5898 PBYTE lpValue;
5899 PPRINTER_ENUM_VALUESW ppev;
5901 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5903 if (pKeyName == NULL || *pKeyName == 0)
5904 return ERROR_INVALID_PARAMETER;
5906 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5907 if (ret != ERROR_SUCCESS)
5909 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5910 hPrinter, ret);
5911 return ret;
5914 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5915 if (ret != ERROR_SUCCESS)
5917 r = RegCloseKey (hkPrinter);
5918 if (r != ERROR_SUCCESS)
5919 WARN ("RegCloseKey returned %i\n", r);
5920 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5921 debugstr_w (pKeyName), ret);
5922 return ret;
5925 ret = RegCloseKey (hkPrinter);
5926 if (ret != ERROR_SUCCESS)
5928 ERR ("RegCloseKey returned %i\n", ret);
5929 r = RegCloseKey (hkSubKey);
5930 if (r != ERROR_SUCCESS)
5931 WARN ("RegCloseKey returned %i\n", r);
5932 return ret;
5935 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5936 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5937 if (ret != ERROR_SUCCESS)
5939 r = RegCloseKey (hkSubKey);
5940 if (r != ERROR_SUCCESS)
5941 WARN ("RegCloseKey returned %i\n", r);
5942 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5943 return ret;
5946 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5947 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5949 if (cValues == 0) /* empty key */
5951 r = RegCloseKey (hkSubKey);
5952 if (r != ERROR_SUCCESS)
5953 WARN ("RegCloseKey returned %i\n", r);
5954 *pcbEnumValues = *pnEnumValues = 0;
5955 return ERROR_SUCCESS;
5958 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5960 hHeap = GetProcessHeap ();
5961 if (hHeap == NULL)
5963 ERR ("GetProcessHeap failed\n");
5964 r = RegCloseKey (hkSubKey);
5965 if (r != ERROR_SUCCESS)
5966 WARN ("RegCloseKey returned %i\n", r);
5967 return ERROR_OUTOFMEMORY;
5970 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5971 if (lpValueName == NULL)
5973 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5974 r = RegCloseKey (hkSubKey);
5975 if (r != ERROR_SUCCESS)
5976 WARN ("RegCloseKey returned %i\n", r);
5977 return ERROR_OUTOFMEMORY;
5980 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5981 if (lpValue == NULL)
5983 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5984 if (HeapFree (hHeap, 0, lpValueName) == 0)
5985 WARN ("HeapFree failed with code %i\n", GetLastError ());
5986 r = RegCloseKey (hkSubKey);
5987 if (r != ERROR_SUCCESS)
5988 WARN ("RegCloseKey returned %i\n", r);
5989 return ERROR_OUTOFMEMORY;
5992 TRACE ("pass 1: calculating buffer required for all names and values\n");
5994 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5996 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5998 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6000 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6001 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6002 NULL, NULL, lpValue, &cbValueLen);
6003 if (ret != ERROR_SUCCESS)
6005 if (HeapFree (hHeap, 0, lpValue) == 0)
6006 WARN ("HeapFree failed with code %i\n", GetLastError ());
6007 if (HeapFree (hHeap, 0, lpValueName) == 0)
6008 WARN ("HeapFree failed with code %i\n", GetLastError ());
6009 r = RegCloseKey (hkSubKey);
6010 if (r != ERROR_SUCCESS)
6011 WARN ("RegCloseKey returned %i\n", r);
6012 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6013 return ret;
6016 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6017 debugstr_w (lpValueName), dwIndex,
6018 cbValueNameLen + 1, cbValueLen);
6020 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6021 cbBufSize += cbValueLen;
6024 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6026 *pcbEnumValues = cbBufSize;
6027 *pnEnumValues = cValues;
6029 if (cbEnumValues < cbBufSize) /* buffer too small */
6031 if (HeapFree (hHeap, 0, lpValue) == 0)
6032 WARN ("HeapFree failed with code %i\n", GetLastError ());
6033 if (HeapFree (hHeap, 0, lpValueName) == 0)
6034 WARN ("HeapFree failed with code %i\n", GetLastError ());
6035 r = RegCloseKey (hkSubKey);
6036 if (r != ERROR_SUCCESS)
6037 WARN ("RegCloseKey returned %i\n", r);
6038 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6039 return ERROR_MORE_DATA;
6042 TRACE ("pass 2: copying all names and values to buffer\n");
6044 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6045 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6047 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6049 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6050 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6051 NULL, &dwType, lpValue, &cbValueLen);
6052 if (ret != ERROR_SUCCESS)
6054 if (HeapFree (hHeap, 0, lpValue) == 0)
6055 WARN ("HeapFree failed with code %i\n", GetLastError ());
6056 if (HeapFree (hHeap, 0, lpValueName) == 0)
6057 WARN ("HeapFree failed with code %i\n", GetLastError ());
6058 r = RegCloseKey (hkSubKey);
6059 if (r != ERROR_SUCCESS)
6060 WARN ("RegCloseKey returned %i\n", r);
6061 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6062 return ret;
6065 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6066 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6067 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6068 pEnumValues += cbValueNameLen;
6070 /* return # of *bytes* (including trailing \0), not # of chars */
6071 ppev[dwIndex].cbValueName = cbValueNameLen;
6073 ppev[dwIndex].dwType = dwType;
6075 memcpy (pEnumValues, lpValue, cbValueLen);
6076 ppev[dwIndex].pData = pEnumValues;
6077 pEnumValues += cbValueLen;
6079 ppev[dwIndex].cbData = cbValueLen;
6081 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6082 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6085 if (HeapFree (hHeap, 0, lpValue) == 0)
6087 ret = GetLastError ();
6088 ERR ("HeapFree failed with code %i\n", ret);
6089 if (HeapFree (hHeap, 0, lpValueName) == 0)
6090 WARN ("HeapFree failed with code %i\n", GetLastError ());
6091 r = RegCloseKey (hkSubKey);
6092 if (r != ERROR_SUCCESS)
6093 WARN ("RegCloseKey returned %i\n", r);
6094 return ret;
6097 if (HeapFree (hHeap, 0, lpValueName) == 0)
6099 ret = GetLastError ();
6100 ERR ("HeapFree failed with code %i\n", ret);
6101 r = RegCloseKey (hkSubKey);
6102 if (r != ERROR_SUCCESS)
6103 WARN ("RegCloseKey returned %i\n", r);
6104 return ret;
6107 ret = RegCloseKey (hkSubKey);
6108 if (ret != ERROR_SUCCESS)
6110 ERR ("RegCloseKey returned %i\n", ret);
6111 return ret;
6114 return ERROR_SUCCESS;
6117 /*******************************************************************************
6118 * EnumPrinterDataExA [WINSPOOL.@]
6120 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6121 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6122 * what Windows 2000 SP1 does.
6125 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6126 LPBYTE pEnumValues, DWORD cbEnumValues,
6127 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6129 INT len;
6130 LPWSTR pKeyNameW;
6131 DWORD ret, dwIndex, dwBufSize;
6132 HANDLE hHeap;
6133 LPSTR pBuffer;
6135 TRACE ("%p %s\n", hPrinter, pKeyName);
6137 if (pKeyName == NULL || *pKeyName == 0)
6138 return ERROR_INVALID_PARAMETER;
6140 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6141 if (len == 0)
6143 ret = GetLastError ();
6144 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6145 return ret;
6148 hHeap = GetProcessHeap ();
6149 if (hHeap == NULL)
6151 ERR ("GetProcessHeap failed\n");
6152 return ERROR_OUTOFMEMORY;
6155 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6156 if (pKeyNameW == NULL)
6158 ERR ("Failed to allocate %i bytes from process heap\n",
6159 (LONG)(len * sizeof (WCHAR)));
6160 return ERROR_OUTOFMEMORY;
6163 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6165 ret = GetLastError ();
6166 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6167 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6168 WARN ("HeapFree failed with code %i\n", GetLastError ());
6169 return ret;
6172 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6173 pcbEnumValues, pnEnumValues);
6174 if (ret != ERROR_SUCCESS)
6176 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6177 WARN ("HeapFree failed with code %i\n", GetLastError ());
6178 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6179 return ret;
6182 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6184 ret = GetLastError ();
6185 ERR ("HeapFree failed with code %i\n", ret);
6186 return ret;
6189 if (*pnEnumValues == 0) /* empty key */
6190 return ERROR_SUCCESS;
6192 dwBufSize = 0;
6193 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6195 PPRINTER_ENUM_VALUESW ppev =
6196 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6198 if (dwBufSize < ppev->cbValueName)
6199 dwBufSize = ppev->cbValueName;
6201 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6202 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6203 dwBufSize = ppev->cbData;
6206 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6208 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6209 if (pBuffer == NULL)
6211 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6212 return ERROR_OUTOFMEMORY;
6215 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6217 PPRINTER_ENUM_VALUESW ppev =
6218 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6220 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6221 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6222 NULL);
6223 if (len == 0)
6225 ret = GetLastError ();
6226 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6227 if (HeapFree (hHeap, 0, pBuffer) == 0)
6228 WARN ("HeapFree failed with code %i\n", GetLastError ());
6229 return ret;
6232 memcpy (ppev->pValueName, pBuffer, len);
6234 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6236 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6237 ppev->dwType != REG_MULTI_SZ)
6238 continue;
6240 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6241 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6242 if (len == 0)
6244 ret = GetLastError ();
6245 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6246 if (HeapFree (hHeap, 0, pBuffer) == 0)
6247 WARN ("HeapFree failed with code %i\n", GetLastError ());
6248 return ret;
6251 memcpy (ppev->pData, pBuffer, len);
6253 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6254 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6257 if (HeapFree (hHeap, 0, pBuffer) == 0)
6259 ret = GetLastError ();
6260 ERR ("HeapFree failed with code %i\n", ret);
6261 return ret;
6264 return ERROR_SUCCESS;
6267 /******************************************************************************
6268 * AbortPrinter (WINSPOOL.@)
6270 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6272 FIXME("(%p), stub!\n", hPrinter);
6273 return TRUE;
6276 /******************************************************************************
6277 * AddPortA (WINSPOOL.@)
6279 * See AddPortW.
6282 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6284 LPWSTR nameW = NULL;
6285 LPWSTR monitorW = NULL;
6286 DWORD len;
6287 BOOL res;
6289 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6291 if (pName) {
6292 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6293 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6294 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6297 if (pMonitorName) {
6298 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6299 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6300 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6302 res = AddPortW(nameW, hWnd, monitorW);
6303 HeapFree(GetProcessHeap(), 0, nameW);
6304 HeapFree(GetProcessHeap(), 0, monitorW);
6305 return res;
6308 /******************************************************************************
6309 * AddPortW (WINSPOOL.@)
6311 * Add a Port for a specific Monitor
6313 * PARAMS
6314 * pName [I] Servername or NULL (local Computer)
6315 * hWnd [I] Handle to parent Window for the Dialog-Box
6316 * pMonitorName [I] Name of the Monitor that manage the Port
6318 * RETURNS
6319 * Success: TRUE
6320 * Failure: FALSE
6323 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6325 monitor_t * pm;
6326 monitor_t * pui;
6327 DWORD res;
6329 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6331 if (pName && pName[0]) {
6332 SetLastError(ERROR_INVALID_PARAMETER);
6333 return FALSE;
6336 if (!pMonitorName) {
6337 SetLastError(RPC_X_NULL_REF_POINTER);
6338 return FALSE;
6341 /* an empty Monitorname is Invalid */
6342 if (!pMonitorName[0]) {
6343 SetLastError(ERROR_NOT_SUPPORTED);
6344 return FALSE;
6347 pm = monitor_load(pMonitorName, NULL);
6348 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6349 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6350 TRACE("got %d with %u\n", res, GetLastError());
6351 res = TRUE;
6353 else
6355 pui = monitor_loadui(pm);
6356 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6357 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6358 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6359 TRACE("got %d with %u\n", res, GetLastError());
6360 res = TRUE;
6362 else
6364 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6365 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6367 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6368 SetLastError(ERROR_NOT_SUPPORTED);
6369 res = FALSE;
6371 monitor_unload(pui);
6373 monitor_unload(pm);
6374 TRACE("returning %d with %u\n", res, GetLastError());
6375 return res;
6378 /******************************************************************************
6379 * AddPortExA (WINSPOOL.@)
6381 * See AddPortExW.
6384 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6386 PORT_INFO_2W pi2W;
6387 PORT_INFO_2A * pi2A;
6388 LPWSTR nameW = NULL;
6389 LPWSTR monitorW = NULL;
6390 DWORD len;
6391 BOOL res;
6393 pi2A = (PORT_INFO_2A *) pBuffer;
6395 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6396 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6398 if ((level < 1) || (level > 2)) {
6399 SetLastError(ERROR_INVALID_LEVEL);
6400 return FALSE;
6403 if (!pi2A) {
6404 SetLastError(ERROR_INVALID_PARAMETER);
6405 return FALSE;
6408 if (pName) {
6409 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6410 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6411 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6414 if (pMonitorName) {
6415 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6416 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6417 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6420 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6422 if (pi2A->pPortName) {
6423 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6424 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6425 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6428 if (level > 1) {
6429 if (pi2A->pMonitorName) {
6430 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6431 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6432 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6435 if (pi2A->pDescription) {
6436 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6437 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6438 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6440 pi2W.fPortType = pi2A->fPortType;
6441 pi2W.Reserved = pi2A->Reserved;
6444 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6446 HeapFree(GetProcessHeap(), 0, nameW);
6447 HeapFree(GetProcessHeap(), 0, monitorW);
6448 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6449 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6450 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6451 return res;
6455 /******************************************************************************
6456 * AddPortExW (WINSPOOL.@)
6458 * Add a Port for a specific Monitor, without presenting a user interface
6460 * PARAMS
6461 * pName [I] Servername or NULL (local Computer)
6462 * level [I] Structure-Level (1 or 2) for pBuffer
6463 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6464 * pMonitorName [I] Name of the Monitor that manage the Port
6466 * RETURNS
6467 * Success: TRUE
6468 * Failure: FALSE
6471 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6473 PORT_INFO_2W * pi2;
6474 monitor_t * pm;
6475 DWORD res = FALSE;
6477 pi2 = (PORT_INFO_2W *) pBuffer;
6479 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6480 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6481 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6482 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6485 if ((level < 1) || (level > 2)) {
6486 SetLastError(ERROR_INVALID_LEVEL);
6487 return FALSE;
6490 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6491 SetLastError(ERROR_INVALID_PARAMETER);
6492 return FALSE;
6495 /* load the Monitor */
6496 pm = monitor_load(pMonitorName, NULL);
6497 if (!pm) {
6498 SetLastError(ERROR_INVALID_PARAMETER);
6499 return FALSE;
6502 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6503 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6504 TRACE("got %u with %u\n", res, GetLastError());
6506 else
6508 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6510 monitor_unload(pm);
6511 return res;
6514 /******************************************************************************
6515 * AddPrinterConnectionA (WINSPOOL.@)
6517 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6519 FIXME("%s\n", debugstr_a(pName));
6520 return FALSE;
6523 /******************************************************************************
6524 * AddPrinterConnectionW (WINSPOOL.@)
6526 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6528 FIXME("%s\n", debugstr_w(pName));
6529 return FALSE;
6532 /******************************************************************************
6533 * AddPrinterDriverExW (WINSPOOL.@)
6535 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6537 * PARAMS
6538 * pName [I] Servername or NULL (local Computer)
6539 * level [I] Level for the supplied DRIVER_INFO_*W struct
6540 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6541 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6543 * RESULTS
6544 * Success: TRUE
6545 * Failure: FALSE
6548 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6550 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6552 if ((backend == NULL) && !load_backend()) return FALSE;
6554 if (level < 2 || level == 5 || level == 7 || level > 8) {
6555 SetLastError(ERROR_INVALID_LEVEL);
6556 return FALSE;
6559 if (!pDriverInfo) {
6560 SetLastError(ERROR_INVALID_PARAMETER);
6561 return FALSE;
6564 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6567 /******************************************************************************
6568 * AddPrinterDriverExA (WINSPOOL.@)
6570 * See AddPrinterDriverExW.
6573 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6575 DRIVER_INFO_8A *diA;
6576 DRIVER_INFO_8W diW;
6577 LPWSTR nameW = NULL;
6578 DWORD lenA;
6579 DWORD len;
6580 DWORD res = FALSE;
6582 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6584 diA = (DRIVER_INFO_8A *) pDriverInfo;
6585 ZeroMemory(&diW, sizeof(diW));
6587 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6588 SetLastError(ERROR_INVALID_LEVEL);
6589 return FALSE;
6592 if (diA == NULL) {
6593 SetLastError(ERROR_INVALID_PARAMETER);
6594 return FALSE;
6597 /* convert servername to unicode */
6598 if (pName) {
6599 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6600 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6601 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6604 /* common fields */
6605 diW.cVersion = diA->cVersion;
6607 if (diA->pName) {
6608 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6609 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6610 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6613 if (diA->pEnvironment) {
6614 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6615 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6616 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6619 if (diA->pDriverPath) {
6620 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6621 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6622 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6625 if (diA->pDataFile) {
6626 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6627 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6628 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6631 if (diA->pConfigFile) {
6632 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6633 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6634 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6637 if ((Level > 2) && diA->pDependentFiles) {
6638 lenA = multi_sz_lenA(diA->pDependentFiles);
6639 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6640 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6641 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6644 if ((Level > 2) && diA->pMonitorName) {
6645 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6646 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6647 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6650 if ((Level > 3) && diA->pDefaultDataType) {
6651 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6652 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6653 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6656 if ((Level > 3) && diA->pszzPreviousNames) {
6657 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6658 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6659 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6660 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6663 if ((Level > 5) && diA->pszMfgName) {
6664 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6665 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6666 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6669 if ((Level > 5) && diA->pszOEMUrl) {
6670 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6671 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6672 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6675 if ((Level > 5) && diA->pszHardwareID) {
6676 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6677 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6678 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6681 if ((Level > 5) && diA->pszProvider) {
6682 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6683 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6684 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6687 if (Level > 7) {
6688 FIXME("level %u is incomplete\n", Level);
6691 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6692 TRACE("got %u with %u\n", res, GetLastError());
6693 HeapFree(GetProcessHeap(), 0, nameW);
6694 HeapFree(GetProcessHeap(), 0, diW.pName);
6695 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6696 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6697 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6698 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6699 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6700 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6701 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6702 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6703 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6704 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6705 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6706 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6708 TRACE("=> %u with %u\n", res, GetLastError());
6709 return res;
6712 /******************************************************************************
6713 * ConfigurePortA (WINSPOOL.@)
6715 * See ConfigurePortW.
6718 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6720 LPWSTR nameW = NULL;
6721 LPWSTR portW = NULL;
6722 INT len;
6723 DWORD res;
6725 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6727 /* convert servername to unicode */
6728 if (pName) {
6729 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6730 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6731 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6734 /* convert portname to unicode */
6735 if (pPortName) {
6736 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6737 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6738 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6741 res = ConfigurePortW(nameW, hWnd, portW);
6742 HeapFree(GetProcessHeap(), 0, nameW);
6743 HeapFree(GetProcessHeap(), 0, portW);
6744 return res;
6747 /******************************************************************************
6748 * ConfigurePortW (WINSPOOL.@)
6750 * Display the Configuration-Dialog for a specific Port
6752 * PARAMS
6753 * pName [I] Servername or NULL (local Computer)
6754 * hWnd [I] Handle to parent Window for the Dialog-Box
6755 * pPortName [I] Name of the Port, that should be configured
6757 * RETURNS
6758 * Success: TRUE
6759 * Failure: FALSE
6762 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6764 monitor_t * pm;
6765 monitor_t * pui;
6766 DWORD res;
6768 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6770 if (pName && pName[0]) {
6771 SetLastError(ERROR_INVALID_PARAMETER);
6772 return FALSE;
6775 if (!pPortName) {
6776 SetLastError(RPC_X_NULL_REF_POINTER);
6777 return FALSE;
6780 /* an empty Portname is Invalid, but can popup a Dialog */
6781 if (!pPortName[0]) {
6782 SetLastError(ERROR_NOT_SUPPORTED);
6783 return FALSE;
6786 pm = monitor_load_by_port(pPortName);
6787 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6788 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6789 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6790 TRACE("got %d with %u\n", res, GetLastError());
6792 else
6794 pui = monitor_loadui(pm);
6795 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6796 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6797 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6798 TRACE("got %d with %u\n", res, GetLastError());
6800 else
6802 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6803 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6805 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6806 SetLastError(ERROR_NOT_SUPPORTED);
6807 res = FALSE;
6809 monitor_unload(pui);
6811 monitor_unload(pm);
6813 TRACE("returning %d with %u\n", res, GetLastError());
6814 return res;
6817 /******************************************************************************
6818 * ConnectToPrinterDlg (WINSPOOL.@)
6820 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6822 FIXME("%p %x\n", hWnd, Flags);
6823 return NULL;
6826 /******************************************************************************
6827 * DeletePrinterConnectionA (WINSPOOL.@)
6829 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6831 FIXME("%s\n", debugstr_a(pName));
6832 return TRUE;
6835 /******************************************************************************
6836 * DeletePrinterConnectionW (WINSPOOL.@)
6838 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6840 FIXME("%s\n", debugstr_w(pName));
6841 return TRUE;
6844 /******************************************************************************
6845 * DeletePrinterDriverExW (WINSPOOL.@)
6847 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6848 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6850 HKEY hkey_drivers;
6851 BOOL ret = FALSE;
6853 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6854 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6856 if(pName && pName[0])
6858 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6859 SetLastError(ERROR_INVALID_PARAMETER);
6860 return FALSE;
6863 if(dwDeleteFlag)
6865 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6866 SetLastError(ERROR_INVALID_PARAMETER);
6867 return FALSE;
6870 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6872 if(!hkey_drivers)
6874 ERR("Can't open drivers key\n");
6875 return FALSE;
6878 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6879 ret = TRUE;
6881 RegCloseKey(hkey_drivers);
6883 return ret;
6886 /******************************************************************************
6887 * DeletePrinterDriverExA (WINSPOOL.@)
6889 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6890 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6892 UNICODE_STRING NameW, EnvW, DriverW;
6893 BOOL ret;
6895 asciitounicode(&NameW, pName);
6896 asciitounicode(&EnvW, pEnvironment);
6897 asciitounicode(&DriverW, pDriverName);
6899 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6901 RtlFreeUnicodeString(&DriverW);
6902 RtlFreeUnicodeString(&EnvW);
6903 RtlFreeUnicodeString(&NameW);
6905 return ret;
6908 /******************************************************************************
6909 * DeletePrinterDataExW (WINSPOOL.@)
6911 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6912 LPCWSTR pValueName)
6914 FIXME("%p %s %s\n", hPrinter,
6915 debugstr_w(pKeyName), debugstr_w(pValueName));
6916 return ERROR_INVALID_PARAMETER;
6919 /******************************************************************************
6920 * DeletePrinterDataExA (WINSPOOL.@)
6922 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6923 LPCSTR pValueName)
6925 FIXME("%p %s %s\n", hPrinter,
6926 debugstr_a(pKeyName), debugstr_a(pValueName));
6927 return ERROR_INVALID_PARAMETER;
6930 /******************************************************************************
6931 * DeletePrintProcessorA (WINSPOOL.@)
6933 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6935 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6936 debugstr_a(pPrintProcessorName));
6937 return TRUE;
6940 /******************************************************************************
6941 * DeletePrintProcessorW (WINSPOOL.@)
6943 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6945 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6946 debugstr_w(pPrintProcessorName));
6947 return TRUE;
6950 /******************************************************************************
6951 * DeletePrintProvidorA (WINSPOOL.@)
6953 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6955 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6956 debugstr_a(pPrintProviderName));
6957 return TRUE;
6960 /******************************************************************************
6961 * DeletePrintProvidorW (WINSPOOL.@)
6963 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6965 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6966 debugstr_w(pPrintProviderName));
6967 return TRUE;
6970 /******************************************************************************
6971 * EnumFormsA (WINSPOOL.@)
6973 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6974 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6976 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6977 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6978 return FALSE;
6981 /******************************************************************************
6982 * EnumFormsW (WINSPOOL.@)
6984 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6985 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6987 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6988 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6989 return FALSE;
6992 /*****************************************************************************
6993 * EnumMonitorsA [WINSPOOL.@]
6995 * See EnumMonitorsW.
6998 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6999 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7001 BOOL res;
7002 LPBYTE bufferW = NULL;
7003 LPWSTR nameW = NULL;
7004 DWORD needed = 0;
7005 DWORD numentries = 0;
7006 INT len;
7008 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7009 cbBuf, pcbNeeded, pcReturned);
7011 /* convert servername to unicode */
7012 if (pName) {
7013 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7014 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7015 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7017 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7018 needed = cbBuf * sizeof(WCHAR);
7019 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7020 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7022 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7023 if (pcbNeeded) needed = *pcbNeeded;
7024 /* HeapReAlloc return NULL, when bufferW was NULL */
7025 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7026 HeapAlloc(GetProcessHeap(), 0, needed);
7028 /* Try again with the large Buffer */
7029 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7031 numentries = pcReturned ? *pcReturned : 0;
7032 needed = 0;
7034 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7035 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7037 if (res) {
7038 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7039 DWORD entrysize = 0;
7040 DWORD index;
7041 LPSTR ptr;
7042 LPMONITOR_INFO_2W mi2w;
7043 LPMONITOR_INFO_2A mi2a;
7045 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7046 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7048 /* First pass: calculate the size for all Entries */
7049 mi2w = (LPMONITOR_INFO_2W) bufferW;
7050 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7051 index = 0;
7052 while (index < numentries) {
7053 index++;
7054 needed += entrysize; /* MONITOR_INFO_?A */
7055 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7057 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7058 NULL, 0, NULL, NULL);
7059 if (Level > 1) {
7060 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7061 NULL, 0, NULL, NULL);
7062 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7063 NULL, 0, NULL, NULL);
7065 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7066 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7067 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7070 /* check for errors and quit on failure */
7071 if (cbBuf < needed) {
7072 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7073 res = FALSE;
7074 goto emA_cleanup;
7076 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7077 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7078 cbBuf -= len ; /* free Bytes in the user-Buffer */
7079 mi2w = (LPMONITOR_INFO_2W) bufferW;
7080 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7081 index = 0;
7082 /* Second Pass: Fill the User Buffer (if we have one) */
7083 while ((index < numentries) && pMonitors) {
7084 index++;
7085 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7086 mi2a->pName = ptr;
7087 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7088 ptr, cbBuf , NULL, NULL);
7089 ptr += len;
7090 cbBuf -= len;
7091 if (Level > 1) {
7092 mi2a->pEnvironment = ptr;
7093 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7094 ptr, cbBuf, NULL, NULL);
7095 ptr += len;
7096 cbBuf -= len;
7098 mi2a->pDLLName = ptr;
7099 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7100 ptr, cbBuf, NULL, NULL);
7101 ptr += len;
7102 cbBuf -= len;
7104 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7105 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7106 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7109 emA_cleanup:
7110 if (pcbNeeded) *pcbNeeded = needed;
7111 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7113 HeapFree(GetProcessHeap(), 0, nameW);
7114 HeapFree(GetProcessHeap(), 0, bufferW);
7116 TRACE("returning %d with %d (%d byte for %d entries)\n",
7117 (res), GetLastError(), needed, numentries);
7119 return (res);
7123 /*****************************************************************************
7124 * EnumMonitorsW [WINSPOOL.@]
7126 * Enumerate available Port-Monitors
7128 * PARAMS
7129 * pName [I] Servername or NULL (local Computer)
7130 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7131 * pMonitors [O] PTR to Buffer that receives the Result
7132 * cbBuf [I] Size of Buffer at pMonitors
7133 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7134 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7136 * RETURNS
7137 * Success: TRUE
7138 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7141 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7142 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7145 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7146 cbBuf, pcbNeeded, pcReturned);
7148 if ((backend == NULL) && !load_backend()) return FALSE;
7150 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7151 SetLastError(RPC_X_NULL_REF_POINTER);
7152 return FALSE;
7155 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7158 /******************************************************************************
7159 * SpoolerInit (WINSPOOL.@)
7161 * Initialize the Spooler
7163 * RETURNS
7164 * Success: TRUE
7165 * Failure: FALSE
7167 * NOTES
7168 * The function fails on windows, when the spooler service is not running
7171 BOOL WINAPI SpoolerInit(void)
7174 if ((backend == NULL) && !load_backend()) return FALSE;
7175 return TRUE;
7178 /******************************************************************************
7179 * XcvDataW (WINSPOOL.@)
7181 * Execute commands in the Printmonitor DLL
7183 * PARAMS
7184 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7185 * pszDataName [i] Name of the command to execute
7186 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7187 * cbInputData [i] Size in Bytes of Buffer at pInputData
7188 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7189 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7190 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7191 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7193 * RETURNS
7194 * Success: TRUE
7195 * Failure: FALSE
7197 * NOTES
7198 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7199 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7201 * Minimal List of commands, that a Printmonitor DLL should support:
7203 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7204 *| "AddPort" : Add a Port
7205 *| "DeletePort": Delete a Port
7207 * Many Printmonitors support additional commands. Examples for localspl.dll:
7208 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7209 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7212 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7213 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7214 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7216 opened_printer_t *printer;
7218 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7219 pInputData, cbInputData, pOutputData,
7220 cbOutputData, pcbOutputNeeded, pdwStatus);
7222 printer = get_opened_printer(hXcv);
7223 if (!printer || (!printer->hXcv)) {
7224 SetLastError(ERROR_INVALID_HANDLE);
7225 return FALSE;
7228 if (!pcbOutputNeeded) {
7229 SetLastError(ERROR_INVALID_PARAMETER);
7230 return FALSE;
7233 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7234 SetLastError(RPC_X_NULL_REF_POINTER);
7235 return FALSE;
7238 *pcbOutputNeeded = 0;
7240 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7241 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7243 return TRUE;
7246 /*****************************************************************************
7247 * EnumPrinterDataA [WINSPOOL.@]
7250 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7251 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7252 DWORD cbData, LPDWORD pcbData )
7254 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7255 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7256 return ERROR_NO_MORE_ITEMS;
7259 /*****************************************************************************
7260 * EnumPrinterDataW [WINSPOOL.@]
7263 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7264 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7265 DWORD cbData, LPDWORD pcbData )
7267 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7268 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7269 return ERROR_NO_MORE_ITEMS;
7272 /*****************************************************************************
7273 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7276 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7277 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7278 LPDWORD pcbNeeded, LPDWORD pcReturned)
7280 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7281 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7282 pcbNeeded, pcReturned);
7283 return FALSE;
7286 /*****************************************************************************
7287 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7290 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7291 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7292 LPDWORD pcbNeeded, LPDWORD pcReturned)
7294 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7295 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7296 pcbNeeded, pcReturned);
7297 return FALSE;
7300 /*****************************************************************************
7301 * EnumPrintProcessorsA [WINSPOOL.@]
7304 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7305 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7307 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7308 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7309 return FALSE;
7312 /*****************************************************************************
7313 * EnumPrintProcessorsW [WINSPOOL.@]
7316 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7317 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7319 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7320 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7321 cbBuf, pcbNeeded, pcbReturned);
7322 return FALSE;
7325 /*****************************************************************************
7326 * ExtDeviceMode [WINSPOOL.@]
7329 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7330 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7331 DWORD fMode)
7333 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7334 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7335 debugstr_a(pProfile), fMode);
7336 return -1;
7339 /*****************************************************************************
7340 * FindClosePrinterChangeNotification [WINSPOOL.@]
7343 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7345 FIXME("Stub: %p\n", hChange);
7346 return TRUE;
7349 /*****************************************************************************
7350 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7353 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7354 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7356 FIXME("Stub: %p %x %x %p\n",
7357 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7358 return INVALID_HANDLE_VALUE;
7361 /*****************************************************************************
7362 * FindNextPrinterChangeNotification [WINSPOOL.@]
7365 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7366 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7368 FIXME("Stub: %p %p %p %p\n",
7369 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7370 return FALSE;
7373 /*****************************************************************************
7374 * FreePrinterNotifyInfo [WINSPOOL.@]
7377 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7379 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7380 return TRUE;
7383 /*****************************************************************************
7384 * string_to_buf
7386 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7387 * ansi depending on the unicode parameter.
7389 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7391 if(!str)
7393 *size = 0;
7394 return TRUE;
7397 if(unicode)
7399 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7400 if(*size <= cb)
7402 memcpy(ptr, str, *size);
7403 return TRUE;
7405 return FALSE;
7407 else
7409 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7410 if(*size <= cb)
7412 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7413 return TRUE;
7415 return FALSE;
7419 /*****************************************************************************
7420 * get_job_info_1
7422 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7423 LPDWORD pcbNeeded, BOOL unicode)
7425 DWORD size, left = cbBuf;
7426 BOOL space = (cbBuf > 0);
7427 LPBYTE ptr = buf;
7429 *pcbNeeded = 0;
7431 if(space)
7433 ji1->JobId = job->job_id;
7436 string_to_buf(job->document_title, ptr, left, &size, unicode);
7437 if(space && size <= left)
7439 ji1->pDocument = (LPWSTR)ptr;
7440 ptr += size;
7441 left -= size;
7443 else
7444 space = FALSE;
7445 *pcbNeeded += size;
7447 return space;
7450 /*****************************************************************************
7451 * get_job_info_2
7453 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7454 LPDWORD pcbNeeded, BOOL unicode)
7456 DWORD size, left = cbBuf;
7457 BOOL space = (cbBuf > 0);
7458 LPBYTE ptr = buf;
7460 *pcbNeeded = 0;
7462 if(space)
7464 ji2->JobId = job->job_id;
7467 string_to_buf(job->document_title, ptr, left, &size, unicode);
7468 if(space && size <= left)
7470 ji2->pDocument = (LPWSTR)ptr;
7471 ptr += size;
7472 left -= size;
7474 else
7475 space = FALSE;
7476 *pcbNeeded += size;
7478 return space;
7481 /*****************************************************************************
7482 * get_job_info
7484 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7485 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7487 BOOL ret = FALSE;
7488 DWORD needed = 0, size;
7489 job_t *job;
7490 LPBYTE ptr = pJob;
7492 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7494 EnterCriticalSection(&printer_handles_cs);
7495 job = get_job(hPrinter, JobId);
7496 if(!job)
7497 goto end;
7499 switch(Level)
7501 case 1:
7502 size = sizeof(JOB_INFO_1W);
7503 if(cbBuf >= size)
7505 cbBuf -= size;
7506 ptr += size;
7507 memset(pJob, 0, size);
7509 else
7510 cbBuf = 0;
7511 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7512 needed += size;
7513 break;
7515 case 2:
7516 size = sizeof(JOB_INFO_2W);
7517 if(cbBuf >= size)
7519 cbBuf -= size;
7520 ptr += size;
7521 memset(pJob, 0, size);
7523 else
7524 cbBuf = 0;
7525 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7526 needed += size;
7527 break;
7529 case 3:
7530 size = sizeof(JOB_INFO_3);
7531 if(cbBuf >= size)
7533 cbBuf -= size;
7534 memset(pJob, 0, size);
7535 ret = TRUE;
7537 else
7538 cbBuf = 0;
7539 needed = size;
7540 break;
7542 default:
7543 SetLastError(ERROR_INVALID_LEVEL);
7544 goto end;
7546 if(pcbNeeded)
7547 *pcbNeeded = needed;
7548 end:
7549 LeaveCriticalSection(&printer_handles_cs);
7550 return ret;
7553 /*****************************************************************************
7554 * GetJobA [WINSPOOL.@]
7557 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7558 DWORD cbBuf, LPDWORD pcbNeeded)
7560 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7563 /*****************************************************************************
7564 * GetJobW [WINSPOOL.@]
7567 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7568 DWORD cbBuf, LPDWORD pcbNeeded)
7570 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7573 /*****************************************************************************
7574 * schedule_lpr
7576 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7578 char *unixname, *queue, *cmd;
7579 char fmt[] = "lpr -P%s %s";
7580 DWORD len;
7581 int r;
7583 if(!(unixname = wine_get_unix_file_name(filename)))
7584 return FALSE;
7586 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7587 queue = HeapAlloc(GetProcessHeap(), 0, len);
7588 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7590 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7591 sprintf(cmd, fmt, queue, unixname);
7593 TRACE("printing with: %s\n", cmd);
7594 r = system(cmd);
7596 HeapFree(GetProcessHeap(), 0, cmd);
7597 HeapFree(GetProcessHeap(), 0, queue);
7598 HeapFree(GetProcessHeap(), 0, unixname);
7599 return (r == 0);
7602 /*****************************************************************************
7603 * schedule_cups
7605 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7607 #ifdef SONAME_LIBCUPS
7608 if(pcupsPrintFile)
7610 char *unixname, *queue, *unix_doc_title;
7611 DWORD len;
7612 BOOL ret;
7614 if(!(unixname = wine_get_unix_file_name(filename)))
7615 return FALSE;
7617 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7618 queue = HeapAlloc(GetProcessHeap(), 0, len);
7619 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7621 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7622 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7623 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7625 TRACE("printing via cups\n");
7626 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7627 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7628 HeapFree(GetProcessHeap(), 0, queue);
7629 HeapFree(GetProcessHeap(), 0, unixname);
7630 return ret;
7632 else
7633 #endif
7635 return schedule_lpr(printer_name, filename);
7639 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7641 LPWSTR filename;
7643 switch(msg)
7645 case WM_INITDIALOG:
7646 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7647 return TRUE;
7649 case WM_COMMAND:
7650 if(HIWORD(wparam) == BN_CLICKED)
7652 if(LOWORD(wparam) == IDOK)
7654 HANDLE hf;
7655 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7656 LPWSTR *output;
7658 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7659 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7661 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7663 WCHAR caption[200], message[200];
7664 int mb_ret;
7666 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7667 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7668 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7669 if(mb_ret == IDCANCEL)
7671 HeapFree(GetProcessHeap(), 0, filename);
7672 return TRUE;
7675 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7676 if(hf == INVALID_HANDLE_VALUE)
7678 WCHAR caption[200], message[200];
7680 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7681 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7682 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7683 HeapFree(GetProcessHeap(), 0, filename);
7684 return TRUE;
7686 CloseHandle(hf);
7687 DeleteFileW(filename);
7688 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7689 *output = filename;
7690 EndDialog(hwnd, IDOK);
7691 return TRUE;
7693 if(LOWORD(wparam) == IDCANCEL)
7695 EndDialog(hwnd, IDCANCEL);
7696 return TRUE;
7699 return FALSE;
7701 return FALSE;
7704 /*****************************************************************************
7705 * get_filename
7707 static BOOL get_filename(LPWSTR *filename)
7709 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7710 file_dlg_proc, (LPARAM)filename) == IDOK;
7713 /*****************************************************************************
7714 * schedule_file
7716 static BOOL schedule_file(LPCWSTR filename)
7718 LPWSTR output = NULL;
7720 if(get_filename(&output))
7722 BOOL r;
7723 TRACE("copy to %s\n", debugstr_w(output));
7724 r = CopyFileW(filename, output, FALSE);
7725 HeapFree(GetProcessHeap(), 0, output);
7726 return r;
7728 return FALSE;
7731 /*****************************************************************************
7732 * schedule_pipe
7734 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7736 #ifdef HAVE_FORK
7737 char *unixname, *cmdA;
7738 DWORD len;
7739 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7740 BOOL ret = FALSE;
7741 char buf[1024];
7743 if(!(unixname = wine_get_unix_file_name(filename)))
7744 return FALSE;
7746 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7747 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7748 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7750 TRACE("printing with: %s\n", cmdA);
7752 if((file_fd = open(unixname, O_RDONLY)) == -1)
7753 goto end;
7755 if (pipe(fds))
7757 ERR("pipe() failed!\n");
7758 goto end;
7761 if (fork() == 0)
7763 close(0);
7764 dup2(fds[0], 0);
7765 close(fds[1]);
7767 /* reset signals that we previously set to SIG_IGN */
7768 signal(SIGPIPE, SIG_DFL);
7769 signal(SIGCHLD, SIG_DFL);
7771 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7772 _exit(1);
7775 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7776 write(fds[1], buf, no_read);
7778 ret = TRUE;
7780 end:
7781 if(file_fd != -1) close(file_fd);
7782 if(fds[0] != -1) close(fds[0]);
7783 if(fds[1] != -1) close(fds[1]);
7785 HeapFree(GetProcessHeap(), 0, cmdA);
7786 HeapFree(GetProcessHeap(), 0, unixname);
7787 return ret;
7788 #else
7789 return FALSE;
7790 #endif
7793 /*****************************************************************************
7794 * schedule_unixfile
7796 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7798 int in_fd, out_fd, no_read;
7799 char buf[1024];
7800 BOOL ret = FALSE;
7801 char *unixname, *outputA;
7802 DWORD len;
7804 if(!(unixname = wine_get_unix_file_name(filename)))
7805 return FALSE;
7807 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7808 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7809 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7811 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7812 in_fd = open(unixname, O_RDONLY);
7813 if(out_fd == -1 || in_fd == -1)
7814 goto end;
7816 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7817 write(out_fd, buf, no_read);
7819 ret = TRUE;
7820 end:
7821 if(in_fd != -1) close(in_fd);
7822 if(out_fd != -1) close(out_fd);
7823 HeapFree(GetProcessHeap(), 0, outputA);
7824 HeapFree(GetProcessHeap(), 0, unixname);
7825 return ret;
7828 /*****************************************************************************
7829 * ScheduleJob [WINSPOOL.@]
7832 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7834 opened_printer_t *printer;
7835 BOOL ret = FALSE;
7836 struct list *cursor, *cursor2;
7838 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7839 EnterCriticalSection(&printer_handles_cs);
7840 printer = get_opened_printer(hPrinter);
7841 if(!printer)
7842 goto end;
7844 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7846 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7847 HANDLE hf;
7849 if(job->job_id != dwJobID) continue;
7851 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7852 if(hf != INVALID_HANDLE_VALUE)
7854 PRINTER_INFO_5W *pi5;
7855 DWORD needed;
7856 HKEY hkey;
7857 WCHAR output[1024];
7858 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7859 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7861 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7862 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7863 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7864 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7865 debugstr_w(pi5->pPortName));
7867 output[0] = 0;
7869 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7870 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7872 DWORD type, count = sizeof(output);
7873 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7874 RegCloseKey(hkey);
7876 if(output[0] == '|')
7878 ret = schedule_pipe(output + 1, job->filename);
7880 else if(output[0])
7882 ret = schedule_unixfile(output, job->filename);
7884 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7886 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7888 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7890 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7892 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7894 ret = schedule_file(job->filename);
7896 else
7898 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7900 HeapFree(GetProcessHeap(), 0, pi5);
7901 CloseHandle(hf);
7902 DeleteFileW(job->filename);
7904 list_remove(cursor);
7905 HeapFree(GetProcessHeap(), 0, job->document_title);
7906 HeapFree(GetProcessHeap(), 0, job->filename);
7907 HeapFree(GetProcessHeap(), 0, job);
7908 break;
7910 end:
7911 LeaveCriticalSection(&printer_handles_cs);
7912 return ret;
7915 /*****************************************************************************
7916 * StartDocDlgA [WINSPOOL.@]
7918 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7920 UNICODE_STRING usBuffer;
7921 DOCINFOW docW;
7922 LPWSTR retW;
7923 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7924 LPSTR ret = NULL;
7926 docW.cbSize = sizeof(docW);
7927 if (doc->lpszDocName)
7929 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7930 if (!(docW.lpszDocName = docnameW)) return NULL;
7932 if (doc->lpszOutput)
7934 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7935 if (!(docW.lpszOutput = outputW)) return NULL;
7937 if (doc->lpszDatatype)
7939 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7940 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7942 docW.fwType = doc->fwType;
7944 retW = StartDocDlgW(hPrinter, &docW);
7946 if(retW)
7948 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7949 ret = HeapAlloc(GetProcessHeap(), 0, len);
7950 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7951 HeapFree(GetProcessHeap(), 0, retW);
7954 HeapFree(GetProcessHeap(), 0, datatypeW);
7955 HeapFree(GetProcessHeap(), 0, outputW);
7956 HeapFree(GetProcessHeap(), 0, docnameW);
7958 return ret;
7961 /*****************************************************************************
7962 * StartDocDlgW [WINSPOOL.@]
7964 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7965 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7966 * port is "FILE:". Also returns the full path if passed a relative path.
7968 * The caller should free the returned string from the process heap.
7970 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7972 LPWSTR ret = NULL;
7973 DWORD len, attr;
7975 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7977 PRINTER_INFO_5W *pi5;
7978 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7979 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7980 return NULL;
7981 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7982 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7983 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7985 HeapFree(GetProcessHeap(), 0, pi5);
7986 return NULL;
7988 HeapFree(GetProcessHeap(), 0, pi5);
7991 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7993 LPWSTR name;
7995 if (get_filename(&name))
7997 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7999 HeapFree(GetProcessHeap(), 0, name);
8000 return NULL;
8002 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8003 GetFullPathNameW(name, len, ret, NULL);
8004 HeapFree(GetProcessHeap(), 0, name);
8006 return ret;
8009 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8010 return NULL;
8012 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8013 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8015 attr = GetFileAttributesW(ret);
8016 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8018 HeapFree(GetProcessHeap(), 0, ret);
8019 ret = NULL;
8021 return ret;