localspl: Start implementation of OpenPrinter/ClosePrinter.
[wine/hacks.git] / dlls / winspool.drv / info.c
blobd2a40d0bf2cc6996c85fc56a48a9b24e5f22606f
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2009 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 HANDLE backend_printer;
115 jobqueue_t *queue;
116 started_doc_t *doc;
117 } opened_printer_t;
119 typedef struct {
120 struct list entry;
121 DWORD job_id;
122 WCHAR *filename;
123 WCHAR *document_title;
124 } job_t;
127 typedef struct {
128 LPCWSTR envname;
129 LPCWSTR subdir;
130 DWORD driverversion;
131 LPCWSTR versionregpath;
132 LPCWSTR versionsubdir;
133 } printenv_t;
135 /* ############################### */
137 static struct list monitor_handles = LIST_INIT( monitor_handles );
138 static monitor_t * pm_localport;
140 static opened_printer_t **printer_handles;
141 static UINT nb_printer_handles;
142 static LONG next_job_id = 1;
144 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
145 WORD fwCapability, LPSTR lpszOutput,
146 LPDEVMODEA lpdm );
147 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
148 LPSTR lpszDevice, LPSTR lpszPort,
149 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
150 DWORD fwMode );
152 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
153 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
154 'c','o','n','t','r','o','l','\\',
155 'P','r','i','n','t','\\',
156 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
157 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
159 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
160 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
161 'C','o','n','t','r','o','l','\\',
162 'P','r','i','n','t','\\',
163 'M','o','n','i','t','o','r','s','\\',0};
165 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
166 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
167 'C','o','n','t','r','o','l','\\',
168 'P','r','i','n','t','\\',
169 'P','r','i','n','t','e','r','s',0};
171 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
173 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
174 'M','i','c','r','o','s','o','f','t','\\',
175 'W','i','n','d','o','w','s',' ','N','T','\\',
176 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
177 'W','i','n','d','o','w','s',0};
179 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
180 'M','i','c','r','o','s','o','f','t','\\',
181 'W','i','n','d','o','w','s',' ','N','T','\\',
182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
183 'D','e','v','i','c','e','s',0};
185 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
186 'M','i','c','r','o','s','o','f','t','\\',
187 'W','i','n','d','o','w','s',' ','N','T','\\',
188 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
189 'P','o','r','t','s',0};
191 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
192 'M','i','c','r','o','s','o','f','t','\\',
193 'W','i','n','d','o','w','s',' ','N','T','\\',
194 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
195 'P','r','i','n','t','e','r','P','o','r','t','s',0};
197 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
198 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
199 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
200 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
201 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
202 static const WCHAR subdir_x64W[] = {'x','6','4',0};
203 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
204 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
205 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
206 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
207 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
209 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
210 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
212 static const WCHAR backslashW[] = {'\\',0};
213 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
214 'i','o','n',' ','F','i','l','e',0};
215 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
216 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
217 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
218 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
219 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
220 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
221 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
222 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
223 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
224 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
225 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
226 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
227 static const WCHAR NameW[] = {'N','a','m','e',0};
228 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
229 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
230 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
231 static const WCHAR PortW[] = {'P','o','r','t',0};
232 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
233 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
234 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
235 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
236 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
237 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
238 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
239 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
240 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
241 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
242 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
243 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
244 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
245 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
246 static const WCHAR emptyStringW[] = {0};
247 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
248 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
250 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
252 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
253 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
254 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
256 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
257 'D','o','c','u','m','e','n','t',0};
259 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
260 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
261 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
262 0, sizeof(DRIVER_INFO_8W)};
265 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
266 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
267 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
268 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
269 sizeof(PRINTER_INFO_9W)};
271 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
272 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
273 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
275 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
277 /******************************************************************
278 * validate the user-supplied printing-environment [internal]
280 * PARAMS
281 * env [I] PTR to Environment-String or NULL
283 * RETURNS
284 * Failure: NULL
285 * Success: PTR to printenv_t
287 * NOTES
288 * An empty string is handled the same way as NULL.
289 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
293 static const printenv_t * validate_envW(LPCWSTR env)
295 const printenv_t *result = NULL;
296 unsigned int i;
298 TRACE("testing %s\n", debugstr_w(env));
299 if (env && env[0])
301 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
303 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
305 result = all_printenv[i];
306 break;
310 if (result == NULL) {
311 FIXME("unsupported Environment: %s\n", debugstr_w(env));
312 SetLastError(ERROR_INVALID_ENVIRONMENT);
314 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
316 else
318 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
320 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
322 return result;
326 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
327 if passed a NULL string. This returns NULLs to the result.
329 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
331 if ( (src) )
333 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
334 return usBufferPtr->Buffer;
336 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
337 return NULL;
340 static LPWSTR strdupW(LPCWSTR p)
342 LPWSTR ret;
343 DWORD len;
345 if(!p) return NULL;
346 len = (strlenW(p) + 1) * sizeof(WCHAR);
347 ret = HeapAlloc(GetProcessHeap(), 0, len);
348 memcpy(ret, p, len);
349 return ret;
352 static LPSTR strdupWtoA( LPCWSTR str )
354 LPSTR ret;
355 INT len;
357 if (!str) return NULL;
358 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
359 ret = HeapAlloc( GetProcessHeap(), 0, len );
360 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
361 return ret;
364 /******************************************************************
365 * Return the number of bytes for an multi_sz string.
366 * The result includes all \0s
367 * (specifically the extra \0, that is needed as multi_sz terminator).
369 #if 0
370 static int multi_sz_lenW(const WCHAR *str)
372 const WCHAR *ptr = str;
373 if(!str) return 0;
376 ptr += lstrlenW(ptr) + 1;
377 } while(*ptr);
379 return (ptr - str + 1) * sizeof(WCHAR);
381 #endif
382 /* ################################ */
384 static int multi_sz_lenA(const char *str)
386 const char *ptr = str;
387 if(!str) return 0;
390 ptr += lstrlenA(ptr) + 1;
391 } while(*ptr);
393 return ptr - str + 1;
396 static void
397 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
398 char qbuf[200];
400 /* If forcing, or no profile string entry for device yet, set the entry
402 * The always change entry if not WINEPS yet is discussable.
404 if (force ||
405 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
406 !strcmp(qbuf,"*") ||
407 !strstr(qbuf,"WINEPS.DRV")
409 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
410 HKEY hkey;
412 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
413 WriteProfileStringA("windows","device",buf);
414 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
415 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
416 RegCloseKey(hkey);
418 HeapFree(GetProcessHeap(),0,buf);
422 static BOOL add_printer_driver(const char *name)
424 DRIVER_INFO_3A di3a;
426 static char driver_9x[] = "wineps16.drv",
427 driver_nt[] = "wineps.drv",
428 env_9x[] = "Windows 4.0",
429 env_nt[] = "Windows NT x86",
430 data_file[] = "generic.ppd",
431 default_data_type[] = "RAW";
433 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
434 di3a.cVersion = 3;
435 di3a.pName = (char *)name;
436 di3a.pEnvironment = env_nt;
437 di3a.pDriverPath = driver_nt;
438 di3a.pDataFile = data_file;
439 di3a.pConfigFile = driver_nt;
440 di3a.pDefaultDataType = default_data_type;
442 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
443 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
445 di3a.cVersion = 0;
446 di3a.pEnvironment = env_9x;
447 di3a.pDriverPath = driver_9x;
448 di3a.pConfigFile = driver_9x;
449 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
450 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
452 return TRUE;
455 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
456 debugstr_a(di3a.pEnvironment), GetLastError());
457 return FALSE;
460 #ifdef SONAME_LIBCUPS
461 static typeof(cupsFreeDests) *pcupsFreeDests;
462 static typeof(cupsGetDests) *pcupsGetDests;
463 static typeof(cupsGetPPD) *pcupsGetPPD;
464 static typeof(cupsPrintFile) *pcupsPrintFile;
465 static void *cupshandle;
467 static BOOL CUPS_LoadPrinters(void)
469 int i, nrofdests;
470 BOOL hadprinter = FALSE, haddefault = FALSE;
471 cups_dest_t *dests;
472 PRINTER_INFO_2A pinfo2a;
473 char *port,*devline;
474 HKEY hkeyPrinter, hkeyPrinters, hkey;
475 char loaderror[256];
477 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
478 if (!cupshandle) {
479 TRACE("%s\n", loaderror);
480 return FALSE;
482 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
484 #define DYNCUPS(x) \
485 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
486 if (!p##x) return FALSE;
488 DYNCUPS(cupsFreeDests);
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 pcupsFreeDests(nrofdests, dests);
570 RegCloseKey(hkeyPrinters);
571 return hadprinter;
573 #endif
575 static BOOL
576 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
577 PRINTER_INFO_2A pinfo2a;
578 char *e,*s,*name,*prettyname,*devname;
579 BOOL ret = FALSE, set_default = FALSE;
580 char *port = NULL, *devline,*env_default;
581 HKEY hkeyPrinter, hkeyPrinters, hkey;
583 while (isspace(*pent)) pent++;
584 s = strchr(pent,':');
585 if(s) *s='\0';
586 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
587 strcpy(name,pent);
588 if(s) {
589 *s=':';
590 pent = s;
591 } else
592 pent = "";
594 TRACE("name=%s entry=%s\n",name, pent);
596 if(ispunct(*name)) { /* a tc entry, not a real printer */
597 TRACE("skipping tc entry\n");
598 goto end;
601 if(strstr(pent,":server")) { /* server only version so skip */
602 TRACE("skipping server entry\n");
603 goto end;
606 /* Determine whether this is a postscript printer. */
608 ret = TRUE;
609 env_default = getenv("PRINTER");
610 prettyname = name;
611 /* Get longest name, usually the one at the right for later display. */
612 while((s=strchr(prettyname,'|'))) {
613 *s = '\0';
614 e = s;
615 while(isspace(*--e)) *e = '\0';
616 TRACE("\t%s\n", debugstr_a(prettyname));
617 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
618 for(prettyname = s+1; isspace(*prettyname); prettyname++)
621 e = prettyname + strlen(prettyname);
622 while(isspace(*--e)) *e = '\0';
623 TRACE("\t%s\n", debugstr_a(prettyname));
624 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
626 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
627 * if it is too long, we use it as comment below. */
628 devname = prettyname;
629 if (strlen(devname)>=CCHDEVICENAME-1)
630 devname = name;
631 if (strlen(devname)>=CCHDEVICENAME-1) {
632 ret = FALSE;
633 goto end;
636 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
637 sprintf(port,"LPR:%s",name);
639 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
640 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
641 sprintf(devline, "WINEPS.DRV,%s", port);
642 WriteProfileStringA("devices", devname, devline);
643 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
644 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
645 RegCloseKey(hkey);
648 lstrcatA(devline, ",15,45");
649 WriteProfileStringA("PrinterPorts", devname, devline);
650 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
651 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
652 RegCloseKey(hkey);
655 HeapFree(GetProcessHeap(),0,devline);
657 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
658 ERROR_SUCCESS) {
659 ERR("Can't create Printers key\n");
660 ret = FALSE;
661 goto end;
663 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
664 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
665 and continue */
666 TRACE("Printer already exists\n");
667 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
668 RegCloseKey(hkeyPrinter);
669 } else {
670 static CHAR data_type[] = "RAW",
671 print_proc[] = "WinPrint",
672 comment[] = "WINEPS Printer using LPR",
673 params[] = "<parameters?>",
674 share_name[] = "<share name?>",
675 sep_file[] = "<sep file?>";
677 add_printer_driver(devname);
679 memset(&pinfo2a,0,sizeof(pinfo2a));
680 pinfo2a.pPrinterName = devname;
681 pinfo2a.pDatatype = data_type;
682 pinfo2a.pPrintProcessor = print_proc;
683 pinfo2a.pDriverName = devname;
684 pinfo2a.pComment = comment;
685 pinfo2a.pLocation = prettyname;
686 pinfo2a.pPortName = port;
687 pinfo2a.pParameters = params;
688 pinfo2a.pShareName = share_name;
689 pinfo2a.pSepFile = sep_file;
691 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
692 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
693 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
696 RegCloseKey(hkeyPrinters);
698 if (isfirst || set_default)
699 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
701 end:
702 HeapFree(GetProcessHeap(), 0, port);
703 HeapFree(GetProcessHeap(), 0, name);
704 return ret;
707 static BOOL
708 PRINTCAP_LoadPrinters(void) {
709 BOOL hadprinter = FALSE;
710 char buf[200];
711 FILE *f;
712 char *pent = NULL;
713 BOOL had_bash = FALSE;
715 f = fopen("/etc/printcap","r");
716 if (!f)
717 return FALSE;
719 while(fgets(buf,sizeof(buf),f)) {
720 char *start, *end;
722 end=strchr(buf,'\n');
723 if (end) *end='\0';
725 start = buf;
726 while(isspace(*start)) start++;
727 if(*start == '#' || *start == '\0')
728 continue;
730 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
731 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
732 HeapFree(GetProcessHeap(),0,pent);
733 pent = NULL;
736 if (end && *--end == '\\') {
737 *end = '\0';
738 had_bash = TRUE;
739 } else
740 had_bash = FALSE;
742 if (pent) {
743 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
744 strcat(pent,start);
745 } else {
746 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
747 strcpy(pent,start);
751 if(pent) {
752 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
753 HeapFree(GetProcessHeap(),0,pent);
755 fclose(f);
756 return hadprinter;
759 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
761 if (value)
762 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
763 (lstrlenW(value) + 1) * sizeof(WCHAR));
764 else
765 return ERROR_FILE_NOT_FOUND;
768 /******************************************************************
769 * monitor_unload [internal]
771 * release a printmonitor and unload it from memory, when needed
774 static void monitor_unload(monitor_t * pm)
776 if (pm == NULL) return;
777 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
779 EnterCriticalSection(&monitor_handles_cs);
781 if (pm->refcount) pm->refcount--;
783 if (pm->refcount == 0) {
784 list_remove(&pm->entry);
785 FreeLibrary(pm->hdll);
786 HeapFree(GetProcessHeap(), 0, pm->name);
787 HeapFree(GetProcessHeap(), 0, pm->dllname);
788 HeapFree(GetProcessHeap(), 0, pm);
790 LeaveCriticalSection(&monitor_handles_cs);
793 /******************************************************************
794 * monitor_load [internal]
796 * load a printmonitor, get the dllname from the registry, when needed
797 * initialize the monitor and dump found function-pointers
799 * On failure, SetLastError() is called and NULL is returned
802 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
804 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
805 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
806 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
807 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
808 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
810 monitor_t * pm = NULL;
811 monitor_t * cursor;
812 LPWSTR regroot = NULL;
813 LPWSTR driver = dllname;
815 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
816 /* Is the Monitor already loaded? */
817 EnterCriticalSection(&monitor_handles_cs);
819 if (name) {
820 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
822 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
823 pm = cursor;
824 break;
829 if (pm == NULL) {
830 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
831 if (pm == NULL) goto cleanup;
832 list_add_tail(&monitor_handles, &pm->entry);
834 pm->refcount++;
836 if (pm->name == NULL) {
837 /* Load the monitor */
838 LPMONITOREX pmonitorEx;
839 DWORD len;
841 if (name) {
842 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
843 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
846 if (regroot) {
847 lstrcpyW(regroot, MonitorsW);
848 lstrcatW(regroot, name);
849 /* Get the Driver from the Registry */
850 if (driver == NULL) {
851 HKEY hroot;
852 DWORD namesize;
853 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
854 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
855 &namesize) == ERROR_SUCCESS) {
856 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
857 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
859 RegCloseKey(hroot);
864 pm->name = strdupW(name);
865 pm->dllname = strdupW(driver);
867 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
868 monitor_unload(pm);
869 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
870 pm = NULL;
871 goto cleanup;
874 pm->hdll = LoadLibraryW(driver);
875 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
877 if (pm->hdll == NULL) {
878 monitor_unload(pm);
879 SetLastError(ERROR_MOD_NOT_FOUND);
880 pm = NULL;
881 goto cleanup;
884 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
885 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
886 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
887 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
888 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
891 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
892 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
893 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
894 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
895 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
897 if (pInitializePrintMonitorUI != NULL) {
898 pm->monitorUI = pInitializePrintMonitorUI();
899 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
900 if (pm->monitorUI) {
901 TRACE( "0x%08x: dwMonitorSize (%d)\n",
902 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
907 if (pInitializePrintMonitor && regroot) {
908 pmonitorEx = pInitializePrintMonitor(regroot);
909 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
910 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
912 if (pmonitorEx) {
913 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
914 pm->monitor = &(pmonitorEx->Monitor);
918 if (pm->monitor) {
919 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
923 if (!pm->monitor && regroot) {
924 if (pInitializePrintMonitor2 != NULL) {
925 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
927 if (pInitializeMonitorEx != NULL) {
928 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
930 if (pInitializeMonitor != NULL) {
931 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
934 if (!pm->monitor && !pm->monitorUI) {
935 monitor_unload(pm);
936 SetLastError(ERROR_PROC_NOT_FOUND);
937 pm = NULL;
940 cleanup:
941 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
942 pm->refcount++;
943 pm_localport = pm;
945 LeaveCriticalSection(&monitor_handles_cs);
946 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
947 HeapFree(GetProcessHeap(), 0, regroot);
948 TRACE("=> %p\n", pm);
949 return pm;
952 /******************************************************************
953 * monitor_loadui [internal]
955 * load the userinterface-dll for a given portmonitor
957 * On failure, NULL is returned
960 static monitor_t * monitor_loadui(monitor_t * pm)
962 monitor_t * pui = NULL;
963 LPWSTR buffer[MAX_PATH];
964 HANDLE hXcv;
965 DWORD len;
966 DWORD res;
968 if (pm == NULL) return NULL;
969 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
971 /* Try the Portmonitor first; works for many monitors */
972 if (pm->monitorUI) {
973 EnterCriticalSection(&monitor_handles_cs);
974 pm->refcount++;
975 LeaveCriticalSection(&monitor_handles_cs);
976 return pm;
979 /* query the userinterface-dllname from the Portmonitor */
980 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
981 /* building (",XcvMonitor %s",pm->name) not needed yet */
982 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
983 TRACE("got %u with %p\n", res, hXcv);
984 if (res) {
985 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
986 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
987 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
988 pm->monitor->pfnXcvClosePort(hXcv);
991 return pui;
995 /******************************************************************
996 * monitor_load_by_port [internal]
998 * load a printmonitor for a given port
1000 * On failure, NULL is returned
1003 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1005 HKEY hroot;
1006 HKEY hport;
1007 LPWSTR buffer;
1008 monitor_t * pm = NULL;
1009 DWORD registered = 0;
1010 DWORD id = 0;
1011 DWORD len;
1013 TRACE("(%s)\n", debugstr_w(portname));
1015 /* Try the Local Monitor first */
1016 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1017 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1018 /* found the portname */
1019 RegCloseKey(hroot);
1020 return monitor_load(LocalPortW, NULL);
1022 RegCloseKey(hroot);
1025 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1026 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1027 if (buffer == NULL) return NULL;
1029 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1030 EnterCriticalSection(&monitor_handles_cs);
1031 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1033 while ((pm == NULL) && (id < registered)) {
1034 buffer[0] = '\0';
1035 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1036 TRACE("testing %s\n", debugstr_w(buffer));
1037 len = lstrlenW(buffer);
1038 lstrcatW(buffer, bs_Ports_bsW);
1039 lstrcatW(buffer, portname);
1040 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1041 RegCloseKey(hport);
1042 buffer[len] = '\0'; /* use only the Monitor-Name */
1043 pm = monitor_load(buffer, NULL);
1045 id++;
1047 LeaveCriticalSection(&monitor_handles_cs);
1048 RegCloseKey(hroot);
1050 HeapFree(GetProcessHeap(), 0, buffer);
1051 return pm;
1054 /******************************************************************
1055 * get_servername_from_name (internal)
1057 * for an external server, a copy of the serverpart from the full name is returned
1060 static LPWSTR get_servername_from_name(LPCWSTR name)
1062 LPWSTR server;
1063 LPWSTR ptr;
1064 WCHAR buffer[MAX_PATH];
1065 DWORD len;
1067 if (name == NULL) return NULL;
1068 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1070 server = strdupW(&name[2]); /* skip over both backslash */
1071 if (server == NULL) return NULL;
1073 /* strip '\' and the printername */
1074 ptr = strchrW(server, '\\');
1075 if (ptr) ptr[0] = '\0';
1077 TRACE("found %s\n", debugstr_w(server));
1079 len = sizeof(buffer)/sizeof(buffer[0]);
1080 if (GetComputerNameW(buffer, &len)) {
1081 if (lstrcmpW(buffer, server) == 0) {
1082 /* The requested Servername is our computername */
1083 HeapFree(GetProcessHeap(), 0, server);
1084 return NULL;
1087 return server;
1090 /******************************************************************
1091 * get_basename_from_name (internal)
1093 * skip over the serverpart from the full name
1096 static LPCWSTR get_basename_from_name(LPCWSTR name)
1098 if (name == NULL) return NULL;
1099 if ((name[0] == '\\') && (name[1] == '\\')) {
1100 /* skip over the servername and search for the following '\' */
1101 name = strchrW(&name[2], '\\');
1102 if ((name) && (name[1])) {
1103 /* found a separator ('\') followed by a name:
1104 skip over the separator and return the rest */
1105 name++;
1107 else
1109 /* no basename present (we found only a servername) */
1110 return NULL;
1113 return name;
1116 /******************************************************************
1117 * get_opened_printer_entry
1118 * Get the first place empty in the opened printer table
1120 * ToDo:
1121 * - pDefault is ignored
1123 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1125 UINT_PTR handle = nb_printer_handles, i;
1126 jobqueue_t *queue = NULL;
1127 opened_printer_t *printer = NULL;
1128 LPWSTR servername;
1129 LPCWSTR printername;
1130 HKEY hkeyPrinters;
1131 HKEY hkeyPrinter;
1132 DWORD len;
1134 if ((backend == NULL) && !load_backend()) return NULL;
1136 servername = get_servername_from_name(name);
1137 if (servername) {
1138 FIXME("server %s not supported\n", debugstr_w(servername));
1139 HeapFree(GetProcessHeap(), 0, servername);
1140 SetLastError(ERROR_INVALID_PRINTER_NAME);
1141 return NULL;
1144 printername = get_basename_from_name(name);
1145 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1147 /* an empty printername is invalid */
1148 if (printername && (!printername[0])) {
1149 SetLastError(ERROR_INVALID_PARAMETER);
1150 return NULL;
1153 EnterCriticalSection(&printer_handles_cs);
1155 for (i = 0; i < nb_printer_handles; i++)
1157 if (!printer_handles[i])
1159 if(handle == nb_printer_handles)
1160 handle = i;
1162 else
1164 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1165 queue = printer_handles[i]->queue;
1169 if (handle >= nb_printer_handles)
1171 opened_printer_t **new_array;
1172 if (printer_handles)
1173 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1174 (nb_printer_handles + 16) * sizeof(*new_array) );
1175 else
1176 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1177 (nb_printer_handles + 16) * sizeof(*new_array) );
1179 if (!new_array)
1181 handle = 0;
1182 goto end;
1184 printer_handles = new_array;
1185 nb_printer_handles += 16;
1188 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1190 handle = 0;
1191 goto end;
1194 /* get a printer handle from the backend */
1195 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1196 handle = 0;
1197 goto end;
1200 /* clone the base name. This is NULL for the printserver */
1201 printer->printername = strdupW(printername);
1203 /* clone the full name */
1204 printer->name = strdupW(name);
1205 if (name && (!printer->name)) {
1206 handle = 0;
1207 goto end;
1210 if (printername) {
1211 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1212 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1213 /* OpenPrinter(",XcvMonitor " detected */
1214 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1215 printer->pm = monitor_load(&printername[len], NULL);
1216 if (printer->pm == NULL) {
1217 SetLastError(ERROR_UNKNOWN_PORT);
1218 handle = 0;
1219 goto end;
1222 else
1224 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1225 if (strncmpW( printername, XcvPortW, len) == 0) {
1226 /* OpenPrinter(",XcvPort " detected */
1227 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1228 printer->pm = monitor_load_by_port(&printername[len]);
1229 if (printer->pm == NULL) {
1230 SetLastError(ERROR_UNKNOWN_PORT);
1231 handle = 0;
1232 goto end;
1237 if (printer->pm) {
1238 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1239 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1240 pDefault ? pDefault->DesiredAccess : 0,
1241 &printer->hXcv);
1243 if (printer->hXcv == NULL) {
1244 SetLastError(ERROR_INVALID_PARAMETER);
1245 handle = 0;
1246 goto end;
1249 else
1251 /* Does the Printer exist? */
1252 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1253 ERR("Can't create Printers key\n");
1254 handle = 0;
1255 goto end;
1257 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1258 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1259 RegCloseKey(hkeyPrinters);
1260 SetLastError(ERROR_INVALID_PRINTER_NAME);
1261 handle = 0;
1262 goto end;
1264 RegCloseKey(hkeyPrinter);
1265 RegCloseKey(hkeyPrinters);
1268 else
1270 TRACE("using the local printserver\n");
1273 if(queue)
1274 printer->queue = queue;
1275 else
1277 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1278 if (!printer->queue) {
1279 handle = 0;
1280 goto end;
1282 list_init(&printer->queue->jobs);
1283 printer->queue->ref = 0;
1285 InterlockedIncrement(&printer->queue->ref);
1287 printer_handles[handle] = printer;
1288 handle++;
1289 end:
1290 LeaveCriticalSection(&printer_handles_cs);
1291 if (!handle && printer) {
1292 /* Something failed: Free all resources */
1293 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1294 monitor_unload(printer->pm);
1295 HeapFree(GetProcessHeap(), 0, printer->printername);
1296 HeapFree(GetProcessHeap(), 0, printer->name);
1297 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1298 HeapFree(GetProcessHeap(), 0, printer);
1301 return (HANDLE)handle;
1304 /******************************************************************
1305 * get_opened_printer
1306 * Get the pointer to the opened printer referred by the handle
1308 static opened_printer_t *get_opened_printer(HANDLE hprn)
1310 UINT_PTR idx = (UINT_PTR)hprn;
1311 opened_printer_t *ret = NULL;
1313 EnterCriticalSection(&printer_handles_cs);
1315 if ((idx > 0) && (idx <= nb_printer_handles)) {
1316 ret = printer_handles[idx - 1];
1318 LeaveCriticalSection(&printer_handles_cs);
1319 return ret;
1322 /******************************************************************
1323 * get_opened_printer_name
1324 * Get the pointer to the opened printer name referred by the handle
1326 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1328 opened_printer_t *printer = get_opened_printer(hprn);
1329 if(!printer) return NULL;
1330 return printer->name;
1333 /******************************************************************
1334 * WINSPOOL_GetOpenedPrinterRegKey
1337 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1339 LPCWSTR name = get_opened_printer_name(hPrinter);
1340 DWORD ret;
1341 HKEY hkeyPrinters;
1343 if(!name) return ERROR_INVALID_HANDLE;
1345 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1346 ERROR_SUCCESS)
1347 return ret;
1349 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1351 ERR("Can't find opened printer %s in registry\n",
1352 debugstr_w(name));
1353 RegCloseKey(hkeyPrinters);
1354 return ERROR_INVALID_PRINTER_NAME; /* ? */
1356 RegCloseKey(hkeyPrinters);
1357 return ERROR_SUCCESS;
1360 void WINSPOOL_LoadSystemPrinters(void)
1362 HKEY hkey, hkeyPrinters;
1363 HANDLE hprn;
1364 DWORD needed, num, i;
1365 WCHAR PrinterName[256];
1366 BOOL done = FALSE;
1368 /* This ensures that all printer entries have a valid Name value. If causes
1369 problems later if they don't. If one is found to be missed we create one
1370 and set it equal to the name of the key */
1371 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1372 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1373 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1374 for(i = 0; i < num; i++) {
1375 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1376 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1377 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1378 set_reg_szW(hkey, NameW, PrinterName);
1380 RegCloseKey(hkey);
1385 RegCloseKey(hkeyPrinters);
1388 /* We want to avoid calling AddPrinter on printers as much as
1389 possible, because on cups printers this will (eventually) lead
1390 to a call to cupsGetPPD which takes forever, even with non-cups
1391 printers AddPrinter takes a while. So we'll tag all printers that
1392 were automatically added last time around, if they still exist
1393 we'll leave them be otherwise we'll delete them. */
1394 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1395 if(needed) {
1396 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1397 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1398 for(i = 0; i < num; i++) {
1399 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1400 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1401 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1402 DWORD dw = 1;
1403 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1404 RegCloseKey(hkey);
1406 ClosePrinter(hprn);
1411 HeapFree(GetProcessHeap(), 0, pi);
1415 #ifdef SONAME_LIBCUPS
1416 done = CUPS_LoadPrinters();
1417 #endif
1419 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1420 PRINTCAP_LoadPrinters();
1422 /* Now enumerate the list again and delete any printers that are still tagged */
1423 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1424 if(needed) {
1425 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1426 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1427 for(i = 0; i < num; i++) {
1428 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1429 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1430 BOOL delete_driver = FALSE;
1431 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1432 DWORD dw, type, size = sizeof(dw);
1433 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1434 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1435 DeletePrinter(hprn);
1436 delete_driver = TRUE;
1438 RegCloseKey(hkey);
1440 ClosePrinter(hprn);
1441 if(delete_driver)
1442 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1447 HeapFree(GetProcessHeap(), 0, pi);
1450 return;
1454 /******************************************************************
1455 * get_job
1457 * Get the pointer to the specified job.
1458 * Should hold the printer_handles_cs before calling.
1460 static job_t *get_job(HANDLE hprn, DWORD JobId)
1462 opened_printer_t *printer = get_opened_printer(hprn);
1463 job_t *job;
1465 if(!printer) return NULL;
1466 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1468 if(job->job_id == JobId)
1469 return job;
1471 return NULL;
1474 /***********************************************************
1475 * DEVMODEcpyAtoW
1477 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1479 BOOL Formname;
1480 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1481 DWORD size;
1483 Formname = (dmA->dmSize > off_formname);
1484 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1485 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1486 dmW->dmDeviceName, CCHDEVICENAME);
1487 if(!Formname) {
1488 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1489 dmA->dmSize - CCHDEVICENAME);
1490 } else {
1491 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1492 off_formname - CCHDEVICENAME);
1493 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1494 dmW->dmFormName, CCHFORMNAME);
1495 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1496 (off_formname + CCHFORMNAME));
1498 dmW->dmSize = size;
1499 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1500 dmA->dmDriverExtra);
1501 return dmW;
1504 /***********************************************************
1505 * DEVMODEdupWtoA
1506 * Creates an ansi copy of supplied devmode
1508 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1510 LPDEVMODEA dmA;
1511 DWORD size;
1513 if (!dmW) return NULL;
1514 size = dmW->dmSize - CCHDEVICENAME -
1515 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1517 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1518 if (!dmA) return NULL;
1520 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1521 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1523 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1524 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1525 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1527 else
1529 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1530 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1531 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1532 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1534 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1537 dmA->dmSize = size;
1538 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1539 return dmA;
1542 /******************************************************************
1543 * convert_printerinfo_W_to_A [internal]
1546 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1547 DWORD level, DWORD outlen, DWORD numentries)
1549 DWORD id = 0;
1550 LPSTR ptr;
1551 INT len;
1553 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1555 len = pi_sizeof[level] * numentries;
1556 ptr = (LPSTR) out + len;
1557 outlen -= len;
1559 /* copy the numbers of all PRINTER_INFO_* first */
1560 memcpy(out, pPrintersW, len);
1562 while (id < numentries) {
1563 switch (level) {
1564 case 1:
1566 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1567 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1569 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1570 if (piW->pDescription) {
1571 piA->pDescription = ptr;
1572 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1573 ptr, outlen, NULL, NULL);
1574 ptr += len;
1575 outlen -= len;
1577 if (piW->pName) {
1578 piA->pName = ptr;
1579 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1580 ptr, outlen, NULL, NULL);
1581 ptr += len;
1582 outlen -= len;
1584 if (piW->pComment) {
1585 piA->pComment = ptr;
1586 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1587 ptr, outlen, NULL, NULL);
1588 ptr += len;
1589 outlen -= len;
1591 break;
1594 case 2:
1596 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1597 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1598 LPDEVMODEA dmA;
1600 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1601 if (piW->pServerName) {
1602 piA->pServerName = ptr;
1603 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1604 ptr, outlen, NULL, NULL);
1605 ptr += len;
1606 outlen -= len;
1608 if (piW->pPrinterName) {
1609 piA->pPrinterName = ptr;
1610 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1611 ptr, outlen, NULL, NULL);
1612 ptr += len;
1613 outlen -= len;
1615 if (piW->pShareName) {
1616 piA->pShareName = ptr;
1617 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1618 ptr, outlen, NULL, NULL);
1619 ptr += len;
1620 outlen -= len;
1622 if (piW->pPortName) {
1623 piA->pPortName = ptr;
1624 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1625 ptr, outlen, NULL, NULL);
1626 ptr += len;
1627 outlen -= len;
1629 if (piW->pDriverName) {
1630 piA->pDriverName = ptr;
1631 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1632 ptr, outlen, NULL, NULL);
1633 ptr += len;
1634 outlen -= len;
1636 if (piW->pComment) {
1637 piA->pComment = ptr;
1638 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1639 ptr, outlen, NULL, NULL);
1640 ptr += len;
1641 outlen -= len;
1643 if (piW->pLocation) {
1644 piA->pLocation = ptr;
1645 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1646 ptr, outlen, NULL, NULL);
1647 ptr += len;
1648 outlen -= len;
1651 dmA = DEVMODEdupWtoA(piW->pDevMode);
1652 if (dmA) {
1653 /* align DEVMODEA to a DWORD boundary */
1654 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1655 ptr += len;
1656 outlen -= len;
1658 piA->pDevMode = (LPDEVMODEA) ptr;
1659 len = dmA->dmSize + dmA->dmDriverExtra;
1660 memcpy(ptr, dmA, len);
1661 HeapFree(GetProcessHeap(), 0, dmA);
1663 ptr += len;
1664 outlen -= len;
1667 if (piW->pSepFile) {
1668 piA->pSepFile = ptr;
1669 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1670 ptr, outlen, NULL, NULL);
1671 ptr += len;
1672 outlen -= len;
1674 if (piW->pPrintProcessor) {
1675 piA->pPrintProcessor = ptr;
1676 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1677 ptr, outlen, NULL, NULL);
1678 ptr += len;
1679 outlen -= len;
1681 if (piW->pDatatype) {
1682 piA->pDatatype = ptr;
1683 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1684 ptr, outlen, NULL, NULL);
1685 ptr += len;
1686 outlen -= len;
1688 if (piW->pParameters) {
1689 piA->pParameters = ptr;
1690 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1691 ptr, outlen, NULL, NULL);
1692 ptr += len;
1693 outlen -= len;
1695 if (piW->pSecurityDescriptor) {
1696 piA->pSecurityDescriptor = NULL;
1697 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1699 break;
1702 case 4:
1704 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1705 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1707 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1709 if (piW->pPrinterName) {
1710 piA->pPrinterName = ptr;
1711 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1712 ptr, outlen, NULL, NULL);
1713 ptr += len;
1714 outlen -= len;
1716 if (piW->pServerName) {
1717 piA->pServerName = ptr;
1718 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1719 ptr, outlen, NULL, NULL);
1720 ptr += len;
1721 outlen -= len;
1723 break;
1726 case 5:
1728 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1729 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1731 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1733 if (piW->pPrinterName) {
1734 piA->pPrinterName = ptr;
1735 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1736 ptr, outlen, NULL, NULL);
1737 ptr += len;
1738 outlen -= len;
1740 if (piW->pPortName) {
1741 piA->pPortName = ptr;
1742 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1743 ptr, outlen, NULL, NULL);
1744 ptr += len;
1745 outlen -= len;
1747 break;
1750 default:
1751 FIXME("for level %u\n", level);
1753 pPrintersW += pi_sizeof[level];
1754 out += pi_sizeof[level];
1755 id++;
1759 /***********************************************************
1760 * PRINTER_INFO_2AtoW
1761 * Creates a unicode copy of PRINTER_INFO_2A on heap
1763 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1765 LPPRINTER_INFO_2W piW;
1766 UNICODE_STRING usBuffer;
1768 if(!piA) return NULL;
1769 piW = HeapAlloc(heap, 0, sizeof(*piW));
1770 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1772 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1773 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1774 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1775 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1776 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1777 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1778 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1779 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1780 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1781 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1782 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1783 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1784 return piW;
1787 /***********************************************************
1788 * FREE_PRINTER_INFO_2W
1789 * Free PRINTER_INFO_2W and all strings
1791 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1793 if(!piW) return;
1795 HeapFree(heap,0,piW->pServerName);
1796 HeapFree(heap,0,piW->pPrinterName);
1797 HeapFree(heap,0,piW->pShareName);
1798 HeapFree(heap,0,piW->pPortName);
1799 HeapFree(heap,0,piW->pDriverName);
1800 HeapFree(heap,0,piW->pComment);
1801 HeapFree(heap,0,piW->pLocation);
1802 HeapFree(heap,0,piW->pDevMode);
1803 HeapFree(heap,0,piW->pSepFile);
1804 HeapFree(heap,0,piW->pPrintProcessor);
1805 HeapFree(heap,0,piW->pDatatype);
1806 HeapFree(heap,0,piW->pParameters);
1807 HeapFree(heap,0,piW);
1808 return;
1811 /******************************************************************
1812 * DeviceCapabilities [WINSPOOL.@]
1813 * DeviceCapabilitiesA [WINSPOOL.@]
1816 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1817 LPSTR pOutput, LPDEVMODEA lpdm)
1819 INT ret;
1821 if (!GDI_CallDeviceCapabilities16)
1823 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1824 (LPCSTR)104 );
1825 if (!GDI_CallDeviceCapabilities16) return -1;
1827 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1829 /* If DC_PAPERSIZE map POINT16s to POINTs */
1830 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1831 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1832 POINT *pt = (POINT *)pOutput;
1833 INT i;
1834 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1835 for(i = 0; i < ret; i++, pt++)
1837 pt->x = tmp[i].x;
1838 pt->y = tmp[i].y;
1840 HeapFree( GetProcessHeap(), 0, tmp );
1842 return ret;
1846 /*****************************************************************************
1847 * DeviceCapabilitiesW [WINSPOOL.@]
1849 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1852 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1853 WORD fwCapability, LPWSTR pOutput,
1854 const DEVMODEW *pDevMode)
1856 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1857 LPSTR pDeviceA = strdupWtoA(pDevice);
1858 LPSTR pPortA = strdupWtoA(pPort);
1859 INT ret;
1861 if(pOutput && (fwCapability == DC_BINNAMES ||
1862 fwCapability == DC_FILEDEPENDENCIES ||
1863 fwCapability == DC_PAPERNAMES)) {
1864 /* These need A -> W translation */
1865 INT size = 0, i;
1866 LPSTR pOutputA;
1867 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1868 dmA);
1869 if(ret == -1)
1870 return ret;
1871 switch(fwCapability) {
1872 case DC_BINNAMES:
1873 size = 24;
1874 break;
1875 case DC_PAPERNAMES:
1876 case DC_FILEDEPENDENCIES:
1877 size = 64;
1878 break;
1880 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1881 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1882 dmA);
1883 for(i = 0; i < ret; i++)
1884 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1885 pOutput + (i * size), size);
1886 HeapFree(GetProcessHeap(), 0, pOutputA);
1887 } else {
1888 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1889 (LPSTR)pOutput, dmA);
1891 HeapFree(GetProcessHeap(),0,pPortA);
1892 HeapFree(GetProcessHeap(),0,pDeviceA);
1893 HeapFree(GetProcessHeap(),0,dmA);
1894 return ret;
1897 /******************************************************************
1898 * DocumentPropertiesA [WINSPOOL.@]
1900 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1902 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1903 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1904 LPDEVMODEA pDevModeInput,DWORD fMode )
1906 LPSTR lpName = pDeviceName;
1907 static CHAR port[] = "LPT1:";
1908 LONG ret;
1910 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1911 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1914 if(!pDeviceName) {
1915 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1916 if(!lpNameW) {
1917 ERR("no name from hPrinter?\n");
1918 SetLastError(ERROR_INVALID_HANDLE);
1919 return -1;
1921 lpName = strdupWtoA(lpNameW);
1924 if (!GDI_CallExtDeviceMode16)
1926 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1927 (LPCSTR)102 );
1928 if (!GDI_CallExtDeviceMode16) {
1929 ERR("No CallExtDeviceMode16?\n");
1930 return -1;
1933 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1934 pDevModeInput, NULL, fMode);
1936 if(!pDeviceName)
1937 HeapFree(GetProcessHeap(),0,lpName);
1938 return ret;
1942 /*****************************************************************************
1943 * DocumentPropertiesW (WINSPOOL.@)
1945 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1947 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1948 LPWSTR pDeviceName,
1949 LPDEVMODEW pDevModeOutput,
1950 LPDEVMODEW pDevModeInput, DWORD fMode)
1953 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1954 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1955 LPDEVMODEA pDevModeOutputA = NULL;
1956 LONG ret;
1958 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1959 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1960 fMode);
1961 if(pDevModeOutput) {
1962 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1963 if(ret < 0) return ret;
1964 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1966 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1967 pDevModeInputA, fMode);
1968 if(pDevModeOutput) {
1969 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1970 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1972 if(fMode == 0 && ret > 0)
1973 ret += (CCHDEVICENAME + CCHFORMNAME);
1974 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1975 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1976 return ret;
1979 /******************************************************************
1980 * OpenPrinterA [WINSPOOL.@]
1982 * See OpenPrinterW.
1985 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1986 LPPRINTER_DEFAULTSA pDefault)
1988 UNICODE_STRING lpPrinterNameW;
1989 UNICODE_STRING usBuffer;
1990 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1991 PWSTR pwstrPrinterNameW;
1992 BOOL ret;
1994 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1996 if(pDefault) {
1997 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1998 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1999 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2000 pDefaultW = &DefaultW;
2002 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2003 if(pDefault) {
2004 RtlFreeUnicodeString(&usBuffer);
2005 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2007 RtlFreeUnicodeString(&lpPrinterNameW);
2008 return ret;
2011 /******************************************************************
2012 * OpenPrinterW [WINSPOOL.@]
2014 * Open a Printer / Printserver or a Printer-Object
2016 * PARAMS
2017 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2018 * phPrinter [O] The resulting Handle is stored here
2019 * pDefault [I] PTR to Default Printer Settings or NULL
2021 * RETURNS
2022 * Success: TRUE
2023 * Failure: FALSE
2025 * NOTES
2026 * lpPrinterName is one of:
2027 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2028 *| Printer: "PrinterName"
2029 *| Printer-Object: "PrinterName,Job xxx"
2030 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2031 *| XcvPort: "Servername,XcvPort PortName"
2033 * BUGS
2034 *| Printer-Object not supported
2035 *| pDefaults is ignored
2038 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2041 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2042 if (pDefault) {
2043 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2044 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2047 if(!phPrinter) {
2048 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2049 SetLastError(ERROR_INVALID_PARAMETER);
2050 return FALSE;
2053 /* Get the unique handle of the printer or Printserver */
2054 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2055 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2056 return (*phPrinter != 0);
2059 /******************************************************************
2060 * AddMonitorA [WINSPOOL.@]
2062 * See AddMonitorW.
2065 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2067 LPWSTR nameW = NULL;
2068 INT len;
2069 BOOL res;
2070 LPMONITOR_INFO_2A mi2a;
2071 MONITOR_INFO_2W mi2w;
2073 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2074 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2075 debugstr_a(mi2a ? mi2a->pName : NULL),
2076 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2077 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2079 if (Level != 2) {
2080 SetLastError(ERROR_INVALID_LEVEL);
2081 return FALSE;
2084 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2085 if (mi2a == NULL) {
2086 return FALSE;
2089 if (pName) {
2090 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2091 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2092 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2095 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2096 if (mi2a->pName) {
2097 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2098 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2099 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2101 if (mi2a->pEnvironment) {
2102 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2103 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2104 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2106 if (mi2a->pDLLName) {
2107 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2108 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2109 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2112 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2114 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2115 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2116 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2118 HeapFree(GetProcessHeap(), 0, nameW);
2119 return (res);
2122 /******************************************************************************
2123 * AddMonitorW [WINSPOOL.@]
2125 * Install a Printmonitor
2127 * PARAMS
2128 * pName [I] Servername or NULL (local Computer)
2129 * Level [I] Structure-Level (Must be 2)
2130 * pMonitors [I] PTR to MONITOR_INFO_2
2132 * RETURNS
2133 * Success: TRUE
2134 * Failure: FALSE
2136 * NOTES
2137 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2140 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2142 LPMONITOR_INFO_2W mi2w;
2144 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2145 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2146 debugstr_w(mi2w ? mi2w->pName : NULL),
2147 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2148 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2150 if ((backend == NULL) && !load_backend()) return FALSE;
2152 if (Level != 2) {
2153 SetLastError(ERROR_INVALID_LEVEL);
2154 return FALSE;
2157 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2158 if (mi2w == NULL) {
2159 return FALSE;
2162 return backend->fpAddMonitor(pName, Level, pMonitors);
2165 /******************************************************************
2166 * DeletePrinterDriverA [WINSPOOL.@]
2169 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2171 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2174 /******************************************************************
2175 * DeletePrinterDriverW [WINSPOOL.@]
2178 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2180 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2183 /******************************************************************
2184 * DeleteMonitorA [WINSPOOL.@]
2186 * See DeleteMonitorW.
2189 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2191 LPWSTR nameW = NULL;
2192 LPWSTR EnvironmentW = NULL;
2193 LPWSTR MonitorNameW = NULL;
2194 BOOL res;
2195 INT len;
2197 if (pName) {
2198 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2199 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2200 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2203 if (pEnvironment) {
2204 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2205 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2208 if (pMonitorName) {
2209 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2210 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2211 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2214 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2216 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2217 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2218 HeapFree(GetProcessHeap(), 0, nameW);
2219 return (res);
2222 /******************************************************************
2223 * DeleteMonitorW [WINSPOOL.@]
2225 * Delete a specific Printmonitor from a Printing-Environment
2227 * PARAMS
2228 * pName [I] Servername or NULL (local Computer)
2229 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2230 * pMonitorName [I] Name of the Monitor, that should be deleted
2232 * RETURNS
2233 * Success: TRUE
2234 * Failure: FALSE
2236 * NOTES
2237 * pEnvironment is ignored in Windows for the local Computer.
2240 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2243 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2244 debugstr_w(pMonitorName));
2246 if ((backend == NULL) && !load_backend()) return FALSE;
2248 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2252 /******************************************************************
2253 * DeletePortA [WINSPOOL.@]
2255 * See DeletePortW.
2258 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2260 LPWSTR nameW = NULL;
2261 LPWSTR portW = NULL;
2262 INT len;
2263 DWORD res;
2265 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2267 /* convert servername to unicode */
2268 if (pName) {
2269 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2270 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2271 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2274 /* convert portname to unicode */
2275 if (pPortName) {
2276 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2277 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2278 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2281 res = DeletePortW(nameW, hWnd, portW);
2282 HeapFree(GetProcessHeap(), 0, nameW);
2283 HeapFree(GetProcessHeap(), 0, portW);
2284 return res;
2287 /******************************************************************
2288 * DeletePortW [WINSPOOL.@]
2290 * Delete a specific Port
2292 * PARAMS
2293 * pName [I] Servername or NULL (local Computer)
2294 * hWnd [I] Handle to parent Window for the Dialog-Box
2295 * pPortName [I] Name of the Port, that should be deleted
2297 * RETURNS
2298 * Success: TRUE
2299 * Failure: FALSE
2302 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2304 monitor_t * pm;
2305 monitor_t * pui;
2306 DWORD res;
2308 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2310 if (pName && pName[0]) {
2311 SetLastError(ERROR_INVALID_PARAMETER);
2312 return FALSE;
2315 if (!pPortName) {
2316 SetLastError(RPC_X_NULL_REF_POINTER);
2317 return FALSE;
2320 /* an empty Portname is Invalid */
2321 if (!pPortName[0]) {
2322 SetLastError(ERROR_NOT_SUPPORTED);
2323 return FALSE;
2326 pm = monitor_load_by_port(pPortName);
2327 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2328 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2329 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2330 TRACE("got %d with %u\n", res, GetLastError());
2332 else
2334 pui = monitor_loadui(pm);
2335 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2336 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2337 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2338 TRACE("got %d with %u\n", res, GetLastError());
2340 else
2342 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2343 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2345 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2346 SetLastError(ERROR_NOT_SUPPORTED);
2347 res = FALSE;
2349 monitor_unload(pui);
2351 monitor_unload(pm);
2353 TRACE("returning %d with %u\n", res, GetLastError());
2354 return res;
2357 /******************************************************************************
2358 * SetPrinterW [WINSPOOL.@]
2360 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2362 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2363 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2364 return FALSE;
2367 /******************************************************************************
2368 * WritePrinter [WINSPOOL.@]
2370 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2372 opened_printer_t *printer;
2373 BOOL ret = FALSE;
2375 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2377 EnterCriticalSection(&printer_handles_cs);
2378 printer = get_opened_printer(hPrinter);
2379 if(!printer)
2381 SetLastError(ERROR_INVALID_HANDLE);
2382 goto end;
2385 if(!printer->doc)
2387 SetLastError(ERROR_SPL_NO_STARTDOC);
2388 goto end;
2391 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2392 end:
2393 LeaveCriticalSection(&printer_handles_cs);
2394 return ret;
2397 /*****************************************************************************
2398 * AddFormA [WINSPOOL.@]
2400 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2402 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2403 return 1;
2406 /*****************************************************************************
2407 * AddFormW [WINSPOOL.@]
2409 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2411 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2412 return 1;
2415 /*****************************************************************************
2416 * AddJobA [WINSPOOL.@]
2418 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2420 BOOL ret;
2421 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2422 DWORD needed;
2424 if(Level != 1) {
2425 SetLastError(ERROR_INVALID_LEVEL);
2426 return FALSE;
2429 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2431 if(ret) {
2432 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2433 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2434 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2435 if(*pcbNeeded > cbBuf) {
2436 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2437 ret = FALSE;
2438 } else {
2439 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2440 addjobA->JobId = addjobW->JobId;
2441 addjobA->Path = (char *)(addjobA + 1);
2442 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2445 return ret;
2448 /*****************************************************************************
2449 * AddJobW [WINSPOOL.@]
2451 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2453 opened_printer_t *printer;
2454 job_t *job;
2455 BOOL ret = FALSE;
2456 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2457 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2458 WCHAR path[MAX_PATH], filename[MAX_PATH];
2459 DWORD len;
2460 ADDJOB_INFO_1W *addjob;
2462 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2464 EnterCriticalSection(&printer_handles_cs);
2466 printer = get_opened_printer(hPrinter);
2468 if(!printer) {
2469 SetLastError(ERROR_INVALID_HANDLE);
2470 goto end;
2473 if(Level != 1) {
2474 SetLastError(ERROR_INVALID_LEVEL);
2475 goto end;
2478 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2479 if(!job)
2480 goto end;
2482 job->job_id = InterlockedIncrement(&next_job_id);
2484 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2485 if(path[len - 1] != '\\')
2486 path[len++] = '\\';
2487 memcpy(path + len, spool_path, sizeof(spool_path));
2488 sprintfW(filename, fmtW, path, job->job_id);
2490 len = strlenW(filename);
2491 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2492 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2493 job->document_title = strdupW(default_doc_title);
2494 list_add_tail(&printer->queue->jobs, &job->entry);
2496 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2497 if(*pcbNeeded <= cbBuf) {
2498 addjob = (ADDJOB_INFO_1W*)pData;
2499 addjob->JobId = job->job_id;
2500 addjob->Path = (WCHAR *)(addjob + 1);
2501 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2502 ret = TRUE;
2503 } else
2504 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2506 end:
2507 LeaveCriticalSection(&printer_handles_cs);
2508 return ret;
2511 /*****************************************************************************
2512 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2514 * Return the PATH for the Print-Processors
2516 * See GetPrintProcessorDirectoryW.
2520 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2521 DWORD level, LPBYTE Info,
2522 DWORD cbBuf, LPDWORD pcbNeeded)
2524 LPWSTR serverW = NULL;
2525 LPWSTR envW = NULL;
2526 BOOL ret;
2527 INT len;
2529 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2530 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2533 if (server) {
2534 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2535 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2536 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2539 if (env) {
2540 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2541 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2542 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2545 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2546 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2548 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2549 cbBuf, pcbNeeded);
2551 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2552 cbBuf, NULL, NULL) > 0;
2555 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2556 HeapFree(GetProcessHeap(), 0, envW);
2557 HeapFree(GetProcessHeap(), 0, serverW);
2558 return ret;
2561 /*****************************************************************************
2562 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2564 * Return the PATH for the Print-Processors
2566 * PARAMS
2567 * server [I] Servername (NT only) or NULL (local Computer)
2568 * env [I] Printing-Environment (see below) or NULL (Default)
2569 * level [I] Structure-Level (must be 1)
2570 * Info [O] PTR to Buffer that receives the Result
2571 * cbBuf [I] Size of Buffer at "Info"
2572 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2573 * required for the Buffer at "Info"
2575 * RETURNS
2576 * Success: TRUE and in pcbNeeded the Bytes used in Info
2577 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2578 * if cbBuf is too small
2580 * Native Values returned in Info on Success:
2581 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2582 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2583 *| win9x(Windows 4.0): "%winsysdir%"
2585 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2587 * BUGS
2588 * Only NULL or "" is supported for server
2591 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2592 DWORD level, LPBYTE Info,
2593 DWORD cbBuf, LPDWORD pcbNeeded)
2595 DWORD needed;
2596 const printenv_t * env_t;
2598 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2599 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2601 if(server != NULL && server[0]) {
2602 FIXME("server not supported: %s\n", debugstr_w(server));
2603 SetLastError(ERROR_INVALID_PARAMETER);
2604 return FALSE;
2607 env_t = validate_envW(env);
2608 if(!env_t) return FALSE; /* environment invalid or unsupported */
2610 if(level != 1) {
2611 WARN("(Level: %d) is ignored in win9x\n", level);
2612 SetLastError(ERROR_INVALID_LEVEL);
2613 return FALSE;
2616 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2617 needed = GetSystemDirectoryW(NULL, 0);
2618 /* add the Size for the Subdirectories */
2619 needed += lstrlenW(spoolprtprocsW);
2620 needed += lstrlenW(env_t->subdir);
2621 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2623 if(pcbNeeded) *pcbNeeded = needed;
2624 TRACE ("required: 0x%x/%d\n", needed, needed);
2625 if (needed > cbBuf) {
2626 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2627 return FALSE;
2629 if(pcbNeeded == NULL) {
2630 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2631 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2632 SetLastError(RPC_X_NULL_REF_POINTER);
2633 return FALSE;
2635 if(Info == NULL) {
2636 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2637 SetLastError(RPC_X_NULL_REF_POINTER);
2638 return FALSE;
2641 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2642 /* add the Subdirectories */
2643 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2644 lstrcatW((LPWSTR) Info, env_t->subdir);
2645 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2646 return TRUE;
2649 /*****************************************************************************
2650 * WINSPOOL_OpenDriverReg [internal]
2652 * opens the registry for the printer drivers depending on the given input
2653 * variable pEnvironment
2655 * RETURNS:
2656 * the opened hkey on success
2657 * NULL on error
2659 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2661 HKEY retval = NULL;
2662 LPWSTR buffer;
2663 const printenv_t * env;
2665 TRACE("(%s, %d)\n",
2666 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2668 if (!pEnvironment || unicode) {
2669 /* pEnvironment was NULL or a Unicode-String: use it direct */
2670 env = validate_envW(pEnvironment);
2672 else
2674 /* pEnvironment was an ANSI-String: convert to unicode first */
2675 LPWSTR buffer;
2676 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2677 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2678 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2679 env = validate_envW(buffer);
2680 HeapFree(GetProcessHeap(), 0, buffer);
2682 if (!env) return NULL;
2684 buffer = HeapAlloc( GetProcessHeap(), 0,
2685 (strlenW(DriversW) + strlenW(env->envname) +
2686 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2687 if(buffer) {
2688 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2689 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2690 HeapFree(GetProcessHeap(), 0, buffer);
2692 return retval;
2695 /*****************************************************************************
2696 * AddPrinterW [WINSPOOL.@]
2698 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2700 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2701 LPDEVMODEA dmA;
2702 LPDEVMODEW dmW;
2703 HANDLE retval;
2704 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2705 LONG size;
2706 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2707 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2708 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2709 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2710 statusW[] = {'S','t','a','t','u','s',0},
2711 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2713 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2715 if(pName != NULL) {
2716 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2717 SetLastError(ERROR_INVALID_PARAMETER);
2718 return 0;
2720 if(Level != 2) {
2721 ERR("Level = %d, unsupported!\n", Level);
2722 SetLastError(ERROR_INVALID_LEVEL);
2723 return 0;
2725 if(!pPrinter) {
2726 SetLastError(ERROR_INVALID_PARAMETER);
2727 return 0;
2729 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2730 ERROR_SUCCESS) {
2731 ERR("Can't create Printers key\n");
2732 return 0;
2734 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2735 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2736 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2737 RegCloseKey(hkeyPrinter);
2738 RegCloseKey(hkeyPrinters);
2739 return 0;
2741 RegCloseKey(hkeyPrinter);
2743 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2744 if(!hkeyDrivers) {
2745 ERR("Can't create Drivers key\n");
2746 RegCloseKey(hkeyPrinters);
2747 return 0;
2749 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2750 ERROR_SUCCESS) {
2751 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2752 RegCloseKey(hkeyPrinters);
2753 RegCloseKey(hkeyDrivers);
2754 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2755 return 0;
2757 RegCloseKey(hkeyDriver);
2758 RegCloseKey(hkeyDrivers);
2760 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2761 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2762 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2763 RegCloseKey(hkeyPrinters);
2764 return 0;
2767 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2768 ERROR_SUCCESS) {
2769 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2770 SetLastError(ERROR_INVALID_PRINTER_NAME);
2771 RegCloseKey(hkeyPrinters);
2772 return 0;
2774 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2775 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2776 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2778 /* See if we can load the driver. We may need the devmode structure anyway
2780 * FIXME:
2781 * Note that DocumentPropertiesW will briefly try to open the printer we
2782 * just create to find a DEVMODEA struct (it will use the WINEPS default
2783 * one in case it is not there, so we are ok).
2785 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2787 if(size < 0) {
2788 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2789 size = sizeof(DEVMODEW);
2791 if(pi->pDevMode)
2792 dmW = pi->pDevMode;
2793 else
2795 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2796 dmW->dmSize = size;
2797 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2799 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2800 HeapFree(GetProcessHeap(),0,dmW);
2801 dmW=NULL;
2803 else
2805 /* set devmode to printer name */
2806 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2810 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2811 and we support these drivers. NT writes DEVMODEW so somehow
2812 we'll need to distinguish between these when we support NT
2813 drivers */
2814 if (dmW)
2816 dmA = DEVMODEdupWtoA(dmW);
2817 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2818 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2819 HeapFree(GetProcessHeap(), 0, dmA);
2820 if(!pi->pDevMode)
2821 HeapFree(GetProcessHeap(), 0, dmW);
2823 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2824 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2825 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2826 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2828 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2829 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2830 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2831 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2832 (LPBYTE)&pi->Priority, sizeof(DWORD));
2833 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2834 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2835 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2836 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2837 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2838 (LPBYTE)&pi->Status, sizeof(DWORD));
2839 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2840 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2842 RegCloseKey(hkeyPrinter);
2843 RegCloseKey(hkeyPrinters);
2844 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2845 ERR("OpenPrinter failing\n");
2846 return 0;
2848 return retval;
2851 /*****************************************************************************
2852 * AddPrinterA [WINSPOOL.@]
2854 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2856 UNICODE_STRING pNameW;
2857 PWSTR pwstrNameW;
2858 PRINTER_INFO_2W *piW;
2859 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2860 HANDLE ret;
2862 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2863 if(Level != 2) {
2864 ERR("Level = %d, unsupported!\n", Level);
2865 SetLastError(ERROR_INVALID_LEVEL);
2866 return 0;
2868 pwstrNameW = asciitounicode(&pNameW,pName);
2869 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2871 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2873 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2874 RtlFreeUnicodeString(&pNameW);
2875 return ret;
2879 /*****************************************************************************
2880 * ClosePrinter [WINSPOOL.@]
2882 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2884 UINT_PTR i = (UINT_PTR)hPrinter;
2885 opened_printer_t *printer = NULL;
2886 BOOL ret = FALSE;
2888 TRACE("(%p)\n", hPrinter);
2890 EnterCriticalSection(&printer_handles_cs);
2892 if ((i > 0) && (i <= nb_printer_handles))
2893 printer = printer_handles[i - 1];
2896 if(printer)
2898 struct list *cursor, *cursor2;
2900 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2901 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2902 printer->hXcv, debugstr_w(printer->name), printer->doc );
2904 if (printer->backend_printer) {
2905 backend->fpClosePrinter(printer->backend_printer);
2908 if(printer->doc)
2909 EndDocPrinter(hPrinter);
2911 if(InterlockedDecrement(&printer->queue->ref) == 0)
2913 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2915 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2916 ScheduleJob(hPrinter, job->job_id);
2918 HeapFree(GetProcessHeap(), 0, printer->queue);
2920 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2921 monitor_unload(printer->pm);
2922 HeapFree(GetProcessHeap(), 0, printer->printername);
2923 HeapFree(GetProcessHeap(), 0, printer->name);
2924 HeapFree(GetProcessHeap(), 0, printer);
2925 printer_handles[i - 1] = NULL;
2926 ret = TRUE;
2928 LeaveCriticalSection(&printer_handles_cs);
2929 return ret;
2932 /*****************************************************************************
2933 * DeleteFormA [WINSPOOL.@]
2935 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2937 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2938 return 1;
2941 /*****************************************************************************
2942 * DeleteFormW [WINSPOOL.@]
2944 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2946 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2947 return 1;
2950 /*****************************************************************************
2951 * DeletePrinter [WINSPOOL.@]
2953 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2955 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2956 HKEY hkeyPrinters, hkey;
2958 if(!lpNameW) {
2959 SetLastError(ERROR_INVALID_HANDLE);
2960 return FALSE;
2962 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2963 RegDeleteTreeW(hkeyPrinters, lpNameW);
2964 RegCloseKey(hkeyPrinters);
2966 WriteProfileStringW(devicesW, lpNameW, NULL);
2967 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2969 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2970 RegDeleteValueW(hkey, lpNameW);
2971 RegCloseKey(hkey);
2974 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2975 RegDeleteValueW(hkey, lpNameW);
2976 RegCloseKey(hkey);
2978 return TRUE;
2981 /*****************************************************************************
2982 * SetPrinterA [WINSPOOL.@]
2984 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2985 DWORD Command)
2987 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2988 return FALSE;
2991 /*****************************************************************************
2992 * SetJobA [WINSPOOL.@]
2994 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2995 LPBYTE pJob, DWORD Command)
2997 BOOL ret;
2998 LPBYTE JobW;
2999 UNICODE_STRING usBuffer;
3001 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3003 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3004 are all ignored by SetJob, so we don't bother copying them */
3005 switch(Level)
3007 case 0:
3008 JobW = NULL;
3009 break;
3010 case 1:
3012 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3013 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3015 JobW = (LPBYTE)info1W;
3016 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3017 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3018 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3019 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3020 info1W->Status = info1A->Status;
3021 info1W->Priority = info1A->Priority;
3022 info1W->Position = info1A->Position;
3023 info1W->PagesPrinted = info1A->PagesPrinted;
3024 break;
3026 case 2:
3028 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3029 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3031 JobW = (LPBYTE)info2W;
3032 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3033 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3034 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3035 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3036 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3037 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3038 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3039 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3040 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3041 info2W->Status = info2A->Status;
3042 info2W->Priority = info2A->Priority;
3043 info2W->Position = info2A->Position;
3044 info2W->StartTime = info2A->StartTime;
3045 info2W->UntilTime = info2A->UntilTime;
3046 info2W->PagesPrinted = info2A->PagesPrinted;
3047 break;
3049 case 3:
3050 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3051 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3052 break;
3053 default:
3054 SetLastError(ERROR_INVALID_LEVEL);
3055 return FALSE;
3058 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3060 switch(Level)
3062 case 1:
3064 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3065 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3066 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3067 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3068 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3069 break;
3071 case 2:
3073 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3074 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3075 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3076 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3077 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3078 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3079 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3080 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3081 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3082 break;
3085 HeapFree(GetProcessHeap(), 0, JobW);
3087 return ret;
3090 /*****************************************************************************
3091 * SetJobW [WINSPOOL.@]
3093 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3094 LPBYTE pJob, DWORD Command)
3096 BOOL ret = FALSE;
3097 job_t *job;
3099 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3100 FIXME("Ignoring everything other than document title\n");
3102 EnterCriticalSection(&printer_handles_cs);
3103 job = get_job(hPrinter, JobId);
3104 if(!job)
3105 goto end;
3107 switch(Level)
3109 case 0:
3110 break;
3111 case 1:
3113 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3114 HeapFree(GetProcessHeap(), 0, job->document_title);
3115 job->document_title = strdupW(info1->pDocument);
3116 break;
3118 case 2:
3120 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3121 HeapFree(GetProcessHeap(), 0, job->document_title);
3122 job->document_title = strdupW(info2->pDocument);
3123 break;
3125 case 3:
3126 break;
3127 default:
3128 SetLastError(ERROR_INVALID_LEVEL);
3129 goto end;
3131 ret = TRUE;
3132 end:
3133 LeaveCriticalSection(&printer_handles_cs);
3134 return ret;
3137 /*****************************************************************************
3138 * EndDocPrinter [WINSPOOL.@]
3140 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3142 opened_printer_t *printer;
3143 BOOL ret = FALSE;
3144 TRACE("(%p)\n", hPrinter);
3146 EnterCriticalSection(&printer_handles_cs);
3148 printer = get_opened_printer(hPrinter);
3149 if(!printer)
3151 SetLastError(ERROR_INVALID_HANDLE);
3152 goto end;
3155 if(!printer->doc)
3157 SetLastError(ERROR_SPL_NO_STARTDOC);
3158 goto end;
3161 CloseHandle(printer->doc->hf);
3162 ScheduleJob(hPrinter, printer->doc->job_id);
3163 HeapFree(GetProcessHeap(), 0, printer->doc);
3164 printer->doc = NULL;
3165 ret = TRUE;
3166 end:
3167 LeaveCriticalSection(&printer_handles_cs);
3168 return ret;
3171 /*****************************************************************************
3172 * EndPagePrinter [WINSPOOL.@]
3174 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3176 FIXME("(%p): stub\n", hPrinter);
3177 return TRUE;
3180 /*****************************************************************************
3181 * StartDocPrinterA [WINSPOOL.@]
3183 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3185 UNICODE_STRING usBuffer;
3186 DOC_INFO_2W doc2W;
3187 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3188 DWORD ret;
3190 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3191 or one (DOC_INFO_3) extra DWORDs */
3193 switch(Level) {
3194 case 2:
3195 doc2W.JobId = doc2->JobId;
3196 /* fall through */
3197 case 3:
3198 doc2W.dwMode = doc2->dwMode;
3199 /* fall through */
3200 case 1:
3201 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3202 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3203 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3204 break;
3206 default:
3207 SetLastError(ERROR_INVALID_LEVEL);
3208 return FALSE;
3211 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3213 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3214 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3215 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3217 return ret;
3220 /*****************************************************************************
3221 * StartDocPrinterW [WINSPOOL.@]
3223 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3225 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3226 opened_printer_t *printer;
3227 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3228 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3229 JOB_INFO_1W job_info;
3230 DWORD needed, ret = 0;
3231 HANDLE hf;
3232 WCHAR *filename;
3234 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3235 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3236 debugstr_w(doc->pDatatype));
3238 if(Level < 1 || Level > 3)
3240 SetLastError(ERROR_INVALID_LEVEL);
3241 return 0;
3244 EnterCriticalSection(&printer_handles_cs);
3245 printer = get_opened_printer(hPrinter);
3246 if(!printer)
3248 SetLastError(ERROR_INVALID_HANDLE);
3249 goto end;
3252 if(printer->doc)
3254 SetLastError(ERROR_INVALID_PRINTER_STATE);
3255 goto end;
3258 /* Even if we're printing to a file we still add a print job, we'll
3259 just ignore the spool file name */
3261 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3263 ERR("AddJob failed gle %u\n", GetLastError());
3264 goto end;
3267 if(doc->pOutputFile)
3268 filename = doc->pOutputFile;
3269 else
3270 filename = addjob->Path;
3272 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3273 if(hf == INVALID_HANDLE_VALUE)
3274 goto end;
3276 memset(&job_info, 0, sizeof(job_info));
3277 job_info.pDocument = doc->pDocName;
3278 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3280 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3281 printer->doc->hf = hf;
3282 ret = printer->doc->job_id = addjob->JobId;
3283 end:
3284 LeaveCriticalSection(&printer_handles_cs);
3286 return ret;
3289 /*****************************************************************************
3290 * StartPagePrinter [WINSPOOL.@]
3292 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3294 FIXME("(%p): stub\n", hPrinter);
3295 return TRUE;
3298 /*****************************************************************************
3299 * GetFormA [WINSPOOL.@]
3301 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3302 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3304 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3305 Level,pForm,cbBuf,pcbNeeded);
3306 return FALSE;
3309 /*****************************************************************************
3310 * GetFormW [WINSPOOL.@]
3312 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3313 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3315 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3316 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3317 return FALSE;
3320 /*****************************************************************************
3321 * SetFormA [WINSPOOL.@]
3323 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3324 LPBYTE pForm)
3326 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3327 return FALSE;
3330 /*****************************************************************************
3331 * SetFormW [WINSPOOL.@]
3333 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3334 LPBYTE pForm)
3336 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3337 return FALSE;
3340 /*****************************************************************************
3341 * ReadPrinter [WINSPOOL.@]
3343 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3344 LPDWORD pNoBytesRead)
3346 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3347 return FALSE;
3350 /*****************************************************************************
3351 * ResetPrinterA [WINSPOOL.@]
3353 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3355 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3356 return FALSE;
3359 /*****************************************************************************
3360 * ResetPrinterW [WINSPOOL.@]
3362 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3364 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3365 return FALSE;
3368 /*****************************************************************************
3369 * WINSPOOL_GetDWORDFromReg
3371 * Return DWORD associated with ValueName from hkey.
3373 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3375 DWORD sz = sizeof(DWORD), type, value = 0;
3376 LONG ret;
3378 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3380 if(ret != ERROR_SUCCESS) {
3381 WARN("Got ret = %d on name %s\n", ret, ValueName);
3382 return 0;
3384 if(type != REG_DWORD) {
3385 ERR("Got type %d\n", type);
3386 return 0;
3388 return value;
3392 /*****************************************************************************
3393 * get_filename_from_reg [internal]
3395 * Get ValueName from hkey storing result in out
3396 * when the Value in the registry has only a filename, use driverdir as prefix
3397 * outlen is space left in out
3398 * String is stored either as unicode or ascii
3402 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3403 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3405 WCHAR filename[MAX_PATH];
3406 DWORD size;
3407 DWORD type;
3408 LONG ret;
3409 LPWSTR buffer = filename;
3410 LPWSTR ptr;
3412 *needed = 0;
3413 size = sizeof(filename);
3414 buffer[0] = '\0';
3415 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3416 if (ret == ERROR_MORE_DATA) {
3417 TRACE("need dynamic buffer: %u\n", size);
3418 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3419 if (!buffer) {
3420 /* No Memory is bad */
3421 return FALSE;
3423 buffer[0] = '\0';
3424 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3427 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3428 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3429 return FALSE;
3432 ptr = buffer;
3433 while (ptr) {
3434 /* do we have a full path ? */
3435 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3436 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3438 if (!ret) {
3439 /* we must build the full Path */
3440 *needed += dirlen;
3441 if ((out) && (outlen > dirlen)) {
3442 if (unicode) {
3443 lstrcpyW((LPWSTR)out, driverdir);
3445 else
3447 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3449 out += dirlen;
3450 outlen -= dirlen;
3452 else
3453 out = NULL;
3456 /* write the filename */
3457 if (unicode) {
3458 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3459 if ((out) && (outlen >= size)) {
3460 lstrcpyW((LPWSTR)out, ptr);
3461 out += size;
3462 outlen -= size;
3464 else
3465 out = NULL;
3467 else
3469 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3470 if ((out) && (outlen >= size)) {
3471 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3472 out += size;
3473 outlen -= size;
3475 else
3476 out = NULL;
3478 *needed += size;
3479 ptr += lstrlenW(ptr)+1;
3480 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3483 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3485 /* write the multisz-termination */
3486 if (type == REG_MULTI_SZ) {
3487 size = (unicode) ? sizeof(WCHAR) : 1;
3489 *needed += size;
3490 if (out && (outlen >= size)) {
3491 memset (out, 0, size);
3494 return TRUE;
3497 /*****************************************************************************
3498 * WINSPOOL_GetStringFromReg
3500 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3501 * String is stored either as unicode or ascii.
3502 * Bit of a hack here to get the ValueName if we want ascii.
3504 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3505 DWORD buflen, DWORD *needed,
3506 BOOL unicode)
3508 DWORD sz = buflen, type;
3509 LONG ret;
3511 if(unicode)
3512 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3513 else {
3514 LPSTR ValueNameA = strdupWtoA(ValueName);
3515 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3516 HeapFree(GetProcessHeap(),0,ValueNameA);
3518 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3519 WARN("Got ret = %d\n", ret);
3520 *needed = 0;
3521 return FALSE;
3523 /* add space for terminating '\0' */
3524 sz += unicode ? sizeof(WCHAR) : 1;
3525 *needed = sz;
3527 if (ptr)
3528 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3530 return TRUE;
3533 /*****************************************************************************
3534 * WINSPOOL_GetDefaultDevMode
3536 * Get a default DevMode values for wineps.
3537 * FIXME - use ppd.
3540 static void WINSPOOL_GetDefaultDevMode(
3541 LPBYTE ptr,
3542 DWORD buflen, DWORD *needed,
3543 BOOL unicode)
3545 DEVMODEA dm;
3546 static const char szwps[] = "wineps.drv";
3548 /* fill default DEVMODE - should be read from ppd... */
3549 ZeroMemory( &dm, sizeof(dm) );
3550 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3551 dm.dmSpecVersion = DM_SPECVERSION;
3552 dm.dmDriverVersion = 1;
3553 dm.dmSize = sizeof(DEVMODEA);
3554 dm.dmDriverExtra = 0;
3555 dm.dmFields =
3556 DM_ORIENTATION | DM_PAPERSIZE |
3557 DM_PAPERLENGTH | DM_PAPERWIDTH |
3558 DM_SCALE |
3559 DM_COPIES |
3560 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3561 DM_YRESOLUTION | DM_TTOPTION;
3563 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3564 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3565 dm.u1.s1.dmPaperLength = 2970;
3566 dm.u1.s1.dmPaperWidth = 2100;
3568 dm.u1.s1.dmScale = 100;
3569 dm.u1.s1.dmCopies = 1;
3570 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3571 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3572 /* dm.dmColor */
3573 /* dm.dmDuplex */
3574 dm.dmYResolution = 300; /* 300dpi */
3575 dm.dmTTOption = DMTT_BITMAP;
3576 /* dm.dmCollate */
3577 /* dm.dmFormName */
3578 /* dm.dmLogPixels */
3579 /* dm.dmBitsPerPel */
3580 /* dm.dmPelsWidth */
3581 /* dm.dmPelsHeight */
3582 /* dm.u2.dmDisplayFlags */
3583 /* dm.dmDisplayFrequency */
3584 /* dm.dmICMMethod */
3585 /* dm.dmICMIntent */
3586 /* dm.dmMediaType */
3587 /* dm.dmDitherType */
3588 /* dm.dmReserved1 */
3589 /* dm.dmReserved2 */
3590 /* dm.dmPanningWidth */
3591 /* dm.dmPanningHeight */
3593 if(unicode) {
3594 if(buflen >= sizeof(DEVMODEW)) {
3595 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3596 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3597 HeapFree(GetProcessHeap(),0,pdmW);
3599 *needed = sizeof(DEVMODEW);
3601 else
3603 if(buflen >= sizeof(DEVMODEA)) {
3604 memcpy(ptr, &dm, sizeof(DEVMODEA));
3606 *needed = sizeof(DEVMODEA);
3610 /*****************************************************************************
3611 * WINSPOOL_GetDevModeFromReg
3613 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3614 * DevMode is stored either as unicode or ascii.
3616 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3617 LPBYTE ptr,
3618 DWORD buflen, DWORD *needed,
3619 BOOL unicode)
3621 DWORD sz = buflen, type;
3622 LONG ret;
3624 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3625 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3626 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3627 if (sz < sizeof(DEVMODEA))
3629 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3630 return FALSE;
3632 /* ensures that dmSize is not erratically bogus if registry is invalid */
3633 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3634 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3635 if(unicode) {
3636 sz += (CCHDEVICENAME + CCHFORMNAME);
3637 if(buflen >= sz) {
3638 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3639 memcpy(ptr, dmW, sz);
3640 HeapFree(GetProcessHeap(),0,dmW);
3643 *needed = sz;
3644 return TRUE;
3647 /*********************************************************************
3648 * WINSPOOL_GetPrinter_1
3650 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3651 * The strings are either stored as unicode or ascii.
3653 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3654 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3655 BOOL unicode)
3657 DWORD size, left = cbBuf;
3658 BOOL space = (cbBuf > 0);
3659 LPBYTE ptr = buf;
3661 *pcbNeeded = 0;
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3664 unicode)) {
3665 if(space && size <= left) {
3666 pi1->pName = (LPWSTR)ptr;
3667 ptr += size;
3668 left -= size;
3669 } else
3670 space = FALSE;
3671 *pcbNeeded += size;
3674 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3675 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3676 unicode)) {
3677 if(space && size <= left) {
3678 pi1->pDescription = (LPWSTR)ptr;
3679 ptr += size;
3680 left -= size;
3681 } else
3682 space = FALSE;
3683 *pcbNeeded += size;
3686 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3687 unicode)) {
3688 if(space && size <= left) {
3689 pi1->pComment = (LPWSTR)ptr;
3690 ptr += size;
3691 left -= size;
3692 } else
3693 space = FALSE;
3694 *pcbNeeded += size;
3697 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3699 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3700 memset(pi1, 0, sizeof(*pi1));
3702 return space;
3704 /*********************************************************************
3705 * WINSPOOL_GetPrinter_2
3707 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3708 * The strings are either stored as unicode or ascii.
3710 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3711 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3712 BOOL unicode)
3714 DWORD size, left = cbBuf;
3715 BOOL space = (cbBuf > 0);
3716 LPBYTE ptr = buf;
3718 *pcbNeeded = 0;
3720 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3721 unicode)) {
3722 if(space && size <= left) {
3723 pi2->pPrinterName = (LPWSTR)ptr;
3724 ptr += size;
3725 left -= size;
3726 } else
3727 space = FALSE;
3728 *pcbNeeded += size;
3730 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3731 unicode)) {
3732 if(space && size <= left) {
3733 pi2->pShareName = (LPWSTR)ptr;
3734 ptr += size;
3735 left -= size;
3736 } else
3737 space = FALSE;
3738 *pcbNeeded += size;
3740 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3741 unicode)) {
3742 if(space && size <= left) {
3743 pi2->pPortName = (LPWSTR)ptr;
3744 ptr += size;
3745 left -= size;
3746 } else
3747 space = FALSE;
3748 *pcbNeeded += size;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3751 &size, unicode)) {
3752 if(space && size <= left) {
3753 pi2->pDriverName = (LPWSTR)ptr;
3754 ptr += size;
3755 left -= size;
3756 } else
3757 space = FALSE;
3758 *pcbNeeded += size;
3760 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3761 unicode)) {
3762 if(space && size <= left) {
3763 pi2->pComment = (LPWSTR)ptr;
3764 ptr += size;
3765 left -= size;
3766 } else
3767 space = FALSE;
3768 *pcbNeeded += size;
3770 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3771 unicode)) {
3772 if(space && size <= left) {
3773 pi2->pLocation = (LPWSTR)ptr;
3774 ptr += size;
3775 left -= size;
3776 } else
3777 space = FALSE;
3778 *pcbNeeded += size;
3780 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3781 &size, unicode)) {
3782 if(space && size <= left) {
3783 pi2->pDevMode = (LPDEVMODEW)ptr;
3784 ptr += size;
3785 left -= size;
3786 } else
3787 space = FALSE;
3788 *pcbNeeded += size;
3790 else
3792 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3793 if(space && size <= left) {
3794 pi2->pDevMode = (LPDEVMODEW)ptr;
3795 ptr += size;
3796 left -= size;
3797 } else
3798 space = FALSE;
3799 *pcbNeeded += size;
3801 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3802 &size, unicode)) {
3803 if(space && size <= left) {
3804 pi2->pSepFile = (LPWSTR)ptr;
3805 ptr += size;
3806 left -= size;
3807 } else
3808 space = FALSE;
3809 *pcbNeeded += size;
3811 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3812 &size, unicode)) {
3813 if(space && size <= left) {
3814 pi2->pPrintProcessor = (LPWSTR)ptr;
3815 ptr += size;
3816 left -= size;
3817 } else
3818 space = FALSE;
3819 *pcbNeeded += size;
3821 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3822 &size, unicode)) {
3823 if(space && size <= left) {
3824 pi2->pDatatype = (LPWSTR)ptr;
3825 ptr += size;
3826 left -= size;
3827 } else
3828 space = FALSE;
3829 *pcbNeeded += size;
3831 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3832 &size, unicode)) {
3833 if(space && size <= left) {
3834 pi2->pParameters = (LPWSTR)ptr;
3835 ptr += size;
3836 left -= size;
3837 } else
3838 space = FALSE;
3839 *pcbNeeded += size;
3841 if(pi2) {
3842 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3843 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3844 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3845 "Default Priority");
3846 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3847 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3850 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3851 memset(pi2, 0, sizeof(*pi2));
3853 return space;
3856 /*********************************************************************
3857 * WINSPOOL_GetPrinter_4
3859 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3861 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3862 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3863 BOOL unicode)
3865 DWORD size, left = cbBuf;
3866 BOOL space = (cbBuf > 0);
3867 LPBYTE ptr = buf;
3869 *pcbNeeded = 0;
3871 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3872 unicode)) {
3873 if(space && size <= left) {
3874 pi4->pPrinterName = (LPWSTR)ptr;
3875 ptr += size;
3876 left -= size;
3877 } else
3878 space = FALSE;
3879 *pcbNeeded += size;
3881 if(pi4) {
3882 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3885 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3886 memset(pi4, 0, sizeof(*pi4));
3888 return space;
3891 /*********************************************************************
3892 * WINSPOOL_GetPrinter_5
3894 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3896 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3897 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3898 BOOL unicode)
3900 DWORD size, left = cbBuf;
3901 BOOL space = (cbBuf > 0);
3902 LPBYTE ptr = buf;
3904 *pcbNeeded = 0;
3906 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3907 unicode)) {
3908 if(space && size <= left) {
3909 pi5->pPrinterName = (LPWSTR)ptr;
3910 ptr += size;
3911 left -= size;
3912 } else
3913 space = FALSE;
3914 *pcbNeeded += size;
3916 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3917 unicode)) {
3918 if(space && size <= left) {
3919 pi5->pPortName = (LPWSTR)ptr;
3920 ptr += size;
3921 left -= size;
3922 } else
3923 space = FALSE;
3924 *pcbNeeded += size;
3926 if(pi5) {
3927 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3928 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3929 "dnsTimeout");
3930 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3931 "txTimeout");
3934 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3935 memset(pi5, 0, sizeof(*pi5));
3937 return space;
3940 /*********************************************************************
3941 * WINSPOOL_GetPrinter_7
3943 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3945 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3946 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3948 DWORD size, left = cbBuf;
3949 BOOL space = (cbBuf > 0);
3950 LPBYTE ptr = buf;
3952 *pcbNeeded = 0;
3954 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3956 if (space && size <= left) {
3957 pi7->pszObjectGUID = (LPWSTR)ptr;
3958 ptr += size;
3959 left -= size;
3960 } else
3961 space = FALSE;
3962 *pcbNeeded += size;
3964 if (pi7) {
3965 /* We do not have a Directory Service */
3966 pi7->dwAction = DSPRINT_UNPUBLISH;
3969 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3970 memset(pi7, 0, sizeof(*pi7));
3972 return space;
3975 /*********************************************************************
3976 * WINSPOOL_GetPrinter_9
3978 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3979 * The strings are either stored as unicode or ascii.
3981 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3982 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3984 DWORD size;
3985 BOOL space = (cbBuf > 0);
3987 *pcbNeeded = 0;
3989 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3990 if(space && size <= cbBuf) {
3991 pi9->pDevMode = (LPDEVMODEW)buf;
3992 } else
3993 space = FALSE;
3994 *pcbNeeded += size;
3996 else
3998 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3999 if(space && size <= cbBuf) {
4000 pi9->pDevMode = (LPDEVMODEW)buf;
4001 } else
4002 space = FALSE;
4003 *pcbNeeded += size;
4006 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4007 memset(pi9, 0, sizeof(*pi9));
4009 return space;
4012 /*****************************************************************************
4013 * WINSPOOL_GetPrinter
4015 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4016 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4017 * just a collection of pointers to strings.
4019 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4020 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4022 LPCWSTR name;
4023 DWORD size, needed = 0;
4024 LPBYTE ptr = NULL;
4025 HKEY hkeyPrinter, hkeyPrinters;
4026 BOOL ret;
4028 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4030 if (!(name = get_opened_printer_name(hPrinter))) {
4031 SetLastError(ERROR_INVALID_HANDLE);
4032 return FALSE;
4035 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4036 ERROR_SUCCESS) {
4037 ERR("Can't create Printers key\n");
4038 return FALSE;
4040 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4042 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4043 RegCloseKey(hkeyPrinters);
4044 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4045 return FALSE;
4048 switch(Level) {
4049 case 2:
4051 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4053 size = sizeof(PRINTER_INFO_2W);
4054 if(size <= cbBuf) {
4055 ptr = pPrinter + size;
4056 cbBuf -= size;
4057 memset(pPrinter, 0, size);
4058 } else {
4059 pi2 = NULL;
4060 cbBuf = 0;
4062 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4063 unicode);
4064 needed += size;
4065 break;
4068 case 4:
4070 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4072 size = sizeof(PRINTER_INFO_4W);
4073 if(size <= cbBuf) {
4074 ptr = pPrinter + size;
4075 cbBuf -= size;
4076 memset(pPrinter, 0, size);
4077 } else {
4078 pi4 = NULL;
4079 cbBuf = 0;
4081 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4082 unicode);
4083 needed += size;
4084 break;
4088 case 5:
4090 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4092 size = sizeof(PRINTER_INFO_5W);
4093 if(size <= cbBuf) {
4094 ptr = pPrinter + size;
4095 cbBuf -= size;
4096 memset(pPrinter, 0, size);
4097 } else {
4098 pi5 = NULL;
4099 cbBuf = 0;
4102 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4103 unicode);
4104 needed += size;
4105 break;
4109 case 6:
4111 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4113 size = sizeof(PRINTER_INFO_6);
4114 if (size <= cbBuf) {
4115 /* FIXME: We do not update the status yet */
4116 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4117 ret = TRUE;
4118 } else {
4119 ret = FALSE;
4122 needed += size;
4123 break;
4126 case 7:
4128 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4130 size = sizeof(PRINTER_INFO_7W);
4131 if (size <= cbBuf) {
4132 ptr = pPrinter + size;
4133 cbBuf -= size;
4134 memset(pPrinter, 0, size);
4135 } else {
4136 pi7 = NULL;
4137 cbBuf = 0;
4140 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4141 needed += size;
4142 break;
4146 case 9:
4148 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4150 size = sizeof(PRINTER_INFO_9W);
4151 if(size <= cbBuf) {
4152 ptr = pPrinter + size;
4153 cbBuf -= size;
4154 memset(pPrinter, 0, size);
4155 } else {
4156 pi9 = NULL;
4157 cbBuf = 0;
4160 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4161 needed += size;
4162 break;
4166 default:
4167 FIXME("Unimplemented level %d\n", Level);
4168 SetLastError(ERROR_INVALID_LEVEL);
4169 RegCloseKey(hkeyPrinters);
4170 RegCloseKey(hkeyPrinter);
4171 return FALSE;
4174 RegCloseKey(hkeyPrinter);
4175 RegCloseKey(hkeyPrinters);
4177 TRACE("returning %d needed = %d\n", ret, needed);
4178 if(pcbNeeded) *pcbNeeded = needed;
4179 if(!ret)
4180 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4181 return ret;
4184 /*****************************************************************************
4185 * GetPrinterW [WINSPOOL.@]
4187 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4188 DWORD cbBuf, LPDWORD pcbNeeded)
4190 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4191 TRUE);
4194 /*****************************************************************************
4195 * GetPrinterA [WINSPOOL.@]
4197 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4198 DWORD cbBuf, LPDWORD pcbNeeded)
4200 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4201 FALSE);
4204 /*****************************************************************************
4205 * WINSPOOL_EnumPrinters
4207 * Implementation of EnumPrintersA|W
4209 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4210 DWORD dwLevel, LPBYTE lpbPrinters,
4211 DWORD cbBuf, LPDWORD lpdwNeeded,
4212 LPDWORD lpdwReturned, BOOL unicode)
4215 HKEY hkeyPrinters, hkeyPrinter;
4216 WCHAR PrinterName[255];
4217 DWORD needed = 0, number = 0;
4218 DWORD used, i, left;
4219 PBYTE pi, buf;
4221 if(lpbPrinters)
4222 memset(lpbPrinters, 0, cbBuf);
4223 if(lpdwReturned)
4224 *lpdwReturned = 0;
4225 if(lpdwNeeded)
4226 *lpdwNeeded = 0;
4228 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4229 if(dwType == PRINTER_ENUM_DEFAULT)
4230 return TRUE;
4232 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4233 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4234 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4235 if (!dwType) {
4236 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4237 *lpdwNeeded = 0;
4238 *lpdwReturned = 0;
4239 return TRUE;
4244 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4245 FIXME("dwType = %08x\n", dwType);
4246 SetLastError(ERROR_INVALID_FLAGS);
4247 return FALSE;
4250 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4251 ERROR_SUCCESS) {
4252 ERR("Can't create Printers key\n");
4253 return FALSE;
4256 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4257 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4258 RegCloseKey(hkeyPrinters);
4259 ERR("Can't query Printers key\n");
4260 return FALSE;
4262 TRACE("Found %d printers\n", number);
4264 switch(dwLevel) {
4265 case 1:
4266 used = number * sizeof(PRINTER_INFO_1W);
4267 break;
4268 case 2:
4269 used = number * sizeof(PRINTER_INFO_2W);
4270 break;
4271 case 4:
4272 used = number * sizeof(PRINTER_INFO_4W);
4273 break;
4274 case 5:
4275 used = number * sizeof(PRINTER_INFO_5W);
4276 break;
4278 default:
4279 SetLastError(ERROR_INVALID_LEVEL);
4280 RegCloseKey(hkeyPrinters);
4281 return FALSE;
4283 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4285 for(i = 0; i < number; i++) {
4286 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4287 ERROR_SUCCESS) {
4288 ERR("Can't enum key number %d\n", i);
4289 RegCloseKey(hkeyPrinters);
4290 return FALSE;
4292 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4293 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4294 ERROR_SUCCESS) {
4295 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4296 RegCloseKey(hkeyPrinters);
4297 return FALSE;
4300 if(cbBuf > used) {
4301 buf = lpbPrinters + used;
4302 left = cbBuf - used;
4303 } else {
4304 buf = NULL;
4305 left = 0;
4308 switch(dwLevel) {
4309 case 1:
4310 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4311 left, &needed, unicode);
4312 used += needed;
4313 if(pi) pi += sizeof(PRINTER_INFO_1W);
4314 break;
4315 case 2:
4316 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4317 left, &needed, unicode);
4318 used += needed;
4319 if(pi) pi += sizeof(PRINTER_INFO_2W);
4320 break;
4321 case 4:
4322 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4323 left, &needed, unicode);
4324 used += needed;
4325 if(pi) pi += sizeof(PRINTER_INFO_4W);
4326 break;
4327 case 5:
4328 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4329 left, &needed, unicode);
4330 used += needed;
4331 if(pi) pi += sizeof(PRINTER_INFO_5W);
4332 break;
4333 default:
4334 ERR("Shouldn't be here!\n");
4335 RegCloseKey(hkeyPrinter);
4336 RegCloseKey(hkeyPrinters);
4337 return FALSE;
4339 RegCloseKey(hkeyPrinter);
4341 RegCloseKey(hkeyPrinters);
4343 if(lpdwNeeded)
4344 *lpdwNeeded = used;
4346 if(used > cbBuf) {
4347 if(lpbPrinters)
4348 memset(lpbPrinters, 0, cbBuf);
4349 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4350 return FALSE;
4352 if(lpdwReturned)
4353 *lpdwReturned = number;
4354 SetLastError(ERROR_SUCCESS);
4355 return TRUE;
4359 /******************************************************************
4360 * EnumPrintersW [WINSPOOL.@]
4362 * Enumerates the available printers, print servers and print
4363 * providers, depending on the specified flags, name and level.
4365 * RETURNS:
4367 * If level is set to 1:
4368 * Returns an array of PRINTER_INFO_1 data structures in the
4369 * lpbPrinters buffer.
4371 * If level is set to 2:
4372 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4373 * Returns an array of PRINTER_INFO_2 data structures in the
4374 * lpbPrinters buffer. Note that according to MSDN also an
4375 * OpenPrinter should be performed on every remote printer.
4377 * If level is set to 4 (officially WinNT only):
4378 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4379 * Fast: Only the registry is queried to retrieve printer names,
4380 * no connection to the driver is made.
4381 * Returns an array of PRINTER_INFO_4 data structures in the
4382 * lpbPrinters buffer.
4384 * If level is set to 5 (officially WinNT4/Win9x only):
4385 * Fast: Only the registry is queried to retrieve printer names,
4386 * no connection to the driver is made.
4387 * Returns an array of PRINTER_INFO_5 data structures in the
4388 * lpbPrinters buffer.
4390 * If level set to 3 or 6+:
4391 * returns zero (failure!)
4393 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4394 * for information.
4396 * BUGS:
4397 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4398 * - Only levels 2, 4 and 5 are implemented at the moment.
4399 * - 16-bit printer drivers are not enumerated.
4400 * - Returned amount of bytes used/needed does not match the real Windoze
4401 * implementation (as in this implementation, all strings are part
4402 * of the buffer, whereas Win32 keeps them somewhere else)
4403 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4405 * NOTE:
4406 * - In a regular Wine installation, no registry settings for printers
4407 * exist, which makes this function return an empty list.
4409 BOOL WINAPI EnumPrintersW(
4410 DWORD dwType, /* [in] Types of print objects to enumerate */
4411 LPWSTR lpszName, /* [in] name of objects to enumerate */
4412 DWORD dwLevel, /* [in] type of printer info structure */
4413 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4414 DWORD cbBuf, /* [in] max size of buffer in bytes */
4415 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4416 LPDWORD lpdwReturned /* [out] number of entries returned */
4419 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4420 lpdwNeeded, lpdwReturned, TRUE);
4423 /******************************************************************
4424 * EnumPrintersA [WINSPOOL.@]
4426 * See EnumPrintersW
4429 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4430 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4432 BOOL ret;
4433 UNICODE_STRING pNameU;
4434 LPWSTR pNameW;
4435 LPBYTE pPrintersW;
4437 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4438 pPrinters, cbBuf, pcbNeeded, pcReturned);
4440 pNameW = asciitounicode(&pNameU, pName);
4442 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4443 MS Office need this */
4444 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4446 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4448 RtlFreeUnicodeString(&pNameU);
4449 if (ret) {
4450 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4452 HeapFree(GetProcessHeap(), 0, pPrintersW);
4453 return ret;
4456 /*****************************************************************************
4457 * WINSPOOL_GetDriverInfoFromReg [internal]
4459 * Enters the information from the registry into the DRIVER_INFO struct
4461 * RETURNS
4462 * zero if the printer driver does not exist in the registry
4463 * (only if Level > 1) otherwise nonzero
4465 static BOOL WINSPOOL_GetDriverInfoFromReg(
4466 HKEY hkeyDrivers,
4467 LPWSTR DriverName,
4468 const printenv_t * env,
4469 DWORD Level,
4470 LPBYTE ptr, /* DRIVER_INFO */
4471 LPBYTE pDriverStrings, /* strings buffer */
4472 DWORD cbBuf, /* size of string buffer */
4473 LPDWORD pcbNeeded, /* space needed for str. */
4474 BOOL unicode) /* type of strings */
4476 DWORD size, tmp;
4477 HKEY hkeyDriver;
4478 WCHAR driverdir[MAX_PATH];
4479 DWORD dirlen;
4480 LPBYTE strPtr = pDriverStrings;
4481 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4483 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4484 debugstr_w(DriverName), env,
4485 Level, di, pDriverStrings, cbBuf, unicode);
4487 if (di) ZeroMemory(di, di_sizeof[Level]);
4489 if (unicode) {
4490 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4491 if (*pcbNeeded <= cbBuf)
4492 strcpyW((LPWSTR)strPtr, DriverName);
4494 else
4496 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4497 if (*pcbNeeded <= cbBuf)
4498 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4501 /* pName for level 1 has a different offset! */
4502 if (Level == 1) {
4503 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4504 return TRUE;
4507 /* .cVersion and .pName for level > 1 */
4508 if (di) {
4509 di->cVersion = env->driverversion;
4510 di->pName = (LPWSTR) strPtr;
4511 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4514 /* Reserve Space for the largest subdir and a Backslash*/
4515 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4516 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4517 /* Should never Fail */
4518 return FALSE;
4520 lstrcatW(driverdir, env->versionsubdir);
4521 lstrcatW(driverdir, backslashW);
4523 /* dirlen must not include the terminating zero */
4524 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4525 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4527 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4528 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4529 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4530 return FALSE;
4533 /* pEnvironment */
4534 if (unicode)
4535 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4536 else
4537 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4539 *pcbNeeded += size;
4540 if (*pcbNeeded <= cbBuf) {
4541 if (unicode) {
4542 lstrcpyW((LPWSTR)strPtr, env->envname);
4544 else
4546 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4548 if (di) di->pEnvironment = (LPWSTR)strPtr;
4549 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4552 /* .pDriverPath is the Graphics rendering engine.
4553 The full Path is required to avoid a crash in some apps */
4554 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4555 *pcbNeeded += size;
4556 if (*pcbNeeded <= cbBuf)
4557 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4559 if (di) di->pDriverPath = (LPWSTR)strPtr;
4560 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4563 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4564 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4565 *pcbNeeded += size;
4566 if (*pcbNeeded <= cbBuf)
4567 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4569 if (di) di->pDataFile = (LPWSTR)strPtr;
4570 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4573 /* .pConfigFile is the Driver user Interface */
4574 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4575 *pcbNeeded += size;
4576 if (*pcbNeeded <= cbBuf)
4577 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4579 if (di) di->pConfigFile = (LPWSTR)strPtr;
4580 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4583 if (Level == 2 ) {
4584 RegCloseKey(hkeyDriver);
4585 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4586 return TRUE;
4589 if (Level == 5 ) {
4590 RegCloseKey(hkeyDriver);
4591 FIXME("level 5: incomplete\n");
4592 return TRUE;
4595 /* .pHelpFile */
4596 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4597 *pcbNeeded += size;
4598 if (*pcbNeeded <= cbBuf)
4599 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4601 if (di) di->pHelpFile = (LPWSTR)strPtr;
4602 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4605 /* .pDependentFiles */
4606 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4607 *pcbNeeded += size;
4608 if (*pcbNeeded <= cbBuf)
4609 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4611 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4614 else if (GetVersion() & 0x80000000) {
4615 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4616 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4617 *pcbNeeded += size;
4618 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4620 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4621 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4624 /* .pMonitorName is the optional Language Monitor */
4625 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4626 *pcbNeeded += size;
4627 if (*pcbNeeded <= cbBuf)
4628 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4630 if (di) di->pMonitorName = (LPWSTR)strPtr;
4631 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4634 /* .pDefaultDataType */
4635 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4636 *pcbNeeded += size;
4637 if(*pcbNeeded <= cbBuf)
4638 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4640 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4641 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4644 if (Level == 3 ) {
4645 RegCloseKey(hkeyDriver);
4646 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4647 return TRUE;
4650 /* .pszzPreviousNames */
4651 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4652 *pcbNeeded += size;
4653 if(*pcbNeeded <= cbBuf)
4654 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4656 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4657 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4660 if (Level == 4 ) {
4661 RegCloseKey(hkeyDriver);
4662 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4663 return TRUE;
4666 /* support is missing, but not important enough for a FIXME */
4667 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4669 /* .pszMfgName */
4670 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4671 *pcbNeeded += size;
4672 if(*pcbNeeded <= cbBuf)
4673 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4675 if (di) di->pszMfgName = (LPWSTR)strPtr;
4676 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4679 /* .pszOEMUrl */
4680 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4681 *pcbNeeded += size;
4682 if(*pcbNeeded <= cbBuf)
4683 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4685 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4686 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4689 /* .pszHardwareID */
4690 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4691 *pcbNeeded += size;
4692 if(*pcbNeeded <= cbBuf)
4693 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4695 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4696 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4699 /* .pszProvider */
4700 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4701 *pcbNeeded += size;
4702 if(*pcbNeeded <= cbBuf)
4703 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4705 if (di) di->pszProvider = (LPWSTR)strPtr;
4706 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4709 if (Level == 6 ) {
4710 RegCloseKey(hkeyDriver);
4711 return TRUE;
4714 /* support is missing, but not important enough for a FIXME */
4715 TRACE("level 8: incomplete\n");
4717 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4718 RegCloseKey(hkeyDriver);
4719 return TRUE;
4722 /*****************************************************************************
4723 * WINSPOOL_GetPrinterDriver
4725 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4726 DWORD Level, LPBYTE pDriverInfo,
4727 DWORD cbBuf, LPDWORD pcbNeeded,
4728 BOOL unicode)
4730 LPCWSTR name;
4731 WCHAR DriverName[100];
4732 DWORD ret, type, size, needed = 0;
4733 LPBYTE ptr = NULL;
4734 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4735 const printenv_t * env;
4737 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4738 Level,pDriverInfo,cbBuf, pcbNeeded);
4741 if (!(name = get_opened_printer_name(hPrinter))) {
4742 SetLastError(ERROR_INVALID_HANDLE);
4743 return FALSE;
4746 if (Level < 1 || Level == 7 || Level > 8) {
4747 SetLastError(ERROR_INVALID_LEVEL);
4748 return FALSE;
4751 env = validate_envW(pEnvironment);
4752 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4754 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4755 ERROR_SUCCESS) {
4756 ERR("Can't create Printers key\n");
4757 return FALSE;
4759 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4760 != ERROR_SUCCESS) {
4761 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4762 RegCloseKey(hkeyPrinters);
4763 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4764 return FALSE;
4766 size = sizeof(DriverName);
4767 DriverName[0] = 0;
4768 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4769 (LPBYTE)DriverName, &size);
4770 RegCloseKey(hkeyPrinter);
4771 RegCloseKey(hkeyPrinters);
4772 if(ret != ERROR_SUCCESS) {
4773 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4774 return FALSE;
4777 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4778 if(!hkeyDrivers) {
4779 ERR("Can't create Drivers key\n");
4780 return FALSE;
4783 size = di_sizeof[Level];
4784 if ((size <= cbBuf) && pDriverInfo)
4785 ptr = pDriverInfo + size;
4787 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4788 env, Level, pDriverInfo, ptr,
4789 (cbBuf < size) ? 0 : cbBuf - size,
4790 &needed, unicode)) {
4791 RegCloseKey(hkeyDrivers);
4792 return FALSE;
4795 RegCloseKey(hkeyDrivers);
4797 if(pcbNeeded) *pcbNeeded = size + needed;
4798 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4799 if(cbBuf >= needed) return TRUE;
4800 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4801 return FALSE;
4804 /*****************************************************************************
4805 * GetPrinterDriverA [WINSPOOL.@]
4807 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4808 DWORD Level, LPBYTE pDriverInfo,
4809 DWORD cbBuf, LPDWORD pcbNeeded)
4811 BOOL ret;
4812 UNICODE_STRING pEnvW;
4813 PWSTR pwstrEnvW;
4815 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4816 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4817 cbBuf, pcbNeeded, FALSE);
4818 RtlFreeUnicodeString(&pEnvW);
4819 return ret;
4821 /*****************************************************************************
4822 * GetPrinterDriverW [WINSPOOL.@]
4824 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4825 DWORD Level, LPBYTE pDriverInfo,
4826 DWORD cbBuf, LPDWORD pcbNeeded)
4828 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4829 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4832 /*****************************************************************************
4833 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4835 * Return the PATH for the Printer-Drivers (UNICODE)
4837 * PARAMS
4838 * pName [I] Servername (NT only) or NULL (local Computer)
4839 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4840 * Level [I] Structure-Level (must be 1)
4841 * pDriverDirectory [O] PTR to Buffer that receives the Result
4842 * cbBuf [I] Size of Buffer at pDriverDirectory
4843 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4844 * required for pDriverDirectory
4846 * RETURNS
4847 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4848 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4849 * if cbBuf is too small
4851 * Native Values returned in pDriverDirectory on Success:
4852 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4853 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4854 *| win9x(Windows 4.0): "%winsysdir%"
4856 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4858 * FIXME
4859 *- Only NULL or "" is supported for pName
4862 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4863 DWORD Level, LPBYTE pDriverDirectory,
4864 DWORD cbBuf, LPDWORD pcbNeeded)
4866 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4867 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4869 if ((backend == NULL) && !load_backend()) return FALSE;
4871 if (Level != 1) {
4872 /* (Level != 1) is ignored in win9x */
4873 SetLastError(ERROR_INVALID_LEVEL);
4874 return FALSE;
4876 if (pcbNeeded == NULL) {
4877 /* (pcbNeeded == NULL) is ignored in win9x */
4878 SetLastError(RPC_X_NULL_REF_POINTER);
4879 return FALSE;
4882 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4883 pDriverDirectory, cbBuf, pcbNeeded);
4888 /*****************************************************************************
4889 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4891 * Return the PATH for the Printer-Drivers (ANSI)
4893 * See GetPrinterDriverDirectoryW.
4895 * NOTES
4896 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4899 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4900 DWORD Level, LPBYTE pDriverDirectory,
4901 DWORD cbBuf, LPDWORD pcbNeeded)
4903 UNICODE_STRING nameW, environmentW;
4904 BOOL ret;
4905 DWORD pcbNeededW;
4906 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4907 WCHAR *driverDirectoryW = NULL;
4909 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4910 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4912 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4914 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4915 else nameW.Buffer = NULL;
4916 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4917 else environmentW.Buffer = NULL;
4919 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4920 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4921 if (ret) {
4922 DWORD needed;
4923 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4924 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4925 if(pcbNeeded)
4926 *pcbNeeded = needed;
4927 ret = (needed <= cbBuf) ? TRUE : FALSE;
4928 } else
4929 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4931 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4933 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4934 RtlFreeUnicodeString(&environmentW);
4935 RtlFreeUnicodeString(&nameW);
4937 return ret;
4940 /*****************************************************************************
4941 * AddPrinterDriverA [WINSPOOL.@]
4943 * See AddPrinterDriverW.
4946 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4948 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4949 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4952 /******************************************************************************
4953 * AddPrinterDriverW (WINSPOOL.@)
4955 * Install a Printer Driver
4957 * PARAMS
4958 * pName [I] Servername or NULL (local Computer)
4959 * level [I] Level for the supplied DRIVER_INFO_*W struct
4960 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4962 * RESULTS
4963 * Success: TRUE
4964 * Failure: FALSE
4967 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4969 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4970 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4973 /*****************************************************************************
4974 * AddPrintProcessorA [WINSPOOL.@]
4976 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4977 LPSTR pPrintProcessorName)
4979 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4980 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4981 return FALSE;
4984 /*****************************************************************************
4985 * AddPrintProcessorW [WINSPOOL.@]
4987 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4988 LPWSTR pPrintProcessorName)
4990 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4991 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4992 return FALSE;
4995 /*****************************************************************************
4996 * AddPrintProvidorA [WINSPOOL.@]
4998 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5000 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5001 return FALSE;
5004 /*****************************************************************************
5005 * AddPrintProvidorW [WINSPOOL.@]
5007 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5009 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5010 return FALSE;
5013 /*****************************************************************************
5014 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5016 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5017 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5019 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5020 pDevModeOutput, pDevModeInput);
5021 return 0;
5024 /*****************************************************************************
5025 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5027 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5028 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5030 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5031 pDevModeOutput, pDevModeInput);
5032 return 0;
5035 /*****************************************************************************
5036 * PrinterProperties [WINSPOOL.@]
5038 * Displays a dialog to set the properties of the printer.
5040 * RETURNS
5041 * nonzero on success or zero on failure
5043 * BUGS
5044 * implemented as stub only
5046 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5047 HANDLE hPrinter /* [in] handle to printer object */
5049 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5050 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5051 return FALSE;
5054 /*****************************************************************************
5055 * EnumJobsA [WINSPOOL.@]
5058 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5059 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5060 LPDWORD pcReturned)
5062 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5063 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5065 if(pcbNeeded) *pcbNeeded = 0;
5066 if(pcReturned) *pcReturned = 0;
5067 return FALSE;
5071 /*****************************************************************************
5072 * EnumJobsW [WINSPOOL.@]
5075 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5076 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5077 LPDWORD pcReturned)
5079 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5080 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5082 if(pcbNeeded) *pcbNeeded = 0;
5083 if(pcReturned) *pcReturned = 0;
5084 return FALSE;
5087 /*****************************************************************************
5088 * WINSPOOL_EnumPrinterDrivers [internal]
5090 * Delivers information about all printer drivers installed on the
5091 * localhost or a given server
5093 * RETURNS
5094 * nonzero on success or zero on failure. If the buffer for the returned
5095 * information is too small the function will return an error
5097 * BUGS
5098 * - only implemented for localhost, foreign hosts will return an error
5100 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5101 DWORD Level, LPBYTE pDriverInfo,
5102 DWORD cbBuf, LPDWORD pcbNeeded,
5103 LPDWORD pcReturned, BOOL unicode)
5105 { HKEY hkeyDrivers;
5106 DWORD i, needed, number = 0, size = 0;
5107 WCHAR DriverNameW[255];
5108 PBYTE ptr;
5109 const printenv_t * env;
5111 TRACE("%s,%s,%d,%p,%d,%d\n",
5112 debugstr_w(pName), debugstr_w(pEnvironment),
5113 Level, pDriverInfo, cbBuf, unicode);
5115 /* check for local drivers */
5116 if((pName) && (pName[0])) {
5117 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5118 SetLastError(ERROR_ACCESS_DENIED);
5119 return FALSE;
5122 env = validate_envW(pEnvironment);
5123 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5125 /* check input parameter */
5126 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5127 SetLastError(ERROR_INVALID_LEVEL);
5128 return FALSE;
5131 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5132 SetLastError(RPC_X_NULL_REF_POINTER);
5133 return FALSE;
5136 /* initialize return values */
5137 if(pDriverInfo)
5138 memset( pDriverInfo, 0, cbBuf);
5139 *pcbNeeded = 0;
5140 *pcReturned = 0;
5142 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5143 if(!hkeyDrivers) {
5144 ERR("Can't open Drivers key\n");
5145 return FALSE;
5148 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5149 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5150 RegCloseKey(hkeyDrivers);
5151 ERR("Can't query Drivers key\n");
5152 return FALSE;
5154 TRACE("Found %d Drivers\n", number);
5156 /* get size of single struct
5157 * unicode and ascii structure have the same size
5159 size = di_sizeof[Level];
5161 /* calculate required buffer size */
5162 *pcbNeeded = size * number;
5164 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5165 i < number;
5166 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5167 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5168 != ERROR_SUCCESS) {
5169 ERR("Can't enum key number %d\n", i);
5170 RegCloseKey(hkeyDrivers);
5171 return FALSE;
5173 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5174 env, Level, ptr,
5175 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5176 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5177 &needed, unicode)) {
5178 RegCloseKey(hkeyDrivers);
5179 return FALSE;
5181 *pcbNeeded += needed;
5184 RegCloseKey(hkeyDrivers);
5186 if(cbBuf < *pcbNeeded){
5187 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5188 return FALSE;
5191 *pcReturned = number;
5192 return TRUE;
5195 /*****************************************************************************
5196 * EnumPrinterDriversW [WINSPOOL.@]
5198 * see function EnumPrinterDrivers for RETURNS, BUGS
5200 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5201 LPBYTE pDriverInfo, DWORD cbBuf,
5202 LPDWORD pcbNeeded, LPDWORD pcReturned)
5204 static const WCHAR allW[] = {'a','l','l',0};
5206 if (pEnvironment && !strcmpW(pEnvironment, allW))
5208 BOOL ret;
5209 DWORD i, needed, returned, bufsize = cbBuf;
5211 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5213 needed = returned = 0;
5214 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5215 pDriverInfo, bufsize, &needed, &returned, TRUE);
5216 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5217 else if (ret)
5219 bufsize -= needed;
5220 if (pDriverInfo) pDriverInfo += needed;
5221 if (pcReturned) *pcReturned += returned;
5223 if (pcbNeeded) *pcbNeeded += needed;
5225 return ret;
5227 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5228 cbBuf, pcbNeeded, pcReturned, TRUE);
5231 /*****************************************************************************
5232 * EnumPrinterDriversA [WINSPOOL.@]
5234 * see function EnumPrinterDrivers for RETURNS, BUGS
5236 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5237 LPBYTE pDriverInfo, DWORD cbBuf,
5238 LPDWORD pcbNeeded, LPDWORD pcReturned)
5240 BOOL ret;
5241 UNICODE_STRING pNameW, pEnvironmentW;
5242 PWSTR pwstrNameW, pwstrEnvironmentW;
5244 pwstrNameW = asciitounicode(&pNameW, pName);
5245 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5247 if (pEnvironment && !strcmp(pEnvironment, "all"))
5249 DWORD i, needed, returned, bufsize = cbBuf;
5251 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5253 needed = returned = 0;
5254 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
5255 pDriverInfo, bufsize, &needed, &returned, FALSE);
5256 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
5257 else if (ret)
5259 bufsize -= needed;
5260 if (pDriverInfo) pDriverInfo += needed;
5261 if (pcReturned) *pcReturned += returned;
5263 if (pcbNeeded) *pcbNeeded += needed;
5266 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5267 Level, pDriverInfo, cbBuf, pcbNeeded,
5268 pcReturned, FALSE);
5269 RtlFreeUnicodeString(&pNameW);
5270 RtlFreeUnicodeString(&pEnvironmentW);
5272 return ret;
5275 /******************************************************************************
5276 * EnumPortsA (WINSPOOL.@)
5278 * See EnumPortsW.
5281 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5282 LPDWORD pcbNeeded, LPDWORD pcReturned)
5284 BOOL res;
5285 LPBYTE bufferW = NULL;
5286 LPWSTR nameW = NULL;
5287 DWORD needed = 0;
5288 DWORD numentries = 0;
5289 INT len;
5291 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5292 cbBuf, pcbNeeded, pcReturned);
5294 /* convert servername to unicode */
5295 if (pName) {
5296 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5297 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5298 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5300 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5301 needed = cbBuf * sizeof(WCHAR);
5302 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5303 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5305 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5306 if (pcbNeeded) needed = *pcbNeeded;
5307 /* HeapReAlloc return NULL, when bufferW was NULL */
5308 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5309 HeapAlloc(GetProcessHeap(), 0, needed);
5311 /* Try again with the large Buffer */
5312 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5314 needed = pcbNeeded ? *pcbNeeded : 0;
5315 numentries = pcReturned ? *pcReturned : 0;
5318 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5319 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5321 if (res) {
5322 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5323 DWORD entrysize = 0;
5324 DWORD index;
5325 LPSTR ptr;
5326 LPPORT_INFO_2W pi2w;
5327 LPPORT_INFO_2A pi2a;
5329 needed = 0;
5330 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5332 /* First pass: calculate the size for all Entries */
5333 pi2w = (LPPORT_INFO_2W) bufferW;
5334 pi2a = (LPPORT_INFO_2A) pPorts;
5335 index = 0;
5336 while (index < numentries) {
5337 index++;
5338 needed += entrysize; /* PORT_INFO_?A */
5339 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5341 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5342 NULL, 0, NULL, NULL);
5343 if (Level > 1) {
5344 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5345 NULL, 0, NULL, NULL);
5346 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5347 NULL, 0, NULL, NULL);
5349 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5350 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5351 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5354 /* check for errors and quit on failure */
5355 if (cbBuf < needed) {
5356 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5357 res = FALSE;
5358 goto cleanup;
5360 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5361 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5362 cbBuf -= len ; /* free Bytes in the user-Buffer */
5363 pi2w = (LPPORT_INFO_2W) bufferW;
5364 pi2a = (LPPORT_INFO_2A) pPorts;
5365 index = 0;
5366 /* Second Pass: Fill the User Buffer (if we have one) */
5367 while ((index < numentries) && pPorts) {
5368 index++;
5369 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5370 pi2a->pPortName = ptr;
5371 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5372 ptr, cbBuf , NULL, NULL);
5373 ptr += len;
5374 cbBuf -= len;
5375 if (Level > 1) {
5376 pi2a->pMonitorName = ptr;
5377 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5378 ptr, cbBuf, NULL, NULL);
5379 ptr += len;
5380 cbBuf -= len;
5382 pi2a->pDescription = ptr;
5383 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5384 ptr, cbBuf, NULL, NULL);
5385 ptr += len;
5386 cbBuf -= len;
5388 pi2a->fPortType = pi2w->fPortType;
5389 pi2a->Reserved = 0; /* documented: "must be zero" */
5392 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5393 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5394 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5398 cleanup:
5399 if (pcbNeeded) *pcbNeeded = needed;
5400 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5402 HeapFree(GetProcessHeap(), 0, nameW);
5403 HeapFree(GetProcessHeap(), 0, bufferW);
5405 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5406 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5408 return (res);
5412 /******************************************************************************
5413 * EnumPortsW (WINSPOOL.@)
5415 * Enumerate available Ports
5417 * PARAMS
5418 * pName [I] Servername or NULL (local Computer)
5419 * Level [I] Structure-Level (1 or 2)
5420 * pPorts [O] PTR to Buffer that receives the Result
5421 * cbBuf [I] Size of Buffer at pPorts
5422 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5423 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5425 * RETURNS
5426 * Success: TRUE
5427 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5430 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5433 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5434 cbBuf, pcbNeeded, pcReturned);
5436 if ((backend == NULL) && !load_backend()) return FALSE;
5438 /* Level is not checked in win9x */
5439 if (!Level || (Level > 2)) {
5440 WARN("level (%d) is ignored in win9x\n", Level);
5441 SetLastError(ERROR_INVALID_LEVEL);
5442 return FALSE;
5444 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5445 SetLastError(RPC_X_NULL_REF_POINTER);
5446 return FALSE;
5449 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5452 /******************************************************************************
5453 * GetDefaultPrinterW (WINSPOOL.@)
5455 * FIXME
5456 * This function must read the value from data 'device' of key
5457 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5459 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5461 BOOL retval = TRUE;
5462 DWORD insize, len;
5463 WCHAR *buffer, *ptr;
5465 if (!namesize)
5467 SetLastError(ERROR_INVALID_PARAMETER);
5468 return FALSE;
5471 /* make the buffer big enough for the stuff from the profile/registry,
5472 * the content must fit into the local buffer to compute the correct
5473 * size even if the extern buffer is too small or not given.
5474 * (20 for ,driver,port) */
5475 insize = *namesize;
5476 len = max(100, (insize + 20));
5477 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5479 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5481 SetLastError (ERROR_FILE_NOT_FOUND);
5482 retval = FALSE;
5483 goto end;
5485 TRACE("%s\n", debugstr_w(buffer));
5487 if ((ptr = strchrW(buffer, ',')) == NULL)
5489 SetLastError(ERROR_INVALID_NAME);
5490 retval = FALSE;
5491 goto end;
5494 *ptr = 0;
5495 *namesize = strlenW(buffer) + 1;
5496 if(!name || (*namesize > insize))
5498 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5499 retval = FALSE;
5500 goto end;
5502 strcpyW(name, buffer);
5504 end:
5505 HeapFree( GetProcessHeap(), 0, buffer);
5506 return retval;
5510 /******************************************************************************
5511 * GetDefaultPrinterA (WINSPOOL.@)
5513 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5515 BOOL retval = TRUE;
5516 DWORD insize = 0;
5517 WCHAR *bufferW = NULL;
5519 if (!namesize)
5521 SetLastError(ERROR_INVALID_PARAMETER);
5522 return FALSE;
5525 if(name && *namesize) {
5526 insize = *namesize;
5527 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5530 if(!GetDefaultPrinterW( bufferW, namesize)) {
5531 retval = FALSE;
5532 goto end;
5535 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5536 NULL, NULL);
5537 if (!*namesize)
5539 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5540 retval = FALSE;
5542 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5544 end:
5545 HeapFree( GetProcessHeap(), 0, bufferW);
5546 return retval;
5550 /******************************************************************************
5551 * SetDefaultPrinterW (WINSPOOL.204)
5553 * Set the Name of the Default Printer
5555 * PARAMS
5556 * pszPrinter [I] Name of the Printer or NULL
5558 * RETURNS
5559 * Success: True
5560 * Failure: FALSE
5562 * NOTES
5563 * When the Parameter is NULL or points to an Empty String and
5564 * a Default Printer was already present, then this Function changes nothing.
5565 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5566 * the First enumerated local Printer is used.
5569 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5572 TRACE("(%s)\n", debugstr_w(pszPrinter));
5574 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5575 return FALSE;
5578 /******************************************************************************
5579 * SetDefaultPrinterA (WINSPOOL.202)
5581 * See SetDefaultPrinterW.
5584 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5587 TRACE("(%s)\n", debugstr_a(pszPrinter));
5589 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5590 return FALSE;
5594 /******************************************************************************
5595 * SetPrinterDataExA (WINSPOOL.@)
5597 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5598 LPCSTR pValueName, DWORD Type,
5599 LPBYTE pData, DWORD cbData)
5601 HKEY hkeyPrinter, hkeySubkey;
5602 DWORD ret;
5604 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5605 debugstr_a(pValueName), Type, pData, cbData);
5607 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5608 != ERROR_SUCCESS)
5609 return ret;
5611 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5612 != ERROR_SUCCESS) {
5613 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5614 RegCloseKey(hkeyPrinter);
5615 return ret;
5617 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5618 RegCloseKey(hkeySubkey);
5619 RegCloseKey(hkeyPrinter);
5620 return ret;
5623 /******************************************************************************
5624 * SetPrinterDataExW (WINSPOOL.@)
5626 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5627 LPCWSTR pValueName, DWORD Type,
5628 LPBYTE pData, DWORD cbData)
5630 HKEY hkeyPrinter, hkeySubkey;
5631 DWORD ret;
5633 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5634 debugstr_w(pValueName), Type, pData, cbData);
5636 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5637 != ERROR_SUCCESS)
5638 return ret;
5640 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5641 != ERROR_SUCCESS) {
5642 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5643 RegCloseKey(hkeyPrinter);
5644 return ret;
5646 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5647 RegCloseKey(hkeySubkey);
5648 RegCloseKey(hkeyPrinter);
5649 return ret;
5652 /******************************************************************************
5653 * SetPrinterDataA (WINSPOOL.@)
5655 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5656 LPBYTE pData, DWORD cbData)
5658 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5659 pData, cbData);
5662 /******************************************************************************
5663 * SetPrinterDataW (WINSPOOL.@)
5665 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5666 LPBYTE pData, DWORD cbData)
5668 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5669 pData, cbData);
5672 /******************************************************************************
5673 * GetPrinterDataExA (WINSPOOL.@)
5675 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5676 LPCSTR pValueName, LPDWORD pType,
5677 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5679 HKEY hkeyPrinter, hkeySubkey;
5680 DWORD ret;
5682 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5683 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5684 pcbNeeded);
5686 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5687 != ERROR_SUCCESS)
5688 return ret;
5690 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5691 != ERROR_SUCCESS) {
5692 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5693 RegCloseKey(hkeyPrinter);
5694 return ret;
5696 *pcbNeeded = nSize;
5697 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5698 RegCloseKey(hkeySubkey);
5699 RegCloseKey(hkeyPrinter);
5700 return ret;
5703 /******************************************************************************
5704 * GetPrinterDataExW (WINSPOOL.@)
5706 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5707 LPCWSTR pValueName, LPDWORD pType,
5708 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5710 HKEY hkeyPrinter, hkeySubkey;
5711 DWORD ret;
5713 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5714 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5715 pcbNeeded);
5717 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5718 != ERROR_SUCCESS)
5719 return ret;
5721 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5722 != ERROR_SUCCESS) {
5723 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5724 RegCloseKey(hkeyPrinter);
5725 return ret;
5727 *pcbNeeded = nSize;
5728 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5729 RegCloseKey(hkeySubkey);
5730 RegCloseKey(hkeyPrinter);
5731 return ret;
5734 /******************************************************************************
5735 * GetPrinterDataA (WINSPOOL.@)
5737 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5738 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5740 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5741 pData, nSize, pcbNeeded);
5744 /******************************************************************************
5745 * GetPrinterDataW (WINSPOOL.@)
5747 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5748 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5750 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5751 pData, nSize, pcbNeeded);
5754 /*******************************************************************************
5755 * EnumPrinterDataExW [WINSPOOL.@]
5757 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5758 LPBYTE pEnumValues, DWORD cbEnumValues,
5759 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5761 HKEY hkPrinter, hkSubKey;
5762 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5763 cbValueNameLen, cbMaxValueLen, cbValueLen,
5764 cbBufSize, dwType;
5765 LPWSTR lpValueName;
5766 HANDLE hHeap;
5767 PBYTE lpValue;
5768 PPRINTER_ENUM_VALUESW ppev;
5770 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5772 if (pKeyName == NULL || *pKeyName == 0)
5773 return ERROR_INVALID_PARAMETER;
5775 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5776 if (ret != ERROR_SUCCESS)
5778 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5779 hPrinter, ret);
5780 return ret;
5783 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5784 if (ret != ERROR_SUCCESS)
5786 r = RegCloseKey (hkPrinter);
5787 if (r != ERROR_SUCCESS)
5788 WARN ("RegCloseKey returned %i\n", r);
5789 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5790 debugstr_w (pKeyName), ret);
5791 return ret;
5794 ret = RegCloseKey (hkPrinter);
5795 if (ret != ERROR_SUCCESS)
5797 ERR ("RegCloseKey returned %i\n", ret);
5798 r = RegCloseKey (hkSubKey);
5799 if (r != ERROR_SUCCESS)
5800 WARN ("RegCloseKey returned %i\n", r);
5801 return ret;
5804 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5805 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5806 if (ret != ERROR_SUCCESS)
5808 r = RegCloseKey (hkSubKey);
5809 if (r != ERROR_SUCCESS)
5810 WARN ("RegCloseKey returned %i\n", r);
5811 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5812 return ret;
5815 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5816 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5818 if (cValues == 0) /* empty key */
5820 r = RegCloseKey (hkSubKey);
5821 if (r != ERROR_SUCCESS)
5822 WARN ("RegCloseKey returned %i\n", r);
5823 *pcbEnumValues = *pnEnumValues = 0;
5824 return ERROR_SUCCESS;
5827 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5829 hHeap = GetProcessHeap ();
5830 if (hHeap == NULL)
5832 ERR ("GetProcessHeap failed\n");
5833 r = RegCloseKey (hkSubKey);
5834 if (r != ERROR_SUCCESS)
5835 WARN ("RegCloseKey returned %i\n", r);
5836 return ERROR_OUTOFMEMORY;
5839 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5840 if (lpValueName == NULL)
5842 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5843 r = RegCloseKey (hkSubKey);
5844 if (r != ERROR_SUCCESS)
5845 WARN ("RegCloseKey returned %i\n", r);
5846 return ERROR_OUTOFMEMORY;
5849 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5850 if (lpValue == NULL)
5852 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5853 if (HeapFree (hHeap, 0, lpValueName) == 0)
5854 WARN ("HeapFree failed with code %i\n", GetLastError ());
5855 r = RegCloseKey (hkSubKey);
5856 if (r != ERROR_SUCCESS)
5857 WARN ("RegCloseKey returned %i\n", r);
5858 return ERROR_OUTOFMEMORY;
5861 TRACE ("pass 1: calculating buffer required for all names and values\n");
5863 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5865 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5867 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5869 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5870 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5871 NULL, NULL, lpValue, &cbValueLen);
5872 if (ret != ERROR_SUCCESS)
5874 if (HeapFree (hHeap, 0, lpValue) == 0)
5875 WARN ("HeapFree failed with code %i\n", GetLastError ());
5876 if (HeapFree (hHeap, 0, lpValueName) == 0)
5877 WARN ("HeapFree failed with code %i\n", GetLastError ());
5878 r = RegCloseKey (hkSubKey);
5879 if (r != ERROR_SUCCESS)
5880 WARN ("RegCloseKey returned %i\n", r);
5881 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5882 return ret;
5885 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5886 debugstr_w (lpValueName), dwIndex,
5887 cbValueNameLen + 1, cbValueLen);
5889 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5890 cbBufSize += cbValueLen;
5893 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5895 *pcbEnumValues = cbBufSize;
5896 *pnEnumValues = cValues;
5898 if (cbEnumValues < cbBufSize) /* buffer too small */
5900 if (HeapFree (hHeap, 0, lpValue) == 0)
5901 WARN ("HeapFree failed with code %i\n", GetLastError ());
5902 if (HeapFree (hHeap, 0, lpValueName) == 0)
5903 WARN ("HeapFree failed with code %i\n", GetLastError ());
5904 r = RegCloseKey (hkSubKey);
5905 if (r != ERROR_SUCCESS)
5906 WARN ("RegCloseKey returned %i\n", r);
5907 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5908 return ERROR_MORE_DATA;
5911 TRACE ("pass 2: copying all names and values to buffer\n");
5913 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5914 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5916 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5918 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5919 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5920 NULL, &dwType, lpValue, &cbValueLen);
5921 if (ret != ERROR_SUCCESS)
5923 if (HeapFree (hHeap, 0, lpValue) == 0)
5924 WARN ("HeapFree failed with code %i\n", GetLastError ());
5925 if (HeapFree (hHeap, 0, lpValueName) == 0)
5926 WARN ("HeapFree failed with code %i\n", GetLastError ());
5927 r = RegCloseKey (hkSubKey);
5928 if (r != ERROR_SUCCESS)
5929 WARN ("RegCloseKey returned %i\n", r);
5930 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5931 return ret;
5934 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5935 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5936 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5937 pEnumValues += cbValueNameLen;
5939 /* return # of *bytes* (including trailing \0), not # of chars */
5940 ppev[dwIndex].cbValueName = cbValueNameLen;
5942 ppev[dwIndex].dwType = dwType;
5944 memcpy (pEnumValues, lpValue, cbValueLen);
5945 ppev[dwIndex].pData = pEnumValues;
5946 pEnumValues += cbValueLen;
5948 ppev[dwIndex].cbData = cbValueLen;
5950 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5951 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5954 if (HeapFree (hHeap, 0, lpValue) == 0)
5956 ret = GetLastError ();
5957 ERR ("HeapFree failed with code %i\n", ret);
5958 if (HeapFree (hHeap, 0, lpValueName) == 0)
5959 WARN ("HeapFree failed with code %i\n", GetLastError ());
5960 r = RegCloseKey (hkSubKey);
5961 if (r != ERROR_SUCCESS)
5962 WARN ("RegCloseKey returned %i\n", r);
5963 return ret;
5966 if (HeapFree (hHeap, 0, lpValueName) == 0)
5968 ret = GetLastError ();
5969 ERR ("HeapFree failed with code %i\n", ret);
5970 r = RegCloseKey (hkSubKey);
5971 if (r != ERROR_SUCCESS)
5972 WARN ("RegCloseKey returned %i\n", r);
5973 return ret;
5976 ret = RegCloseKey (hkSubKey);
5977 if (ret != ERROR_SUCCESS)
5979 ERR ("RegCloseKey returned %i\n", ret);
5980 return ret;
5983 return ERROR_SUCCESS;
5986 /*******************************************************************************
5987 * EnumPrinterDataExA [WINSPOOL.@]
5989 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5990 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5991 * what Windows 2000 SP1 does.
5994 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5995 LPBYTE pEnumValues, DWORD cbEnumValues,
5996 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5998 INT len;
5999 LPWSTR pKeyNameW;
6000 DWORD ret, dwIndex, dwBufSize;
6001 HANDLE hHeap;
6002 LPSTR pBuffer;
6004 TRACE ("%p %s\n", hPrinter, pKeyName);
6006 if (pKeyName == NULL || *pKeyName == 0)
6007 return ERROR_INVALID_PARAMETER;
6009 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6010 if (len == 0)
6012 ret = GetLastError ();
6013 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6014 return ret;
6017 hHeap = GetProcessHeap ();
6018 if (hHeap == NULL)
6020 ERR ("GetProcessHeap failed\n");
6021 return ERROR_OUTOFMEMORY;
6024 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6025 if (pKeyNameW == NULL)
6027 ERR ("Failed to allocate %i bytes from process heap\n",
6028 (LONG)(len * sizeof (WCHAR)));
6029 return ERROR_OUTOFMEMORY;
6032 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6034 ret = GetLastError ();
6035 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6036 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6037 WARN ("HeapFree failed with code %i\n", GetLastError ());
6038 return ret;
6041 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6042 pcbEnumValues, pnEnumValues);
6043 if (ret != ERROR_SUCCESS)
6045 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6046 WARN ("HeapFree failed with code %i\n", GetLastError ());
6047 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6048 return ret;
6051 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6053 ret = GetLastError ();
6054 ERR ("HeapFree failed with code %i\n", ret);
6055 return ret;
6058 if (*pnEnumValues == 0) /* empty key */
6059 return ERROR_SUCCESS;
6061 dwBufSize = 0;
6062 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6064 PPRINTER_ENUM_VALUESW ppev =
6065 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6067 if (dwBufSize < ppev->cbValueName)
6068 dwBufSize = ppev->cbValueName;
6070 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6071 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6072 dwBufSize = ppev->cbData;
6075 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6077 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6078 if (pBuffer == NULL)
6080 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6081 return ERROR_OUTOFMEMORY;
6084 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6086 PPRINTER_ENUM_VALUESW ppev =
6087 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6089 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6090 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6091 NULL);
6092 if (len == 0)
6094 ret = GetLastError ();
6095 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6096 if (HeapFree (hHeap, 0, pBuffer) == 0)
6097 WARN ("HeapFree failed with code %i\n", GetLastError ());
6098 return ret;
6101 memcpy (ppev->pValueName, pBuffer, len);
6103 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6105 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6106 ppev->dwType != REG_MULTI_SZ)
6107 continue;
6109 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6110 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6111 if (len == 0)
6113 ret = GetLastError ();
6114 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6115 if (HeapFree (hHeap, 0, pBuffer) == 0)
6116 WARN ("HeapFree failed with code %i\n", GetLastError ());
6117 return ret;
6120 memcpy (ppev->pData, pBuffer, len);
6122 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6123 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6126 if (HeapFree (hHeap, 0, pBuffer) == 0)
6128 ret = GetLastError ();
6129 ERR ("HeapFree failed with code %i\n", ret);
6130 return ret;
6133 return ERROR_SUCCESS;
6136 /******************************************************************************
6137 * AbortPrinter (WINSPOOL.@)
6139 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6141 FIXME("(%p), stub!\n", hPrinter);
6142 return TRUE;
6145 /******************************************************************************
6146 * AddPortA (WINSPOOL.@)
6148 * See AddPortW.
6151 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6153 LPWSTR nameW = NULL;
6154 LPWSTR monitorW = NULL;
6155 DWORD len;
6156 BOOL res;
6158 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6160 if (pName) {
6161 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6162 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6163 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6166 if (pMonitorName) {
6167 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6168 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6169 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6171 res = AddPortW(nameW, hWnd, monitorW);
6172 HeapFree(GetProcessHeap(), 0, nameW);
6173 HeapFree(GetProcessHeap(), 0, monitorW);
6174 return res;
6177 /******************************************************************************
6178 * AddPortW (WINSPOOL.@)
6180 * Add a Port for a specific Monitor
6182 * PARAMS
6183 * pName [I] Servername or NULL (local Computer)
6184 * hWnd [I] Handle to parent Window for the Dialog-Box
6185 * pMonitorName [I] Name of the Monitor that manage the Port
6187 * RETURNS
6188 * Success: TRUE
6189 * Failure: FALSE
6192 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6194 monitor_t * pm;
6195 monitor_t * pui;
6196 DWORD res;
6198 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6200 if (pName && pName[0]) {
6201 SetLastError(ERROR_INVALID_PARAMETER);
6202 return FALSE;
6205 if (!pMonitorName) {
6206 SetLastError(RPC_X_NULL_REF_POINTER);
6207 return FALSE;
6210 /* an empty Monitorname is Invalid */
6211 if (!pMonitorName[0]) {
6212 SetLastError(ERROR_NOT_SUPPORTED);
6213 return FALSE;
6216 pm = monitor_load(pMonitorName, NULL);
6217 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6218 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6219 TRACE("got %d with %u\n", res, GetLastError());
6220 res = TRUE;
6222 else
6224 pui = monitor_loadui(pm);
6225 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6226 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6227 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6228 TRACE("got %d with %u\n", res, GetLastError());
6229 res = TRUE;
6231 else
6233 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6234 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6236 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6237 SetLastError(ERROR_NOT_SUPPORTED);
6238 res = FALSE;
6240 monitor_unload(pui);
6242 monitor_unload(pm);
6243 TRACE("returning %d with %u\n", res, GetLastError());
6244 return res;
6247 /******************************************************************************
6248 * AddPortExA (WINSPOOL.@)
6250 * See AddPortExW.
6253 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6255 PORT_INFO_2W pi2W;
6256 PORT_INFO_2A * pi2A;
6257 LPWSTR nameW = NULL;
6258 LPWSTR monitorW = NULL;
6259 DWORD len;
6260 BOOL res;
6262 pi2A = (PORT_INFO_2A *) pBuffer;
6264 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6265 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6267 if ((level < 1) || (level > 2)) {
6268 SetLastError(ERROR_INVALID_LEVEL);
6269 return FALSE;
6272 if (!pi2A) {
6273 SetLastError(ERROR_INVALID_PARAMETER);
6274 return FALSE;
6277 if (pName) {
6278 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6279 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6280 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6283 if (pMonitorName) {
6284 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6285 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6286 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6289 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6291 if (pi2A->pPortName) {
6292 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6293 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6294 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6297 if (level > 1) {
6298 if (pi2A->pMonitorName) {
6299 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6300 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6301 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6304 if (pi2A->pDescription) {
6305 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6306 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6307 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6309 pi2W.fPortType = pi2A->fPortType;
6310 pi2W.Reserved = pi2A->Reserved;
6313 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6315 HeapFree(GetProcessHeap(), 0, nameW);
6316 HeapFree(GetProcessHeap(), 0, monitorW);
6317 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6318 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6319 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6320 return res;
6324 /******************************************************************************
6325 * AddPortExW (WINSPOOL.@)
6327 * Add a Port for a specific Monitor, without presenting a user interface
6329 * PARAMS
6330 * pName [I] Servername or NULL (local Computer)
6331 * level [I] Structure-Level (1 or 2) for pBuffer
6332 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6333 * pMonitorName [I] Name of the Monitor that manage the Port
6335 * RETURNS
6336 * Success: TRUE
6337 * Failure: FALSE
6340 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6342 PORT_INFO_2W * pi2;
6343 monitor_t * pm;
6344 DWORD res = FALSE;
6346 pi2 = (PORT_INFO_2W *) pBuffer;
6348 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6349 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6350 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6351 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6354 if ((level < 1) || (level > 2)) {
6355 SetLastError(ERROR_INVALID_LEVEL);
6356 return FALSE;
6359 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6360 SetLastError(ERROR_INVALID_PARAMETER);
6361 return FALSE;
6364 /* load the Monitor */
6365 pm = monitor_load(pMonitorName, NULL);
6366 if (!pm) {
6367 SetLastError(ERROR_INVALID_PARAMETER);
6368 return FALSE;
6371 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6372 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6373 TRACE("got %u with %u\n", res, GetLastError());
6375 else
6377 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6379 monitor_unload(pm);
6380 return res;
6383 /******************************************************************************
6384 * AddPrinterConnectionA (WINSPOOL.@)
6386 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6388 FIXME("%s\n", debugstr_a(pName));
6389 return FALSE;
6392 /******************************************************************************
6393 * AddPrinterConnectionW (WINSPOOL.@)
6395 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6397 FIXME("%s\n", debugstr_w(pName));
6398 return FALSE;
6401 /******************************************************************************
6402 * AddPrinterDriverExW (WINSPOOL.@)
6404 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6406 * PARAMS
6407 * pName [I] Servername or NULL (local Computer)
6408 * level [I] Level for the supplied DRIVER_INFO_*W struct
6409 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6410 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6412 * RESULTS
6413 * Success: TRUE
6414 * Failure: FALSE
6417 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6419 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6421 if ((backend == NULL) && !load_backend()) return FALSE;
6423 if (level < 2 || level == 5 || level == 7 || level > 8) {
6424 SetLastError(ERROR_INVALID_LEVEL);
6425 return FALSE;
6428 if (!pDriverInfo) {
6429 SetLastError(ERROR_INVALID_PARAMETER);
6430 return FALSE;
6433 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6436 /******************************************************************************
6437 * AddPrinterDriverExA (WINSPOOL.@)
6439 * See AddPrinterDriverExW.
6442 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6444 DRIVER_INFO_8A *diA;
6445 DRIVER_INFO_8W diW;
6446 LPWSTR nameW = NULL;
6447 DWORD lenA;
6448 DWORD len;
6449 DWORD res = FALSE;
6451 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6453 diA = (DRIVER_INFO_8A *) pDriverInfo;
6454 ZeroMemory(&diW, sizeof(diW));
6456 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6457 SetLastError(ERROR_INVALID_LEVEL);
6458 return FALSE;
6461 if (diA == NULL) {
6462 SetLastError(ERROR_INVALID_PARAMETER);
6463 return FALSE;
6466 /* convert servername to unicode */
6467 if (pName) {
6468 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6469 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6470 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6473 /* common fields */
6474 diW.cVersion = diA->cVersion;
6476 if (diA->pName) {
6477 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6478 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6479 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6482 if (diA->pEnvironment) {
6483 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6484 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6485 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6488 if (diA->pDriverPath) {
6489 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6490 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6491 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6494 if (diA->pDataFile) {
6495 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6496 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6497 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6500 if (diA->pConfigFile) {
6501 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6502 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6503 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6506 if ((Level > 2) && diA->pDependentFiles) {
6507 lenA = multi_sz_lenA(diA->pDependentFiles);
6508 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6509 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6510 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6513 if ((Level > 2) && diA->pMonitorName) {
6514 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6515 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6516 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6519 if ((Level > 3) && diA->pDefaultDataType) {
6520 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6521 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6522 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6525 if ((Level > 3) && diA->pszzPreviousNames) {
6526 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6527 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6528 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6529 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6532 if ((Level > 5) && diA->pszMfgName) {
6533 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6534 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6535 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6538 if ((Level > 5) && diA->pszOEMUrl) {
6539 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6540 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6541 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6544 if ((Level > 5) && diA->pszHardwareID) {
6545 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6546 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6547 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6550 if ((Level > 5) && diA->pszProvider) {
6551 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6552 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6553 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6556 if (Level > 7) {
6557 FIXME("level %u is incomplete\n", Level);
6560 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6561 TRACE("got %u with %u\n", res, GetLastError());
6562 HeapFree(GetProcessHeap(), 0, nameW);
6563 HeapFree(GetProcessHeap(), 0, diW.pName);
6564 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6565 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6566 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6567 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6568 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6569 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6570 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6571 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6572 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6573 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6574 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6575 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6577 TRACE("=> %u with %u\n", res, GetLastError());
6578 return res;
6581 /******************************************************************************
6582 * ConfigurePortA (WINSPOOL.@)
6584 * See ConfigurePortW.
6587 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6589 LPWSTR nameW = NULL;
6590 LPWSTR portW = NULL;
6591 INT len;
6592 DWORD res;
6594 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6596 /* convert servername to unicode */
6597 if (pName) {
6598 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6599 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6600 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6603 /* convert portname to unicode */
6604 if (pPortName) {
6605 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6606 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6607 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6610 res = ConfigurePortW(nameW, hWnd, portW);
6611 HeapFree(GetProcessHeap(), 0, nameW);
6612 HeapFree(GetProcessHeap(), 0, portW);
6613 return res;
6616 /******************************************************************************
6617 * ConfigurePortW (WINSPOOL.@)
6619 * Display the Configuration-Dialog for a specific Port
6621 * PARAMS
6622 * pName [I] Servername or NULL (local Computer)
6623 * hWnd [I] Handle to parent Window for the Dialog-Box
6624 * pPortName [I] Name of the Port, that should be configured
6626 * RETURNS
6627 * Success: TRUE
6628 * Failure: FALSE
6631 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6633 monitor_t * pm;
6634 monitor_t * pui;
6635 DWORD res;
6637 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6639 if (pName && pName[0]) {
6640 SetLastError(ERROR_INVALID_PARAMETER);
6641 return FALSE;
6644 if (!pPortName) {
6645 SetLastError(RPC_X_NULL_REF_POINTER);
6646 return FALSE;
6649 /* an empty Portname is Invalid, but can popup a Dialog */
6650 if (!pPortName[0]) {
6651 SetLastError(ERROR_NOT_SUPPORTED);
6652 return FALSE;
6655 pm = monitor_load_by_port(pPortName);
6656 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6657 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6658 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6659 TRACE("got %d with %u\n", res, GetLastError());
6661 else
6663 pui = monitor_loadui(pm);
6664 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6665 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6666 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6667 TRACE("got %d with %u\n", res, GetLastError());
6669 else
6671 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6672 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6674 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6675 SetLastError(ERROR_NOT_SUPPORTED);
6676 res = FALSE;
6678 monitor_unload(pui);
6680 monitor_unload(pm);
6682 TRACE("returning %d with %u\n", res, GetLastError());
6683 return res;
6686 /******************************************************************************
6687 * ConnectToPrinterDlg (WINSPOOL.@)
6689 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6691 FIXME("%p %x\n", hWnd, Flags);
6692 return NULL;
6695 /******************************************************************************
6696 * DeletePrinterConnectionA (WINSPOOL.@)
6698 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6700 FIXME("%s\n", debugstr_a(pName));
6701 return TRUE;
6704 /******************************************************************************
6705 * DeletePrinterConnectionW (WINSPOOL.@)
6707 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6709 FIXME("%s\n", debugstr_w(pName));
6710 return TRUE;
6713 /******************************************************************************
6714 * DeletePrinterDriverExW (WINSPOOL.@)
6716 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6717 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6719 HKEY hkey_drivers;
6720 BOOL ret = FALSE;
6722 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6723 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6725 if(pName && pName[0])
6727 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6728 SetLastError(ERROR_INVALID_PARAMETER);
6729 return FALSE;
6732 if(dwDeleteFlag)
6734 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6735 SetLastError(ERROR_INVALID_PARAMETER);
6736 return FALSE;
6739 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6741 if(!hkey_drivers)
6743 ERR("Can't open drivers key\n");
6744 return FALSE;
6747 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6748 ret = TRUE;
6750 RegCloseKey(hkey_drivers);
6752 return ret;
6755 /******************************************************************************
6756 * DeletePrinterDriverExA (WINSPOOL.@)
6758 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6759 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6761 UNICODE_STRING NameW, EnvW, DriverW;
6762 BOOL ret;
6764 asciitounicode(&NameW, pName);
6765 asciitounicode(&EnvW, pEnvironment);
6766 asciitounicode(&DriverW, pDriverName);
6768 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6770 RtlFreeUnicodeString(&DriverW);
6771 RtlFreeUnicodeString(&EnvW);
6772 RtlFreeUnicodeString(&NameW);
6774 return ret;
6777 /******************************************************************************
6778 * DeletePrinterDataExW (WINSPOOL.@)
6780 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6781 LPCWSTR pValueName)
6783 FIXME("%p %s %s\n", hPrinter,
6784 debugstr_w(pKeyName), debugstr_w(pValueName));
6785 return ERROR_INVALID_PARAMETER;
6788 /******************************************************************************
6789 * DeletePrinterDataExA (WINSPOOL.@)
6791 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6792 LPCSTR pValueName)
6794 FIXME("%p %s %s\n", hPrinter,
6795 debugstr_a(pKeyName), debugstr_a(pValueName));
6796 return ERROR_INVALID_PARAMETER;
6799 /******************************************************************************
6800 * DeletePrintProcessorA (WINSPOOL.@)
6802 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6804 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6805 debugstr_a(pPrintProcessorName));
6806 return TRUE;
6809 /******************************************************************************
6810 * DeletePrintProcessorW (WINSPOOL.@)
6812 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6814 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6815 debugstr_w(pPrintProcessorName));
6816 return TRUE;
6819 /******************************************************************************
6820 * DeletePrintProvidorA (WINSPOOL.@)
6822 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6824 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6825 debugstr_a(pPrintProviderName));
6826 return TRUE;
6829 /******************************************************************************
6830 * DeletePrintProvidorW (WINSPOOL.@)
6832 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6834 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6835 debugstr_w(pPrintProviderName));
6836 return TRUE;
6839 /******************************************************************************
6840 * EnumFormsA (WINSPOOL.@)
6842 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6843 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6845 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6847 return FALSE;
6850 /******************************************************************************
6851 * EnumFormsW (WINSPOOL.@)
6853 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6854 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6856 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6857 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6858 return FALSE;
6861 /*****************************************************************************
6862 * EnumMonitorsA [WINSPOOL.@]
6864 * See EnumMonitorsW.
6867 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6868 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6870 BOOL res;
6871 LPBYTE bufferW = NULL;
6872 LPWSTR nameW = NULL;
6873 DWORD needed = 0;
6874 DWORD numentries = 0;
6875 INT len;
6877 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6878 cbBuf, pcbNeeded, pcReturned);
6880 /* convert servername to unicode */
6881 if (pName) {
6882 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6883 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6884 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6886 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6887 needed = cbBuf * sizeof(WCHAR);
6888 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6889 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6891 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6892 if (pcbNeeded) needed = *pcbNeeded;
6893 /* HeapReAlloc return NULL, when bufferW was NULL */
6894 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6895 HeapAlloc(GetProcessHeap(), 0, needed);
6897 /* Try again with the large Buffer */
6898 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6900 numentries = pcReturned ? *pcReturned : 0;
6901 needed = 0;
6903 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6904 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6906 if (res) {
6907 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6908 DWORD entrysize = 0;
6909 DWORD index;
6910 LPSTR ptr;
6911 LPMONITOR_INFO_2W mi2w;
6912 LPMONITOR_INFO_2A mi2a;
6914 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6915 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6917 /* First pass: calculate the size for all Entries */
6918 mi2w = (LPMONITOR_INFO_2W) bufferW;
6919 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6920 index = 0;
6921 while (index < numentries) {
6922 index++;
6923 needed += entrysize; /* MONITOR_INFO_?A */
6924 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6926 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6927 NULL, 0, NULL, NULL);
6928 if (Level > 1) {
6929 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6930 NULL, 0, NULL, NULL);
6931 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6932 NULL, 0, NULL, NULL);
6934 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6935 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6936 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6939 /* check for errors and quit on failure */
6940 if (cbBuf < needed) {
6941 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6942 res = FALSE;
6943 goto emA_cleanup;
6945 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6946 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6947 cbBuf -= len ; /* free Bytes in the user-Buffer */
6948 mi2w = (LPMONITOR_INFO_2W) bufferW;
6949 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6950 index = 0;
6951 /* Second Pass: Fill the User Buffer (if we have one) */
6952 while ((index < numentries) && pMonitors) {
6953 index++;
6954 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6955 mi2a->pName = ptr;
6956 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6957 ptr, cbBuf , NULL, NULL);
6958 ptr += len;
6959 cbBuf -= len;
6960 if (Level > 1) {
6961 mi2a->pEnvironment = ptr;
6962 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6963 ptr, cbBuf, NULL, NULL);
6964 ptr += len;
6965 cbBuf -= len;
6967 mi2a->pDLLName = ptr;
6968 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6969 ptr, cbBuf, NULL, NULL);
6970 ptr += len;
6971 cbBuf -= len;
6973 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6974 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6975 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6978 emA_cleanup:
6979 if (pcbNeeded) *pcbNeeded = needed;
6980 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6982 HeapFree(GetProcessHeap(), 0, nameW);
6983 HeapFree(GetProcessHeap(), 0, bufferW);
6985 TRACE("returning %d with %d (%d byte for %d entries)\n",
6986 (res), GetLastError(), needed, numentries);
6988 return (res);
6992 /*****************************************************************************
6993 * EnumMonitorsW [WINSPOOL.@]
6995 * Enumerate available Port-Monitors
6997 * PARAMS
6998 * pName [I] Servername or NULL (local Computer)
6999 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7000 * pMonitors [O] PTR to Buffer that receives the Result
7001 * cbBuf [I] Size of Buffer at pMonitors
7002 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7003 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7005 * RETURNS
7006 * Success: TRUE
7007 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7010 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7011 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7014 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7015 cbBuf, pcbNeeded, pcReturned);
7017 if ((backend == NULL) && !load_backend()) return FALSE;
7019 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7020 SetLastError(RPC_X_NULL_REF_POINTER);
7021 return FALSE;
7024 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7027 /******************************************************************************
7028 * SpoolerInit (WINSPOOL.@)
7030 * Initialize the Spooler
7032 * RETURNS
7033 * Success: TRUE
7034 * Failure: FALSE
7036 * NOTES
7037 * The function fails on windows, when the spooler service is not running
7040 BOOL WINAPI SpoolerInit(void)
7043 if ((backend == NULL) && !load_backend()) return FALSE;
7044 return TRUE;
7047 /******************************************************************************
7048 * XcvDataW (WINSPOOL.@)
7050 * Execute commands in the Printmonitor DLL
7052 * PARAMS
7053 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7054 * pszDataName [i] Name of the command to execute
7055 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7056 * cbInputData [i] Size in Bytes of Buffer at pInputData
7057 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7058 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7059 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7060 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7062 * RETURNS
7063 * Success: TRUE
7064 * Failure: FALSE
7066 * NOTES
7067 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7068 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7070 * Minimal List of commands, that a Printmonitor DLL should support:
7072 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7073 *| "AddPort" : Add a Port
7074 *| "DeletePort": Delete a Port
7076 * Many Printmonitors support additional commands. Examples for localspl.dll:
7077 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7078 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7081 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7082 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7083 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7085 opened_printer_t *printer;
7087 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7088 pInputData, cbInputData, pOutputData,
7089 cbOutputData, pcbOutputNeeded, pdwStatus);
7091 printer = get_opened_printer(hXcv);
7092 if (!printer || (!printer->hXcv)) {
7093 SetLastError(ERROR_INVALID_HANDLE);
7094 return FALSE;
7097 if (!pcbOutputNeeded) {
7098 SetLastError(ERROR_INVALID_PARAMETER);
7099 return FALSE;
7102 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7103 SetLastError(RPC_X_NULL_REF_POINTER);
7104 return FALSE;
7107 *pcbOutputNeeded = 0;
7109 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7110 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7112 return TRUE;
7115 /*****************************************************************************
7116 * EnumPrinterDataA [WINSPOOL.@]
7119 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7120 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7121 DWORD cbData, LPDWORD pcbData )
7123 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7124 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7125 return ERROR_NO_MORE_ITEMS;
7128 /*****************************************************************************
7129 * EnumPrinterDataW [WINSPOOL.@]
7132 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7133 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7134 DWORD cbData, LPDWORD pcbData )
7136 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7137 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7138 return ERROR_NO_MORE_ITEMS;
7141 /*****************************************************************************
7142 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7145 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7146 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7147 LPDWORD pcbNeeded, LPDWORD pcReturned)
7149 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7150 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7151 pcbNeeded, pcReturned);
7152 return FALSE;
7155 /*****************************************************************************
7156 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7159 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7160 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7161 LPDWORD pcbNeeded, LPDWORD pcReturned)
7163 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7164 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7165 pcbNeeded, pcReturned);
7166 return FALSE;
7169 /*****************************************************************************
7170 * EnumPrintProcessorsA [WINSPOOL.@]
7173 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7174 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7176 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7177 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7178 return FALSE;
7181 /*****************************************************************************
7182 * EnumPrintProcessorsW [WINSPOOL.@]
7185 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7186 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7188 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7189 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7190 cbBuf, pcbNeeded, pcbReturned);
7191 return FALSE;
7194 /*****************************************************************************
7195 * ExtDeviceMode [WINSPOOL.@]
7198 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7199 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7200 DWORD fMode)
7202 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7203 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7204 debugstr_a(pProfile), fMode);
7205 return -1;
7208 /*****************************************************************************
7209 * FindClosePrinterChangeNotification [WINSPOOL.@]
7212 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7214 FIXME("Stub: %p\n", hChange);
7215 return TRUE;
7218 /*****************************************************************************
7219 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7222 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7223 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7225 FIXME("Stub: %p %x %x %p\n",
7226 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7227 return INVALID_HANDLE_VALUE;
7230 /*****************************************************************************
7231 * FindNextPrinterChangeNotification [WINSPOOL.@]
7234 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7235 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7237 FIXME("Stub: %p %p %p %p\n",
7238 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7239 return FALSE;
7242 /*****************************************************************************
7243 * FreePrinterNotifyInfo [WINSPOOL.@]
7246 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7248 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7249 return TRUE;
7252 /*****************************************************************************
7253 * string_to_buf
7255 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7256 * ansi depending on the unicode parameter.
7258 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7260 if(!str)
7262 *size = 0;
7263 return TRUE;
7266 if(unicode)
7268 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7269 if(*size <= cb)
7271 memcpy(ptr, str, *size);
7272 return TRUE;
7274 return FALSE;
7276 else
7278 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7279 if(*size <= cb)
7281 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7282 return TRUE;
7284 return FALSE;
7288 /*****************************************************************************
7289 * get_job_info_1
7291 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7292 LPDWORD pcbNeeded, BOOL unicode)
7294 DWORD size, left = cbBuf;
7295 BOOL space = (cbBuf > 0);
7296 LPBYTE ptr = buf;
7298 *pcbNeeded = 0;
7300 if(space)
7302 ji1->JobId = job->job_id;
7305 string_to_buf(job->document_title, ptr, left, &size, unicode);
7306 if(space && size <= left)
7308 ji1->pDocument = (LPWSTR)ptr;
7309 ptr += size;
7310 left -= size;
7312 else
7313 space = FALSE;
7314 *pcbNeeded += size;
7316 return space;
7319 /*****************************************************************************
7320 * get_job_info_2
7322 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7323 LPDWORD pcbNeeded, BOOL unicode)
7325 DWORD size, left = cbBuf;
7326 BOOL space = (cbBuf > 0);
7327 LPBYTE ptr = buf;
7329 *pcbNeeded = 0;
7331 if(space)
7333 ji2->JobId = job->job_id;
7336 string_to_buf(job->document_title, ptr, left, &size, unicode);
7337 if(space && size <= left)
7339 ji2->pDocument = (LPWSTR)ptr;
7340 ptr += size;
7341 left -= size;
7343 else
7344 space = FALSE;
7345 *pcbNeeded += size;
7347 return space;
7350 /*****************************************************************************
7351 * get_job_info
7353 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7354 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7356 BOOL ret = FALSE;
7357 DWORD needed = 0, size;
7358 job_t *job;
7359 LPBYTE ptr = pJob;
7361 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7363 EnterCriticalSection(&printer_handles_cs);
7364 job = get_job(hPrinter, JobId);
7365 if(!job)
7366 goto end;
7368 switch(Level)
7370 case 1:
7371 size = sizeof(JOB_INFO_1W);
7372 if(cbBuf >= size)
7374 cbBuf -= size;
7375 ptr += size;
7376 memset(pJob, 0, size);
7378 else
7379 cbBuf = 0;
7380 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7381 needed += size;
7382 break;
7384 case 2:
7385 size = sizeof(JOB_INFO_2W);
7386 if(cbBuf >= size)
7388 cbBuf -= size;
7389 ptr += size;
7390 memset(pJob, 0, size);
7392 else
7393 cbBuf = 0;
7394 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7395 needed += size;
7396 break;
7398 case 3:
7399 size = sizeof(JOB_INFO_3);
7400 if(cbBuf >= size)
7402 cbBuf -= size;
7403 memset(pJob, 0, size);
7404 ret = TRUE;
7406 else
7407 cbBuf = 0;
7408 needed = size;
7409 break;
7411 default:
7412 SetLastError(ERROR_INVALID_LEVEL);
7413 goto end;
7415 if(pcbNeeded)
7416 *pcbNeeded = needed;
7417 end:
7418 LeaveCriticalSection(&printer_handles_cs);
7419 return ret;
7422 /*****************************************************************************
7423 * GetJobA [WINSPOOL.@]
7426 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7427 DWORD cbBuf, LPDWORD pcbNeeded)
7429 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7432 /*****************************************************************************
7433 * GetJobW [WINSPOOL.@]
7436 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7437 DWORD cbBuf, LPDWORD pcbNeeded)
7439 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7442 /*****************************************************************************
7443 * schedule_lpr
7445 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7447 char *unixname, *queue, *cmd;
7448 char fmt[] = "lpr -P%s %s";
7449 DWORD len;
7450 int r;
7452 if(!(unixname = wine_get_unix_file_name(filename)))
7453 return FALSE;
7455 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7456 queue = HeapAlloc(GetProcessHeap(), 0, len);
7457 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7459 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7460 sprintf(cmd, fmt, queue, unixname);
7462 TRACE("printing with: %s\n", cmd);
7463 r = system(cmd);
7465 HeapFree(GetProcessHeap(), 0, cmd);
7466 HeapFree(GetProcessHeap(), 0, queue);
7467 HeapFree(GetProcessHeap(), 0, unixname);
7468 return (r == 0);
7471 /*****************************************************************************
7472 * schedule_cups
7474 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7476 #ifdef SONAME_LIBCUPS
7477 if(pcupsPrintFile)
7479 char *unixname, *queue, *unix_doc_title;
7480 DWORD len;
7481 BOOL ret;
7483 if(!(unixname = wine_get_unix_file_name(filename)))
7484 return FALSE;
7486 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7487 queue = HeapAlloc(GetProcessHeap(), 0, len);
7488 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7490 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7491 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7492 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7494 TRACE("printing via cups\n");
7495 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7496 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7497 HeapFree(GetProcessHeap(), 0, queue);
7498 HeapFree(GetProcessHeap(), 0, unixname);
7499 return ret;
7501 else
7502 #endif
7504 return schedule_lpr(printer_name, filename);
7508 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7510 LPWSTR filename;
7512 switch(msg)
7514 case WM_INITDIALOG:
7515 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7516 return TRUE;
7518 case WM_COMMAND:
7519 if(HIWORD(wparam) == BN_CLICKED)
7521 if(LOWORD(wparam) == IDOK)
7523 HANDLE hf;
7524 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7525 LPWSTR *output;
7527 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7528 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7530 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7532 WCHAR caption[200], message[200];
7533 int mb_ret;
7535 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7536 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7537 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7538 if(mb_ret == IDCANCEL)
7540 HeapFree(GetProcessHeap(), 0, filename);
7541 return TRUE;
7544 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7545 if(hf == INVALID_HANDLE_VALUE)
7547 WCHAR caption[200], message[200];
7549 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7550 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7551 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7552 HeapFree(GetProcessHeap(), 0, filename);
7553 return TRUE;
7555 CloseHandle(hf);
7556 DeleteFileW(filename);
7557 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7558 *output = filename;
7559 EndDialog(hwnd, IDOK);
7560 return TRUE;
7562 if(LOWORD(wparam) == IDCANCEL)
7564 EndDialog(hwnd, IDCANCEL);
7565 return TRUE;
7568 return FALSE;
7570 return FALSE;
7573 /*****************************************************************************
7574 * get_filename
7576 static BOOL get_filename(LPWSTR *filename)
7578 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7579 file_dlg_proc, (LPARAM)filename) == IDOK;
7582 /*****************************************************************************
7583 * schedule_file
7585 static BOOL schedule_file(LPCWSTR filename)
7587 LPWSTR output = NULL;
7589 if(get_filename(&output))
7591 BOOL r;
7592 TRACE("copy to %s\n", debugstr_w(output));
7593 r = CopyFileW(filename, output, FALSE);
7594 HeapFree(GetProcessHeap(), 0, output);
7595 return r;
7597 return FALSE;
7600 /*****************************************************************************
7601 * schedule_pipe
7603 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7605 #ifdef HAVE_FORK
7606 char *unixname, *cmdA;
7607 DWORD len;
7608 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7609 BOOL ret = FALSE;
7610 char buf[1024];
7612 if(!(unixname = wine_get_unix_file_name(filename)))
7613 return FALSE;
7615 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7616 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7617 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7619 TRACE("printing with: %s\n", cmdA);
7621 if((file_fd = open(unixname, O_RDONLY)) == -1)
7622 goto end;
7624 if (pipe(fds))
7626 ERR("pipe() failed!\n");
7627 goto end;
7630 if (fork() == 0)
7632 close(0);
7633 dup2(fds[0], 0);
7634 close(fds[1]);
7636 /* reset signals that we previously set to SIG_IGN */
7637 signal(SIGPIPE, SIG_DFL);
7638 signal(SIGCHLD, SIG_DFL);
7640 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7641 _exit(1);
7644 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7645 write(fds[1], buf, no_read);
7647 ret = TRUE;
7649 end:
7650 if(file_fd != -1) close(file_fd);
7651 if(fds[0] != -1) close(fds[0]);
7652 if(fds[1] != -1) close(fds[1]);
7654 HeapFree(GetProcessHeap(), 0, cmdA);
7655 HeapFree(GetProcessHeap(), 0, unixname);
7656 return ret;
7657 #else
7658 return FALSE;
7659 #endif
7662 /*****************************************************************************
7663 * schedule_unixfile
7665 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7667 int in_fd, out_fd, no_read;
7668 char buf[1024];
7669 BOOL ret = FALSE;
7670 char *unixname, *outputA;
7671 DWORD len;
7673 if(!(unixname = wine_get_unix_file_name(filename)))
7674 return FALSE;
7676 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7677 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7678 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7680 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7681 in_fd = open(unixname, O_RDONLY);
7682 if(out_fd == -1 || in_fd == -1)
7683 goto end;
7685 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7686 write(out_fd, buf, no_read);
7688 ret = TRUE;
7689 end:
7690 if(in_fd != -1) close(in_fd);
7691 if(out_fd != -1) close(out_fd);
7692 HeapFree(GetProcessHeap(), 0, outputA);
7693 HeapFree(GetProcessHeap(), 0, unixname);
7694 return ret;
7697 /*****************************************************************************
7698 * ScheduleJob [WINSPOOL.@]
7701 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7703 opened_printer_t *printer;
7704 BOOL ret = FALSE;
7705 struct list *cursor, *cursor2;
7707 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7708 EnterCriticalSection(&printer_handles_cs);
7709 printer = get_opened_printer(hPrinter);
7710 if(!printer)
7711 goto end;
7713 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7715 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7716 HANDLE hf;
7718 if(job->job_id != dwJobID) continue;
7720 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7721 if(hf != INVALID_HANDLE_VALUE)
7723 PRINTER_INFO_5W *pi5;
7724 DWORD needed;
7725 HKEY hkey;
7726 WCHAR output[1024];
7727 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7728 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7730 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7731 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7732 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7733 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7734 debugstr_w(pi5->pPortName));
7736 output[0] = 0;
7738 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7739 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7741 DWORD type, count = sizeof(output);
7742 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7743 RegCloseKey(hkey);
7745 if(output[0] == '|')
7747 ret = schedule_pipe(output + 1, job->filename);
7749 else if(output[0])
7751 ret = schedule_unixfile(output, job->filename);
7753 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7755 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7757 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7759 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7761 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7763 ret = schedule_file(job->filename);
7765 else
7767 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7769 HeapFree(GetProcessHeap(), 0, pi5);
7770 CloseHandle(hf);
7771 DeleteFileW(job->filename);
7773 list_remove(cursor);
7774 HeapFree(GetProcessHeap(), 0, job->document_title);
7775 HeapFree(GetProcessHeap(), 0, job->filename);
7776 HeapFree(GetProcessHeap(), 0, job);
7777 break;
7779 end:
7780 LeaveCriticalSection(&printer_handles_cs);
7781 return ret;
7784 /*****************************************************************************
7785 * StartDocDlgA [WINSPOOL.@]
7787 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7789 UNICODE_STRING usBuffer;
7790 DOCINFOW docW;
7791 LPWSTR retW;
7792 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7793 LPSTR ret = NULL;
7795 docW.cbSize = sizeof(docW);
7796 if (doc->lpszDocName)
7798 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7799 if (!(docW.lpszDocName = docnameW)) return NULL;
7801 if (doc->lpszOutput)
7803 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7804 if (!(docW.lpszOutput = outputW)) return NULL;
7806 if (doc->lpszDatatype)
7808 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7809 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7811 docW.fwType = doc->fwType;
7813 retW = StartDocDlgW(hPrinter, &docW);
7815 if(retW)
7817 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7818 ret = HeapAlloc(GetProcessHeap(), 0, len);
7819 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7820 HeapFree(GetProcessHeap(), 0, retW);
7823 HeapFree(GetProcessHeap(), 0, datatypeW);
7824 HeapFree(GetProcessHeap(), 0, outputW);
7825 HeapFree(GetProcessHeap(), 0, docnameW);
7827 return ret;
7830 /*****************************************************************************
7831 * StartDocDlgW [WINSPOOL.@]
7833 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7834 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7835 * port is "FILE:". Also returns the full path if passed a relative path.
7837 * The caller should free the returned string from the process heap.
7839 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7841 LPWSTR ret = NULL;
7842 DWORD len, attr;
7844 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7846 PRINTER_INFO_5W *pi5;
7847 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7848 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7849 return NULL;
7850 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7851 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7852 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7854 HeapFree(GetProcessHeap(), 0, pi5);
7855 return NULL;
7857 HeapFree(GetProcessHeap(), 0, pi5);
7860 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7862 LPWSTR name;
7864 if (get_filename(&name))
7866 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7868 HeapFree(GetProcessHeap(), 0, name);
7869 return NULL;
7871 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7872 GetFullPathNameW(name, len, ret, NULL);
7873 HeapFree(GetProcessHeap(), 0, name);
7875 return ret;
7878 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7879 return NULL;
7881 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7882 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7884 attr = GetFileAttributesW(ret);
7885 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7887 HeapFree(GetProcessHeap(), 0, ret);
7888 ret = NULL;
7890 return ret;