winspool: Use the backend for AddPortW.
[wine.git] / dlls / winspool.drv / info.c
blob67c12526c378f691b222ee52726d6e300ec97c88
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 HANDLE backend_printer;
113 jobqueue_t *queue;
114 started_doc_t *doc;
115 } opened_printer_t;
117 typedef struct {
118 struct list entry;
119 DWORD job_id;
120 WCHAR *filename;
121 WCHAR *document_title;
122 } job_t;
125 typedef struct {
126 LPCWSTR envname;
127 LPCWSTR subdir;
128 DWORD driverversion;
129 LPCWSTR versionregpath;
130 LPCWSTR versionsubdir;
131 } printenv_t;
133 /* ############################### */
135 static struct list monitor_handles = LIST_INIT( monitor_handles );
136 static monitor_t * pm_localport;
138 static opened_printer_t **printer_handles;
139 static UINT nb_printer_handles;
140 static LONG next_job_id = 1;
142 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
143 WORD fwCapability, LPSTR lpszOutput,
144 LPDEVMODEA lpdm );
145 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
146 LPSTR lpszDevice, LPSTR lpszPort,
147 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
148 DWORD fwMode );
150 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
151 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
152 'c','o','n','t','r','o','l','\\',
153 'P','r','i','n','t','\\',
154 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
155 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
157 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
158 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
159 'C','o','n','t','r','o','l','\\',
160 'P','r','i','n','t','\\',
161 'M','o','n','i','t','o','r','s','\\',0};
163 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
164 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
165 'C','o','n','t','r','o','l','\\',
166 'P','r','i','n','t','\\',
167 'P','r','i','n','t','e','r','s',0};
169 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
171 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
172 'M','i','c','r','o','s','o','f','t','\\',
173 'W','i','n','d','o','w','s',' ','N','T','\\',
174 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'W','i','n','d','o','w','s',0};
177 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
178 'M','i','c','r','o','s','o','f','t','\\',
179 'W','i','n','d','o','w','s',' ','N','T','\\',
180 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
181 'D','e','v','i','c','e','s',0};
183 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
184 'M','i','c','r','o','s','o','f','t','\\',
185 'W','i','n','d','o','w','s',' ','N','T','\\',
186 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
187 'P','o','r','t','s',0};
189 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
190 'M','i','c','r','o','s','o','f','t','\\',
191 'W','i','n','d','o','w','s',' ','N','T','\\',
192 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
193 'P','r','i','n','t','e','r','P','o','r','t','s',0};
195 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
196 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
197 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x64W[] = {'x','6','4',0};
201 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
203 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
204 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
205 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
207 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
208 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
210 static const WCHAR backslashW[] = {'\\',0};
211 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
212 'i','o','n',' ','F','i','l','e',0};
213 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
214 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
215 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
216 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
217 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
218 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
219 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
220 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
221 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
222 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
223 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
224 static const WCHAR NameW[] = {'N','a','m','e',0};
225 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
226 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
227 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
228 static const WCHAR PortW[] = {'P','o','r','t',0};
229 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
230 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
234 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
235 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW[] = {0};
245 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
247 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
248 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
249 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
251 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
252 'D','o','c','u','m','e','n','t',0};
254 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
255 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
256 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
257 0, sizeof(DRIVER_INFO_8W)};
260 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
261 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
262 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
263 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
264 sizeof(PRINTER_INFO_9W)};
266 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
267 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
268 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
270 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
272 /******************************************************************
273 * validate the user-supplied printing-environment [internal]
275 * PARAMS
276 * env [I] PTR to Environment-String or NULL
278 * RETURNS
279 * Failure: NULL
280 * Success: PTR to printenv_t
282 * NOTES
283 * An empty string is handled the same way as NULL.
284 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
288 static const printenv_t * validate_envW(LPCWSTR env)
290 const printenv_t *result = NULL;
291 unsigned int i;
293 TRACE("testing %s\n", debugstr_w(env));
294 if (env && env[0])
296 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
298 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
300 result = all_printenv[i];
301 break;
305 if (result == NULL) {
306 FIXME("unsupported Environment: %s\n", debugstr_w(env));
307 SetLastError(ERROR_INVALID_ENVIRONMENT);
309 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
311 else
313 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
315 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
317 return result;
321 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
322 if passed a NULL string. This returns NULLs to the result.
324 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
326 if ( (src) )
328 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
329 return usBufferPtr->Buffer;
331 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
332 return NULL;
335 static LPWSTR strdupW(LPCWSTR p)
337 LPWSTR ret;
338 DWORD len;
340 if(!p) return NULL;
341 len = (strlenW(p) + 1) * sizeof(WCHAR);
342 ret = HeapAlloc(GetProcessHeap(), 0, len);
343 memcpy(ret, p, len);
344 return ret;
347 static LPSTR strdupWtoA( LPCWSTR str )
349 LPSTR ret;
350 INT len;
352 if (!str) return NULL;
353 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
354 ret = HeapAlloc( GetProcessHeap(), 0, len );
355 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
356 return ret;
359 /******************************************************************
360 * Return the number of bytes for an multi_sz string.
361 * The result includes all \0s
362 * (specifically the extra \0, that is needed as multi_sz terminator).
364 #if 0
365 static int multi_sz_lenW(const WCHAR *str)
367 const WCHAR *ptr = str;
368 if(!str) return 0;
371 ptr += lstrlenW(ptr) + 1;
372 } while(*ptr);
374 return (ptr - str + 1) * sizeof(WCHAR);
376 #endif
377 /* ################################ */
379 static int multi_sz_lenA(const char *str)
381 const char *ptr = str;
382 if(!str) return 0;
385 ptr += lstrlenA(ptr) + 1;
386 } while(*ptr);
388 return ptr - str + 1;
391 static void
392 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
393 char qbuf[200];
395 /* If forcing, or no profile string entry for device yet, set the entry
397 * The always change entry if not WINEPS yet is discussable.
399 if (force ||
400 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
401 !strcmp(qbuf,"*") ||
402 !strstr(qbuf,"WINEPS.DRV")
404 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
405 HKEY hkey;
407 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
408 WriteProfileStringA("windows","device",buf);
409 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
410 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
411 RegCloseKey(hkey);
413 HeapFree(GetProcessHeap(),0,buf);
417 static BOOL add_printer_driver(const char *name)
419 DRIVER_INFO_3A di3a;
421 static char driver_9x[] = "wineps16.drv",
422 driver_nt[] = "wineps.drv",
423 env_9x[] = "Windows 4.0",
424 env_nt[] = "Windows NT x86",
425 data_file[] = "generic.ppd",
426 default_data_type[] = "RAW";
428 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
429 di3a.cVersion = 3;
430 di3a.pName = (char *)name;
431 di3a.pEnvironment = env_nt;
432 di3a.pDriverPath = driver_nt;
433 di3a.pDataFile = data_file;
434 di3a.pConfigFile = driver_nt;
435 di3a.pDefaultDataType = default_data_type;
437 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
438 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
440 di3a.cVersion = 0;
441 di3a.pEnvironment = env_9x;
442 di3a.pDriverPath = driver_9x;
443 di3a.pConfigFile = driver_9x;
444 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
445 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
447 return TRUE;
450 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
451 debugstr_a(di3a.pEnvironment), GetLastError());
452 return FALSE;
455 #ifdef SONAME_LIBCUPS
456 static typeof(cupsFreeDests) *pcupsFreeDests;
457 static typeof(cupsGetDests) *pcupsGetDests;
458 static typeof(cupsGetPPD) *pcupsGetPPD;
459 static typeof(cupsPrintFile) *pcupsPrintFile;
460 static void *cupshandle;
462 static BOOL CUPS_LoadPrinters(void)
464 int i, nrofdests;
465 BOOL hadprinter = FALSE, haddefault = FALSE;
466 cups_dest_t *dests;
467 PRINTER_INFO_2A pinfo2a;
468 char *port,*devline;
469 HKEY hkeyPrinter, hkeyPrinters, hkey;
470 char loaderror[256];
472 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
473 if (!cupshandle) {
474 TRACE("%s\n", loaderror);
475 return FALSE;
477 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
479 #define DYNCUPS(x) \
480 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
481 if (!p##x) return FALSE;
483 DYNCUPS(cupsFreeDests);
484 DYNCUPS(cupsGetPPD);
485 DYNCUPS(cupsGetDests);
486 DYNCUPS(cupsPrintFile);
487 #undef DYNCUPS
489 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
490 ERROR_SUCCESS) {
491 ERR("Can't create Printers key\n");
492 return FALSE;
495 nrofdests = pcupsGetDests(&dests);
496 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
497 for (i=0;i<nrofdests;i++) {
498 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
499 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
500 sprintf(port,"LPR:%s", dests[i].name);
501 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
502 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
503 sprintf(devline, "WINEPS.DRV,%s", port);
504 WriteProfileStringA("devices", dests[i].name, devline);
505 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
506 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
507 RegCloseKey(hkey);
510 lstrcatA(devline, ",15,45");
511 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
512 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
513 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
514 RegCloseKey(hkey);
517 HeapFree(GetProcessHeap(), 0, devline);
519 TRACE("Printer %d: %s\n", i, dests[i].name);
520 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
521 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
522 and continue */
523 TRACE("Printer already exists\n");
524 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
525 RegCloseKey(hkeyPrinter);
526 } else {
527 static CHAR data_type[] = "RAW",
528 print_proc[] = "WinPrint",
529 comment[] = "WINEPS Printer using CUPS",
530 location[] = "<physical location of printer>",
531 params[] = "<parameters?>",
532 share_name[] = "<share name?>",
533 sep_file[] = "<sep file?>";
535 add_printer_driver(dests[i].name);
537 memset(&pinfo2a,0,sizeof(pinfo2a));
538 pinfo2a.pPrinterName = dests[i].name;
539 pinfo2a.pDatatype = data_type;
540 pinfo2a.pPrintProcessor = print_proc;
541 pinfo2a.pDriverName = dests[i].name;
542 pinfo2a.pComment = comment;
543 pinfo2a.pLocation = location;
544 pinfo2a.pPortName = port;
545 pinfo2a.pParameters = params;
546 pinfo2a.pShareName = share_name;
547 pinfo2a.pSepFile = sep_file;
549 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
550 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
551 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
554 HeapFree(GetProcessHeap(),0,port);
556 hadprinter = TRUE;
557 if (dests[i].is_default) {
558 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
559 haddefault = TRUE;
562 if (hadprinter & !haddefault)
563 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
564 pcupsFreeDests(nrofdests, dests);
565 RegCloseKey(hkeyPrinters);
566 return hadprinter;
568 #endif
570 static BOOL
571 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
572 PRINTER_INFO_2A pinfo2a;
573 char *e,*s,*name,*prettyname,*devname;
574 BOOL ret = FALSE, set_default = FALSE;
575 char *port = NULL, *devline,*env_default;
576 HKEY hkeyPrinter, hkeyPrinters, hkey;
578 while (isspace(*pent)) pent++;
579 s = strchr(pent,':');
580 if(s) *s='\0';
581 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
582 strcpy(name,pent);
583 if(s) {
584 *s=':';
585 pent = s;
586 } else
587 pent = "";
589 TRACE("name=%s entry=%s\n",name, pent);
591 if(ispunct(*name)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
593 goto end;
596 if(strstr(pent,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
598 goto end;
601 /* Determine whether this is a postscript printer. */
603 ret = TRUE;
604 env_default = getenv("PRINTER");
605 prettyname = name;
606 /* Get longest name, usually the one at the right for later display. */
607 while((s=strchr(prettyname,'|'))) {
608 *s = '\0';
609 e = s;
610 while(isspace(*--e)) *e = '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname));
612 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
613 for(prettyname = s+1; isspace(*prettyname); prettyname++)
616 e = prettyname + strlen(prettyname);
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname = prettyname;
624 if (strlen(devname)>=CCHDEVICENAME-1)
625 devname = name;
626 if (strlen(devname)>=CCHDEVICENAME-1) {
627 ret = FALSE;
628 goto end;
631 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
632 sprintf(port,"LPR:%s",name);
634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
636 sprintf(devline, "WINEPS.DRV,%s", port);
637 WriteProfileStringA("devices", devname, devline);
638 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
639 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
640 RegCloseKey(hkey);
643 lstrcatA(devline, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
647 RegCloseKey(hkey);
650 HeapFree(GetProcessHeap(),0,devline);
652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
653 ERROR_SUCCESS) {
654 ERR("Can't create Printers key\n");
655 ret = FALSE;
656 goto end;
658 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
660 and continue */
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
663 RegCloseKey(hkeyPrinter);
664 } else {
665 static CHAR data_type[] = "RAW",
666 print_proc[] = "WinPrint",
667 comment[] = "WINEPS Printer using LPR",
668 params[] = "<parameters?>",
669 share_name[] = "<share name?>",
670 sep_file[] = "<sep file?>";
672 add_printer_driver(devname);
674 memset(&pinfo2a,0,sizeof(pinfo2a));
675 pinfo2a.pPrinterName = devname;
676 pinfo2a.pDatatype = data_type;
677 pinfo2a.pPrintProcessor = print_proc;
678 pinfo2a.pDriverName = devname;
679 pinfo2a.pComment = comment;
680 pinfo2a.pLocation = prettyname;
681 pinfo2a.pPortName = port;
682 pinfo2a.pParameters = params;
683 pinfo2a.pShareName = share_name;
684 pinfo2a.pSepFile = sep_file;
686 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
688 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
691 RegCloseKey(hkeyPrinters);
693 if (isfirst || set_default)
694 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
696 end:
697 HeapFree(GetProcessHeap(), 0, port);
698 HeapFree(GetProcessHeap(), 0, name);
699 return ret;
702 static BOOL
703 PRINTCAP_LoadPrinters(void) {
704 BOOL hadprinter = FALSE;
705 char buf[200];
706 FILE *f;
707 char *pent = NULL;
708 BOOL had_bash = FALSE;
710 f = fopen("/etc/printcap","r");
711 if (!f)
712 return FALSE;
714 while(fgets(buf,sizeof(buf),f)) {
715 char *start, *end;
717 end=strchr(buf,'\n');
718 if (end) *end='\0';
720 start = buf;
721 while(isspace(*start)) start++;
722 if(*start == '#' || *start == '\0')
723 continue;
725 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
726 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
727 HeapFree(GetProcessHeap(),0,pent);
728 pent = NULL;
731 if (end && *--end == '\\') {
732 *end = '\0';
733 had_bash = TRUE;
734 } else
735 had_bash = FALSE;
737 if (pent) {
738 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
739 strcat(pent,start);
740 } else {
741 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
742 strcpy(pent,start);
746 if(pent) {
747 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
748 HeapFree(GetProcessHeap(),0,pent);
750 fclose(f);
751 return hadprinter;
754 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
756 if (value)
757 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
758 (lstrlenW(value) + 1) * sizeof(WCHAR));
759 else
760 return ERROR_FILE_NOT_FOUND;
763 /******************************************************************
764 * monitor_unload [internal]
766 * release a printmonitor and unload it from memory, when needed
769 static void monitor_unload(monitor_t * pm)
771 if (pm == NULL) return;
772 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
774 EnterCriticalSection(&monitor_handles_cs);
776 if (pm->refcount) pm->refcount--;
778 if (pm->refcount == 0) {
779 list_remove(&pm->entry);
780 FreeLibrary(pm->hdll);
781 HeapFree(GetProcessHeap(), 0, pm->name);
782 HeapFree(GetProcessHeap(), 0, pm->dllname);
783 HeapFree(GetProcessHeap(), 0, pm);
785 LeaveCriticalSection(&monitor_handles_cs);
788 /******************************************************************
789 * monitor_load [internal]
791 * load a printmonitor, get the dllname from the registry, when needed
792 * initialize the monitor and dump found function-pointers
794 * On failure, SetLastError() is called and NULL is returned
797 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
799 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
800 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
801 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
802 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
803 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
805 monitor_t * pm = NULL;
806 monitor_t * cursor;
807 LPWSTR regroot = NULL;
808 LPWSTR driver = dllname;
810 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
811 /* Is the Monitor already loaded? */
812 EnterCriticalSection(&monitor_handles_cs);
814 if (name) {
815 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
817 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
818 pm = cursor;
819 break;
824 if (pm == NULL) {
825 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
826 if (pm == NULL) goto cleanup;
827 list_add_tail(&monitor_handles, &pm->entry);
829 pm->refcount++;
831 if (pm->name == NULL) {
832 /* Load the monitor */
833 LPMONITOREX pmonitorEx;
834 DWORD len;
836 if (name) {
837 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
838 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
841 if (regroot) {
842 lstrcpyW(regroot, MonitorsW);
843 lstrcatW(regroot, name);
844 /* Get the Driver from the Registry */
845 if (driver == NULL) {
846 HKEY hroot;
847 DWORD namesize;
848 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
849 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
850 &namesize) == ERROR_SUCCESS) {
851 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
852 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
854 RegCloseKey(hroot);
859 pm->name = strdupW(name);
860 pm->dllname = strdupW(driver);
862 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
863 monitor_unload(pm);
864 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
865 pm = NULL;
866 goto cleanup;
869 pm->hdll = LoadLibraryW(driver);
870 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
872 if (pm->hdll == NULL) {
873 monitor_unload(pm);
874 SetLastError(ERROR_MOD_NOT_FOUND);
875 pm = NULL;
876 goto cleanup;
879 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
880 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
881 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
882 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
883 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
886 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
887 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
888 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
889 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
890 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
892 if (pInitializePrintMonitorUI != NULL) {
893 pm->monitorUI = pInitializePrintMonitorUI();
894 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
895 if (pm->monitorUI) {
896 TRACE( "0x%08x: dwMonitorSize (%d)\n",
897 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
902 if (pInitializePrintMonitor && regroot) {
903 pmonitorEx = pInitializePrintMonitor(regroot);
904 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
905 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
907 if (pmonitorEx) {
908 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
909 pm->monitor = &(pmonitorEx->Monitor);
913 if (pm->monitor) {
914 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
918 if (!pm->monitor && regroot) {
919 if (pInitializePrintMonitor2 != NULL) {
920 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
922 if (pInitializeMonitorEx != NULL) {
923 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
925 if (pInitializeMonitor != NULL) {
926 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
929 if (!pm->monitor && !pm->monitorUI) {
930 monitor_unload(pm);
931 SetLastError(ERROR_PROC_NOT_FOUND);
932 pm = NULL;
935 cleanup:
936 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
937 pm->refcount++;
938 pm_localport = pm;
940 LeaveCriticalSection(&monitor_handles_cs);
941 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
942 HeapFree(GetProcessHeap(), 0, regroot);
943 TRACE("=> %p\n", pm);
944 return pm;
947 /******************************************************************
948 * get_servername_from_name (internal)
950 * for an external server, a copy of the serverpart from the full name is returned
953 static LPWSTR get_servername_from_name(LPCWSTR name)
955 LPWSTR server;
956 LPWSTR ptr;
957 WCHAR buffer[MAX_PATH];
958 DWORD len;
960 if (name == NULL) return NULL;
961 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
963 server = strdupW(&name[2]); /* skip over both backslash */
964 if (server == NULL) return NULL;
966 /* strip '\' and the printername */
967 ptr = strchrW(server, '\\');
968 if (ptr) ptr[0] = '\0';
970 TRACE("found %s\n", debugstr_w(server));
972 len = sizeof(buffer)/sizeof(buffer[0]);
973 if (GetComputerNameW(buffer, &len)) {
974 if (lstrcmpW(buffer, server) == 0) {
975 /* The requested Servername is our computername */
976 HeapFree(GetProcessHeap(), 0, server);
977 return NULL;
980 return server;
983 /******************************************************************
984 * get_basename_from_name (internal)
986 * skip over the serverpart from the full name
989 static LPCWSTR get_basename_from_name(LPCWSTR name)
991 if (name == NULL) return NULL;
992 if ((name[0] == '\\') && (name[1] == '\\')) {
993 /* skip over the servername and search for the following '\' */
994 name = strchrW(&name[2], '\\');
995 if ((name) && (name[1])) {
996 /* found a separator ('\') followed by a name:
997 skip over the separator and return the rest */
998 name++;
1000 else
1002 /* no basename present (we found only a servername) */
1003 return NULL;
1006 return name;
1009 /******************************************************************
1010 * get_opened_printer_entry
1011 * Get the first place empty in the opened printer table
1013 * ToDo:
1014 * - pDefault is ignored
1016 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1018 UINT_PTR handle = nb_printer_handles, i;
1019 jobqueue_t *queue = NULL;
1020 opened_printer_t *printer = NULL;
1021 LPWSTR servername;
1022 LPCWSTR printername;
1024 if ((backend == NULL) && !load_backend()) return NULL;
1026 servername = get_servername_from_name(name);
1027 if (servername) {
1028 FIXME("server %s not supported\n", debugstr_w(servername));
1029 HeapFree(GetProcessHeap(), 0, servername);
1030 SetLastError(ERROR_INVALID_PRINTER_NAME);
1031 return NULL;
1034 printername = get_basename_from_name(name);
1035 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1037 /* an empty printername is invalid */
1038 if (printername && (!printername[0])) {
1039 SetLastError(ERROR_INVALID_PARAMETER);
1040 return NULL;
1043 EnterCriticalSection(&printer_handles_cs);
1045 for (i = 0; i < nb_printer_handles; i++)
1047 if (!printer_handles[i])
1049 if(handle == nb_printer_handles)
1050 handle = i;
1052 else
1054 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1055 queue = printer_handles[i]->queue;
1059 if (handle >= nb_printer_handles)
1061 opened_printer_t **new_array;
1062 if (printer_handles)
1063 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1064 (nb_printer_handles + 16) * sizeof(*new_array) );
1065 else
1066 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1067 (nb_printer_handles + 16) * sizeof(*new_array) );
1069 if (!new_array)
1071 handle = 0;
1072 goto end;
1074 printer_handles = new_array;
1075 nb_printer_handles += 16;
1078 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1080 handle = 0;
1081 goto end;
1084 /* get a printer handle from the backend */
1085 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1086 handle = 0;
1087 goto end;
1090 /* clone the base name. This is NULL for the printserver */
1091 printer->printername = strdupW(printername);
1093 /* clone the full name */
1094 printer->name = strdupW(name);
1095 if (name && (!printer->name)) {
1096 handle = 0;
1097 goto end;
1100 if(queue)
1101 printer->queue = queue;
1102 else
1104 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1105 if (!printer->queue) {
1106 handle = 0;
1107 goto end;
1109 list_init(&printer->queue->jobs);
1110 printer->queue->ref = 0;
1112 InterlockedIncrement(&printer->queue->ref);
1114 printer_handles[handle] = printer;
1115 handle++;
1116 end:
1117 LeaveCriticalSection(&printer_handles_cs);
1118 if (!handle && printer) {
1119 /* Something failed: Free all resources */
1120 HeapFree(GetProcessHeap(), 0, printer->printername);
1121 HeapFree(GetProcessHeap(), 0, printer->name);
1122 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1123 HeapFree(GetProcessHeap(), 0, printer);
1126 return (HANDLE)handle;
1129 /******************************************************************
1130 * get_opened_printer
1131 * Get the pointer to the opened printer referred by the handle
1133 static opened_printer_t *get_opened_printer(HANDLE hprn)
1135 UINT_PTR idx = (UINT_PTR)hprn;
1136 opened_printer_t *ret = NULL;
1138 EnterCriticalSection(&printer_handles_cs);
1140 if ((idx > 0) && (idx <= nb_printer_handles)) {
1141 ret = printer_handles[idx - 1];
1143 LeaveCriticalSection(&printer_handles_cs);
1144 return ret;
1147 /******************************************************************
1148 * get_opened_printer_name
1149 * Get the pointer to the opened printer name referred by the handle
1151 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1153 opened_printer_t *printer = get_opened_printer(hprn);
1154 if(!printer) return NULL;
1155 return printer->name;
1158 /******************************************************************
1159 * WINSPOOL_GetOpenedPrinterRegKey
1162 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1164 LPCWSTR name = get_opened_printer_name(hPrinter);
1165 DWORD ret;
1166 HKEY hkeyPrinters;
1168 if(!name) return ERROR_INVALID_HANDLE;
1170 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1171 ERROR_SUCCESS)
1172 return ret;
1174 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1176 ERR("Can't find opened printer %s in registry\n",
1177 debugstr_w(name));
1178 RegCloseKey(hkeyPrinters);
1179 return ERROR_INVALID_PRINTER_NAME; /* ? */
1181 RegCloseKey(hkeyPrinters);
1182 return ERROR_SUCCESS;
1185 void WINSPOOL_LoadSystemPrinters(void)
1187 HKEY hkey, hkeyPrinters;
1188 HANDLE hprn;
1189 DWORD needed, num, i;
1190 WCHAR PrinterName[256];
1191 BOOL done = FALSE;
1193 /* This ensures that all printer entries have a valid Name value. If causes
1194 problems later if they don't. If one is found to be missed we create one
1195 and set it equal to the name of the key */
1196 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1197 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1198 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1199 for(i = 0; i < num; i++) {
1200 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1201 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1202 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1203 set_reg_szW(hkey, NameW, PrinterName);
1205 RegCloseKey(hkey);
1210 RegCloseKey(hkeyPrinters);
1213 /* We want to avoid calling AddPrinter on printers as much as
1214 possible, because on cups printers this will (eventually) lead
1215 to a call to cupsGetPPD which takes forever, even with non-cups
1216 printers AddPrinter takes a while. So we'll tag all printers that
1217 were automatically added last time around, if they still exist
1218 we'll leave them be otherwise we'll delete them. */
1219 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1220 if(needed) {
1221 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1222 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1223 for(i = 0; i < num; i++) {
1224 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1225 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1226 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1227 DWORD dw = 1;
1228 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1229 RegCloseKey(hkey);
1231 ClosePrinter(hprn);
1236 HeapFree(GetProcessHeap(), 0, pi);
1240 #ifdef SONAME_LIBCUPS
1241 done = CUPS_LoadPrinters();
1242 #endif
1244 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1245 PRINTCAP_LoadPrinters();
1247 /* Now enumerate the list again and delete any printers that are still tagged */
1248 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1249 if(needed) {
1250 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1251 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1252 for(i = 0; i < num; i++) {
1253 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1254 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1255 BOOL delete_driver = FALSE;
1256 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1257 DWORD dw, type, size = sizeof(dw);
1258 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1259 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1260 DeletePrinter(hprn);
1261 delete_driver = TRUE;
1263 RegCloseKey(hkey);
1265 ClosePrinter(hprn);
1266 if(delete_driver)
1267 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1272 HeapFree(GetProcessHeap(), 0, pi);
1275 return;
1279 /******************************************************************
1280 * get_job
1282 * Get the pointer to the specified job.
1283 * Should hold the printer_handles_cs before calling.
1285 static job_t *get_job(HANDLE hprn, DWORD JobId)
1287 opened_printer_t *printer = get_opened_printer(hprn);
1288 job_t *job;
1290 if(!printer) return NULL;
1291 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1293 if(job->job_id == JobId)
1294 return job;
1296 return NULL;
1299 /***********************************************************
1300 * DEVMODEcpyAtoW
1302 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1304 BOOL Formname;
1305 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1306 DWORD size;
1308 Formname = (dmA->dmSize > off_formname);
1309 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1310 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1311 dmW->dmDeviceName, CCHDEVICENAME);
1312 if(!Formname) {
1313 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1314 dmA->dmSize - CCHDEVICENAME);
1315 } else {
1316 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1317 off_formname - CCHDEVICENAME);
1318 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1319 dmW->dmFormName, CCHFORMNAME);
1320 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1321 (off_formname + CCHFORMNAME));
1323 dmW->dmSize = size;
1324 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1325 dmA->dmDriverExtra);
1326 return dmW;
1329 /***********************************************************
1330 * DEVMODEdupWtoA
1331 * Creates an ansi copy of supplied devmode
1333 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1335 LPDEVMODEA dmA;
1336 DWORD size;
1338 if (!dmW) return NULL;
1339 size = dmW->dmSize - CCHDEVICENAME -
1340 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1342 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1343 if (!dmA) return NULL;
1345 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1346 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1348 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1349 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1350 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1352 else
1354 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1355 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1356 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1357 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1359 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1362 dmA->dmSize = size;
1363 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1364 return dmA;
1367 /******************************************************************
1368 * convert_printerinfo_W_to_A [internal]
1371 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1372 DWORD level, DWORD outlen, DWORD numentries)
1374 DWORD id = 0;
1375 LPSTR ptr;
1376 INT len;
1378 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1380 len = pi_sizeof[level] * numentries;
1381 ptr = (LPSTR) out + len;
1382 outlen -= len;
1384 /* copy the numbers of all PRINTER_INFO_* first */
1385 memcpy(out, pPrintersW, len);
1387 while (id < numentries) {
1388 switch (level) {
1389 case 1:
1391 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1392 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1394 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1395 if (piW->pDescription) {
1396 piA->pDescription = ptr;
1397 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1398 ptr, outlen, NULL, NULL);
1399 ptr += len;
1400 outlen -= len;
1402 if (piW->pName) {
1403 piA->pName = ptr;
1404 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1405 ptr, outlen, NULL, NULL);
1406 ptr += len;
1407 outlen -= len;
1409 if (piW->pComment) {
1410 piA->pComment = ptr;
1411 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1412 ptr, outlen, NULL, NULL);
1413 ptr += len;
1414 outlen -= len;
1416 break;
1419 case 2:
1421 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1422 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1423 LPDEVMODEA dmA;
1425 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1426 if (piW->pServerName) {
1427 piA->pServerName = ptr;
1428 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1429 ptr, outlen, NULL, NULL);
1430 ptr += len;
1431 outlen -= len;
1433 if (piW->pPrinterName) {
1434 piA->pPrinterName = ptr;
1435 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1436 ptr, outlen, NULL, NULL);
1437 ptr += len;
1438 outlen -= len;
1440 if (piW->pShareName) {
1441 piA->pShareName = ptr;
1442 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1443 ptr, outlen, NULL, NULL);
1444 ptr += len;
1445 outlen -= len;
1447 if (piW->pPortName) {
1448 piA->pPortName = ptr;
1449 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1450 ptr, outlen, NULL, NULL);
1451 ptr += len;
1452 outlen -= len;
1454 if (piW->pDriverName) {
1455 piA->pDriverName = ptr;
1456 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1457 ptr, outlen, NULL, NULL);
1458 ptr += len;
1459 outlen -= len;
1461 if (piW->pComment) {
1462 piA->pComment = ptr;
1463 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1464 ptr, outlen, NULL, NULL);
1465 ptr += len;
1466 outlen -= len;
1468 if (piW->pLocation) {
1469 piA->pLocation = ptr;
1470 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1471 ptr, outlen, NULL, NULL);
1472 ptr += len;
1473 outlen -= len;
1476 dmA = DEVMODEdupWtoA(piW->pDevMode);
1477 if (dmA) {
1478 /* align DEVMODEA to a DWORD boundary */
1479 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1480 ptr += len;
1481 outlen -= len;
1483 piA->pDevMode = (LPDEVMODEA) ptr;
1484 len = dmA->dmSize + dmA->dmDriverExtra;
1485 memcpy(ptr, dmA, len);
1486 HeapFree(GetProcessHeap(), 0, dmA);
1488 ptr += len;
1489 outlen -= len;
1492 if (piW->pSepFile) {
1493 piA->pSepFile = ptr;
1494 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1495 ptr, outlen, NULL, NULL);
1496 ptr += len;
1497 outlen -= len;
1499 if (piW->pPrintProcessor) {
1500 piA->pPrintProcessor = ptr;
1501 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1502 ptr, outlen, NULL, NULL);
1503 ptr += len;
1504 outlen -= len;
1506 if (piW->pDatatype) {
1507 piA->pDatatype = ptr;
1508 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1509 ptr, outlen, NULL, NULL);
1510 ptr += len;
1511 outlen -= len;
1513 if (piW->pParameters) {
1514 piA->pParameters = ptr;
1515 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1516 ptr, outlen, NULL, NULL);
1517 ptr += len;
1518 outlen -= len;
1520 if (piW->pSecurityDescriptor) {
1521 piA->pSecurityDescriptor = NULL;
1522 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1524 break;
1527 case 4:
1529 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1530 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1532 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1534 if (piW->pPrinterName) {
1535 piA->pPrinterName = ptr;
1536 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1537 ptr, outlen, NULL, NULL);
1538 ptr += len;
1539 outlen -= len;
1541 if (piW->pServerName) {
1542 piA->pServerName = ptr;
1543 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1544 ptr, outlen, NULL, NULL);
1545 ptr += len;
1546 outlen -= len;
1548 break;
1551 case 5:
1553 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1554 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1556 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1558 if (piW->pPrinterName) {
1559 piA->pPrinterName = ptr;
1560 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1561 ptr, outlen, NULL, NULL);
1562 ptr += len;
1563 outlen -= len;
1565 if (piW->pPortName) {
1566 piA->pPortName = ptr;
1567 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1568 ptr, outlen, NULL, NULL);
1569 ptr += len;
1570 outlen -= len;
1572 break;
1575 default:
1576 FIXME("for level %u\n", level);
1578 pPrintersW += pi_sizeof[level];
1579 out += pi_sizeof[level];
1580 id++;
1584 /***********************************************************
1585 * PRINTER_INFO_2AtoW
1586 * Creates a unicode copy of PRINTER_INFO_2A on heap
1588 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1590 LPPRINTER_INFO_2W piW;
1591 UNICODE_STRING usBuffer;
1593 if(!piA) return NULL;
1594 piW = HeapAlloc(heap, 0, sizeof(*piW));
1595 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1597 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1598 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1599 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1600 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1601 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1602 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1603 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1604 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1605 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1606 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1607 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1608 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1609 return piW;
1612 /***********************************************************
1613 * FREE_PRINTER_INFO_2W
1614 * Free PRINTER_INFO_2W and all strings
1616 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1618 if(!piW) return;
1620 HeapFree(heap,0,piW->pServerName);
1621 HeapFree(heap,0,piW->pPrinterName);
1622 HeapFree(heap,0,piW->pShareName);
1623 HeapFree(heap,0,piW->pPortName);
1624 HeapFree(heap,0,piW->pDriverName);
1625 HeapFree(heap,0,piW->pComment);
1626 HeapFree(heap,0,piW->pLocation);
1627 HeapFree(heap,0,piW->pDevMode);
1628 HeapFree(heap,0,piW->pSepFile);
1629 HeapFree(heap,0,piW->pPrintProcessor);
1630 HeapFree(heap,0,piW->pDatatype);
1631 HeapFree(heap,0,piW->pParameters);
1632 HeapFree(heap,0,piW);
1633 return;
1636 /******************************************************************
1637 * DeviceCapabilities [WINSPOOL.@]
1638 * DeviceCapabilitiesA [WINSPOOL.@]
1641 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1642 LPSTR pOutput, LPDEVMODEA lpdm)
1644 INT ret;
1646 if (!GDI_CallDeviceCapabilities16)
1648 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1649 (LPCSTR)104 );
1650 if (!GDI_CallDeviceCapabilities16) return -1;
1652 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1654 /* If DC_PAPERSIZE map POINT16s to POINTs */
1655 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1656 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1657 POINT *pt = (POINT *)pOutput;
1658 INT i;
1659 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1660 for(i = 0; i < ret; i++, pt++)
1662 pt->x = tmp[i].x;
1663 pt->y = tmp[i].y;
1665 HeapFree( GetProcessHeap(), 0, tmp );
1667 return ret;
1671 /*****************************************************************************
1672 * DeviceCapabilitiesW [WINSPOOL.@]
1674 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1677 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1678 WORD fwCapability, LPWSTR pOutput,
1679 const DEVMODEW *pDevMode)
1681 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1682 LPSTR pDeviceA = strdupWtoA(pDevice);
1683 LPSTR pPortA = strdupWtoA(pPort);
1684 INT ret;
1686 if(pOutput && (fwCapability == DC_BINNAMES ||
1687 fwCapability == DC_FILEDEPENDENCIES ||
1688 fwCapability == DC_PAPERNAMES)) {
1689 /* These need A -> W translation */
1690 INT size = 0, i;
1691 LPSTR pOutputA;
1692 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1693 dmA);
1694 if(ret == -1)
1695 return ret;
1696 switch(fwCapability) {
1697 case DC_BINNAMES:
1698 size = 24;
1699 break;
1700 case DC_PAPERNAMES:
1701 case DC_FILEDEPENDENCIES:
1702 size = 64;
1703 break;
1705 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1706 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1707 dmA);
1708 for(i = 0; i < ret; i++)
1709 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1710 pOutput + (i * size), size);
1711 HeapFree(GetProcessHeap(), 0, pOutputA);
1712 } else {
1713 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1714 (LPSTR)pOutput, dmA);
1716 HeapFree(GetProcessHeap(),0,pPortA);
1717 HeapFree(GetProcessHeap(),0,pDeviceA);
1718 HeapFree(GetProcessHeap(),0,dmA);
1719 return ret;
1722 /******************************************************************
1723 * DocumentPropertiesA [WINSPOOL.@]
1725 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1727 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1728 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1729 LPDEVMODEA pDevModeInput,DWORD fMode )
1731 LPSTR lpName = pDeviceName;
1732 static CHAR port[] = "LPT1:";
1733 LONG ret;
1735 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1736 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1739 if(!pDeviceName) {
1740 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1741 if(!lpNameW) {
1742 ERR("no name from hPrinter?\n");
1743 SetLastError(ERROR_INVALID_HANDLE);
1744 return -1;
1746 lpName = strdupWtoA(lpNameW);
1749 if (!GDI_CallExtDeviceMode16)
1751 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1752 (LPCSTR)102 );
1753 if (!GDI_CallExtDeviceMode16) {
1754 ERR("No CallExtDeviceMode16?\n");
1755 return -1;
1758 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1759 pDevModeInput, NULL, fMode);
1761 if(!pDeviceName)
1762 HeapFree(GetProcessHeap(),0,lpName);
1763 return ret;
1767 /*****************************************************************************
1768 * DocumentPropertiesW (WINSPOOL.@)
1770 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1772 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1773 LPWSTR pDeviceName,
1774 LPDEVMODEW pDevModeOutput,
1775 LPDEVMODEW pDevModeInput, DWORD fMode)
1778 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1779 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1780 LPDEVMODEA pDevModeOutputA = NULL;
1781 LONG ret;
1783 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1784 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1785 fMode);
1786 if(pDevModeOutput) {
1787 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1788 if(ret < 0) return ret;
1789 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1791 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1792 pDevModeInputA, fMode);
1793 if(pDevModeOutput) {
1794 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1795 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1797 if(fMode == 0 && ret > 0)
1798 ret += (CCHDEVICENAME + CCHFORMNAME);
1799 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1800 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1801 return ret;
1804 /******************************************************************
1805 * OpenPrinterA [WINSPOOL.@]
1807 * See OpenPrinterW.
1810 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1811 LPPRINTER_DEFAULTSA pDefault)
1813 UNICODE_STRING lpPrinterNameW;
1814 UNICODE_STRING usBuffer;
1815 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1816 PWSTR pwstrPrinterNameW;
1817 BOOL ret;
1819 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1821 if(pDefault) {
1822 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1823 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1824 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1825 pDefaultW = &DefaultW;
1827 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1828 if(pDefault) {
1829 RtlFreeUnicodeString(&usBuffer);
1830 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1832 RtlFreeUnicodeString(&lpPrinterNameW);
1833 return ret;
1836 /******************************************************************
1837 * OpenPrinterW [WINSPOOL.@]
1839 * Open a Printer / Printserver or a Printer-Object
1841 * PARAMS
1842 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1843 * phPrinter [O] The resulting Handle is stored here
1844 * pDefault [I] PTR to Default Printer Settings or NULL
1846 * RETURNS
1847 * Success: TRUE
1848 * Failure: FALSE
1850 * NOTES
1851 * lpPrinterName is one of:
1852 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1853 *| Printer: "PrinterName"
1854 *| Printer-Object: "PrinterName,Job xxx"
1855 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1856 *| XcvPort: "Servername,XcvPort PortName"
1858 * BUGS
1859 *| Printer-Object not supported
1860 *| pDefaults is ignored
1863 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1866 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1867 if (pDefault) {
1868 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1869 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1872 if(!phPrinter) {
1873 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1874 SetLastError(ERROR_INVALID_PARAMETER);
1875 return FALSE;
1878 /* Get the unique handle of the printer or Printserver */
1879 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1880 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1881 return (*phPrinter != 0);
1884 /******************************************************************
1885 * AddMonitorA [WINSPOOL.@]
1887 * See AddMonitorW.
1890 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1892 LPWSTR nameW = NULL;
1893 INT len;
1894 BOOL res;
1895 LPMONITOR_INFO_2A mi2a;
1896 MONITOR_INFO_2W mi2w;
1898 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1899 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1900 debugstr_a(mi2a ? mi2a->pName : NULL),
1901 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1902 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1904 if (Level != 2) {
1905 SetLastError(ERROR_INVALID_LEVEL);
1906 return FALSE;
1909 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1910 if (mi2a == NULL) {
1911 return FALSE;
1914 if (pName) {
1915 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1916 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1917 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1920 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1921 if (mi2a->pName) {
1922 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1923 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1924 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1926 if (mi2a->pEnvironment) {
1927 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1928 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1929 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1931 if (mi2a->pDLLName) {
1932 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1933 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1934 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1937 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1939 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1940 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1941 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1943 HeapFree(GetProcessHeap(), 0, nameW);
1944 return (res);
1947 /******************************************************************************
1948 * AddMonitorW [WINSPOOL.@]
1950 * Install a Printmonitor
1952 * PARAMS
1953 * pName [I] Servername or NULL (local Computer)
1954 * Level [I] Structure-Level (Must be 2)
1955 * pMonitors [I] PTR to MONITOR_INFO_2
1957 * RETURNS
1958 * Success: TRUE
1959 * Failure: FALSE
1961 * NOTES
1962 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1965 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1967 LPMONITOR_INFO_2W mi2w;
1969 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1970 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1971 debugstr_w(mi2w ? mi2w->pName : NULL),
1972 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1973 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1975 if ((backend == NULL) && !load_backend()) return FALSE;
1977 if (Level != 2) {
1978 SetLastError(ERROR_INVALID_LEVEL);
1979 return FALSE;
1982 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1983 if (mi2w == NULL) {
1984 return FALSE;
1987 return backend->fpAddMonitor(pName, Level, pMonitors);
1990 /******************************************************************
1991 * DeletePrinterDriverA [WINSPOOL.@]
1994 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1996 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1999 /******************************************************************
2000 * DeletePrinterDriverW [WINSPOOL.@]
2003 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2005 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2008 /******************************************************************
2009 * DeleteMonitorA [WINSPOOL.@]
2011 * See DeleteMonitorW.
2014 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2016 LPWSTR nameW = NULL;
2017 LPWSTR EnvironmentW = NULL;
2018 LPWSTR MonitorNameW = NULL;
2019 BOOL res;
2020 INT len;
2022 if (pName) {
2023 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2024 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2025 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2028 if (pEnvironment) {
2029 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2030 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2031 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2033 if (pMonitorName) {
2034 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2035 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2036 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2039 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2041 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2042 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2043 HeapFree(GetProcessHeap(), 0, nameW);
2044 return (res);
2047 /******************************************************************
2048 * DeleteMonitorW [WINSPOOL.@]
2050 * Delete a specific Printmonitor from a Printing-Environment
2052 * PARAMS
2053 * pName [I] Servername or NULL (local Computer)
2054 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2055 * pMonitorName [I] Name of the Monitor, that should be deleted
2057 * RETURNS
2058 * Success: TRUE
2059 * Failure: FALSE
2061 * NOTES
2062 * pEnvironment is ignored in Windows for the local Computer.
2065 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2068 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2069 debugstr_w(pMonitorName));
2071 if ((backend == NULL) && !load_backend()) return FALSE;
2073 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2077 /******************************************************************
2078 * DeletePortA [WINSPOOL.@]
2080 * See DeletePortW.
2083 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2085 LPWSTR nameW = NULL;
2086 LPWSTR portW = NULL;
2087 INT len;
2088 DWORD res;
2090 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2092 /* convert servername to unicode */
2093 if (pName) {
2094 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2095 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2096 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2099 /* convert portname to unicode */
2100 if (pPortName) {
2101 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2102 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2103 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2106 res = DeletePortW(nameW, hWnd, portW);
2107 HeapFree(GetProcessHeap(), 0, nameW);
2108 HeapFree(GetProcessHeap(), 0, portW);
2109 return res;
2112 /******************************************************************
2113 * DeletePortW [WINSPOOL.@]
2115 * Delete a specific Port
2117 * PARAMS
2118 * pName [I] Servername or NULL (local Computer)
2119 * hWnd [I] Handle to parent Window for the Dialog-Box
2120 * pPortName [I] Name of the Port, that should be deleted
2122 * RETURNS
2123 * Success: TRUE
2124 * Failure: FALSE
2127 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2129 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2131 if ((backend == NULL) && !load_backend()) return FALSE;
2133 if (!pPortName) {
2134 SetLastError(RPC_X_NULL_REF_POINTER);
2135 return FALSE;
2138 return backend->fpDeletePort(pName, hWnd, pPortName);
2141 /******************************************************************************
2142 * SetPrinterW [WINSPOOL.@]
2144 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2146 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2147 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2148 return FALSE;
2151 /******************************************************************************
2152 * WritePrinter [WINSPOOL.@]
2154 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2156 opened_printer_t *printer;
2157 BOOL ret = FALSE;
2159 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2161 EnterCriticalSection(&printer_handles_cs);
2162 printer = get_opened_printer(hPrinter);
2163 if(!printer)
2165 SetLastError(ERROR_INVALID_HANDLE);
2166 goto end;
2169 if(!printer->doc)
2171 SetLastError(ERROR_SPL_NO_STARTDOC);
2172 goto end;
2175 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2176 end:
2177 LeaveCriticalSection(&printer_handles_cs);
2178 return ret;
2181 /*****************************************************************************
2182 * AddFormA [WINSPOOL.@]
2184 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2186 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2187 return 1;
2190 /*****************************************************************************
2191 * AddFormW [WINSPOOL.@]
2193 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2195 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2196 return 1;
2199 /*****************************************************************************
2200 * AddJobA [WINSPOOL.@]
2202 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2204 BOOL ret;
2205 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2206 DWORD needed;
2208 if(Level != 1) {
2209 SetLastError(ERROR_INVALID_LEVEL);
2210 return FALSE;
2213 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2215 if(ret) {
2216 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2217 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2218 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2219 if(*pcbNeeded > cbBuf) {
2220 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2221 ret = FALSE;
2222 } else {
2223 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2224 addjobA->JobId = addjobW->JobId;
2225 addjobA->Path = (char *)(addjobA + 1);
2226 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2229 return ret;
2232 /*****************************************************************************
2233 * AddJobW [WINSPOOL.@]
2235 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2237 opened_printer_t *printer;
2238 job_t *job;
2239 BOOL ret = FALSE;
2240 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2241 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2242 WCHAR path[MAX_PATH], filename[MAX_PATH];
2243 DWORD len;
2244 ADDJOB_INFO_1W *addjob;
2246 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2248 EnterCriticalSection(&printer_handles_cs);
2250 printer = get_opened_printer(hPrinter);
2252 if(!printer) {
2253 SetLastError(ERROR_INVALID_HANDLE);
2254 goto end;
2257 if(Level != 1) {
2258 SetLastError(ERROR_INVALID_LEVEL);
2259 goto end;
2262 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2263 if(!job)
2264 goto end;
2266 job->job_id = InterlockedIncrement(&next_job_id);
2268 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2269 if(path[len - 1] != '\\')
2270 path[len++] = '\\';
2271 memcpy(path + len, spool_path, sizeof(spool_path));
2272 sprintfW(filename, fmtW, path, job->job_id);
2274 len = strlenW(filename);
2275 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2276 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2277 job->document_title = strdupW(default_doc_title);
2278 list_add_tail(&printer->queue->jobs, &job->entry);
2280 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2281 if(*pcbNeeded <= cbBuf) {
2282 addjob = (ADDJOB_INFO_1W*)pData;
2283 addjob->JobId = job->job_id;
2284 addjob->Path = (WCHAR *)(addjob + 1);
2285 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2286 ret = TRUE;
2287 } else
2288 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2290 end:
2291 LeaveCriticalSection(&printer_handles_cs);
2292 return ret;
2295 /*****************************************************************************
2296 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2298 * Return the PATH for the Print-Processors
2300 * See GetPrintProcessorDirectoryW.
2304 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2305 DWORD level, LPBYTE Info,
2306 DWORD cbBuf, LPDWORD pcbNeeded)
2308 LPWSTR serverW = NULL;
2309 LPWSTR envW = NULL;
2310 BOOL ret;
2311 INT len;
2313 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2314 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2317 if (server) {
2318 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2319 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2320 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2323 if (env) {
2324 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2325 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2326 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2329 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2330 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2332 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2333 cbBuf, pcbNeeded);
2335 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2336 cbBuf, NULL, NULL) > 0;
2339 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2340 HeapFree(GetProcessHeap(), 0, envW);
2341 HeapFree(GetProcessHeap(), 0, serverW);
2342 return ret;
2345 /*****************************************************************************
2346 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2348 * Return the PATH for the Print-Processors
2350 * PARAMS
2351 * server [I] Servername (NT only) or NULL (local Computer)
2352 * env [I] Printing-Environment (see below) or NULL (Default)
2353 * level [I] Structure-Level (must be 1)
2354 * Info [O] PTR to Buffer that receives the Result
2355 * cbBuf [I] Size of Buffer at "Info"
2356 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2357 * required for the Buffer at "Info"
2359 * RETURNS
2360 * Success: TRUE and in pcbNeeded the Bytes used in Info
2361 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2362 * if cbBuf is too small
2364 * Native Values returned in Info on Success:
2365 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2366 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2367 *| win9x(Windows 4.0): "%winsysdir%"
2369 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2371 * BUGS
2372 * Only NULL or "" is supported for server
2375 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2376 DWORD level, LPBYTE Info,
2377 DWORD cbBuf, LPDWORD pcbNeeded)
2379 DWORD needed;
2380 const printenv_t * env_t;
2382 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2383 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2385 if(server != NULL && server[0]) {
2386 FIXME("server not supported: %s\n", debugstr_w(server));
2387 SetLastError(ERROR_INVALID_PARAMETER);
2388 return FALSE;
2391 env_t = validate_envW(env);
2392 if(!env_t) return FALSE; /* environment invalid or unsupported */
2394 if(level != 1) {
2395 WARN("(Level: %d) is ignored in win9x\n", level);
2396 SetLastError(ERROR_INVALID_LEVEL);
2397 return FALSE;
2400 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2401 needed = GetSystemDirectoryW(NULL, 0);
2402 /* add the Size for the Subdirectories */
2403 needed += lstrlenW(spoolprtprocsW);
2404 needed += lstrlenW(env_t->subdir);
2405 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2407 if(pcbNeeded) *pcbNeeded = needed;
2408 TRACE ("required: 0x%x/%d\n", needed, needed);
2409 if (needed > cbBuf) {
2410 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2411 return FALSE;
2413 if(pcbNeeded == NULL) {
2414 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2415 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2416 SetLastError(RPC_X_NULL_REF_POINTER);
2417 return FALSE;
2419 if(Info == NULL) {
2420 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2421 SetLastError(RPC_X_NULL_REF_POINTER);
2422 return FALSE;
2425 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2426 /* add the Subdirectories */
2427 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2428 lstrcatW((LPWSTR) Info, env_t->subdir);
2429 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2430 return TRUE;
2433 /*****************************************************************************
2434 * WINSPOOL_OpenDriverReg [internal]
2436 * opens the registry for the printer drivers depending on the given input
2437 * variable pEnvironment
2439 * RETURNS:
2440 * the opened hkey on success
2441 * NULL on error
2443 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2445 HKEY retval = NULL;
2446 LPWSTR buffer;
2447 const printenv_t * env;
2449 TRACE("(%s, %d)\n",
2450 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2452 if (!pEnvironment || unicode) {
2453 /* pEnvironment was NULL or a Unicode-String: use it direct */
2454 env = validate_envW(pEnvironment);
2456 else
2458 /* pEnvironment was an ANSI-String: convert to unicode first */
2459 LPWSTR buffer;
2460 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2461 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2462 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2463 env = validate_envW(buffer);
2464 HeapFree(GetProcessHeap(), 0, buffer);
2466 if (!env) return NULL;
2468 buffer = HeapAlloc( GetProcessHeap(), 0,
2469 (strlenW(DriversW) + strlenW(env->envname) +
2470 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2471 if(buffer) {
2472 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2473 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2474 HeapFree(GetProcessHeap(), 0, buffer);
2476 return retval;
2479 /*****************************************************************************
2480 * AddPrinterW [WINSPOOL.@]
2482 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2484 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2485 LPDEVMODEA dmA;
2486 LPDEVMODEW dmW;
2487 HANDLE retval;
2488 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2489 LONG size;
2490 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2491 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2492 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2493 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2494 statusW[] = {'S','t','a','t','u','s',0},
2495 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2497 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2499 if(pName != NULL) {
2500 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2501 SetLastError(ERROR_INVALID_PARAMETER);
2502 return 0;
2504 if(Level != 2) {
2505 ERR("Level = %d, unsupported!\n", Level);
2506 SetLastError(ERROR_INVALID_LEVEL);
2507 return 0;
2509 if(!pPrinter) {
2510 SetLastError(ERROR_INVALID_PARAMETER);
2511 return 0;
2513 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2514 ERROR_SUCCESS) {
2515 ERR("Can't create Printers key\n");
2516 return 0;
2518 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2519 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2520 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2521 RegCloseKey(hkeyPrinter);
2522 RegCloseKey(hkeyPrinters);
2523 return 0;
2525 RegCloseKey(hkeyPrinter);
2527 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2528 if(!hkeyDrivers) {
2529 ERR("Can't create Drivers key\n");
2530 RegCloseKey(hkeyPrinters);
2531 return 0;
2533 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2534 ERROR_SUCCESS) {
2535 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2536 RegCloseKey(hkeyPrinters);
2537 RegCloseKey(hkeyDrivers);
2538 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2539 return 0;
2541 RegCloseKey(hkeyDriver);
2542 RegCloseKey(hkeyDrivers);
2544 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2545 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2546 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2547 RegCloseKey(hkeyPrinters);
2548 return 0;
2551 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2552 ERROR_SUCCESS) {
2553 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2554 SetLastError(ERROR_INVALID_PRINTER_NAME);
2555 RegCloseKey(hkeyPrinters);
2556 return 0;
2558 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2559 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2560 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2562 /* See if we can load the driver. We may need the devmode structure anyway
2564 * FIXME:
2565 * Note that DocumentPropertiesW will briefly try to open the printer we
2566 * just create to find a DEVMODEA struct (it will use the WINEPS default
2567 * one in case it is not there, so we are ok).
2569 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2571 if(size < 0) {
2572 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2573 size = sizeof(DEVMODEW);
2575 if(pi->pDevMode)
2576 dmW = pi->pDevMode;
2577 else
2579 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2580 dmW->dmSize = size;
2581 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2583 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2584 HeapFree(GetProcessHeap(),0,dmW);
2585 dmW=NULL;
2587 else
2589 /* set devmode to printer name */
2590 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2594 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2595 and we support these drivers. NT writes DEVMODEW so somehow
2596 we'll need to distinguish between these when we support NT
2597 drivers */
2598 if (dmW)
2600 dmA = DEVMODEdupWtoA(dmW);
2601 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2602 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2603 HeapFree(GetProcessHeap(), 0, dmA);
2604 if(!pi->pDevMode)
2605 HeapFree(GetProcessHeap(), 0, dmW);
2607 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2608 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2609 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2610 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2612 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2613 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2614 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2615 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2616 (LPBYTE)&pi->Priority, sizeof(DWORD));
2617 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2618 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2619 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2620 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2621 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2622 (LPBYTE)&pi->Status, sizeof(DWORD));
2623 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2624 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2626 RegCloseKey(hkeyPrinter);
2627 RegCloseKey(hkeyPrinters);
2628 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2629 ERR("OpenPrinter failing\n");
2630 return 0;
2632 return retval;
2635 /*****************************************************************************
2636 * AddPrinterA [WINSPOOL.@]
2638 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2640 UNICODE_STRING pNameW;
2641 PWSTR pwstrNameW;
2642 PRINTER_INFO_2W *piW;
2643 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2644 HANDLE ret;
2646 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2647 if(Level != 2) {
2648 ERR("Level = %d, unsupported!\n", Level);
2649 SetLastError(ERROR_INVALID_LEVEL);
2650 return 0;
2652 pwstrNameW = asciitounicode(&pNameW,pName);
2653 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2655 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2657 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2658 RtlFreeUnicodeString(&pNameW);
2659 return ret;
2663 /*****************************************************************************
2664 * ClosePrinter [WINSPOOL.@]
2666 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2668 UINT_PTR i = (UINT_PTR)hPrinter;
2669 opened_printer_t *printer = NULL;
2670 BOOL ret = FALSE;
2672 TRACE("(%p)\n", hPrinter);
2674 EnterCriticalSection(&printer_handles_cs);
2676 if ((i > 0) && (i <= nb_printer_handles))
2677 printer = printer_handles[i - 1];
2680 if(printer)
2682 struct list *cursor, *cursor2;
2684 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2686 if (printer->backend_printer) {
2687 backend->fpClosePrinter(printer->backend_printer);
2690 if(printer->doc)
2691 EndDocPrinter(hPrinter);
2693 if(InterlockedDecrement(&printer->queue->ref) == 0)
2695 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2697 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2698 ScheduleJob(hPrinter, job->job_id);
2700 HeapFree(GetProcessHeap(), 0, printer->queue);
2703 HeapFree(GetProcessHeap(), 0, printer->printername);
2704 HeapFree(GetProcessHeap(), 0, printer->name);
2705 HeapFree(GetProcessHeap(), 0, printer);
2706 printer_handles[i - 1] = NULL;
2707 ret = TRUE;
2709 LeaveCriticalSection(&printer_handles_cs);
2710 return ret;
2713 /*****************************************************************************
2714 * DeleteFormA [WINSPOOL.@]
2716 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2718 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2719 return 1;
2722 /*****************************************************************************
2723 * DeleteFormW [WINSPOOL.@]
2725 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2727 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2728 return 1;
2731 /*****************************************************************************
2732 * DeletePrinter [WINSPOOL.@]
2734 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2736 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2737 HKEY hkeyPrinters, hkey;
2739 if(!lpNameW) {
2740 SetLastError(ERROR_INVALID_HANDLE);
2741 return FALSE;
2743 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2744 RegDeleteTreeW(hkeyPrinters, lpNameW);
2745 RegCloseKey(hkeyPrinters);
2747 WriteProfileStringW(devicesW, lpNameW, NULL);
2748 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2750 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2751 RegDeleteValueW(hkey, lpNameW);
2752 RegCloseKey(hkey);
2755 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2756 RegDeleteValueW(hkey, lpNameW);
2757 RegCloseKey(hkey);
2759 return TRUE;
2762 /*****************************************************************************
2763 * SetPrinterA [WINSPOOL.@]
2765 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2766 DWORD Command)
2768 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2769 return FALSE;
2772 /*****************************************************************************
2773 * SetJobA [WINSPOOL.@]
2775 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2776 LPBYTE pJob, DWORD Command)
2778 BOOL ret;
2779 LPBYTE JobW;
2780 UNICODE_STRING usBuffer;
2782 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2784 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2785 are all ignored by SetJob, so we don't bother copying them */
2786 switch(Level)
2788 case 0:
2789 JobW = NULL;
2790 break;
2791 case 1:
2793 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2794 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2796 JobW = (LPBYTE)info1W;
2797 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2798 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2799 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2800 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2801 info1W->Status = info1A->Status;
2802 info1W->Priority = info1A->Priority;
2803 info1W->Position = info1A->Position;
2804 info1W->PagesPrinted = info1A->PagesPrinted;
2805 break;
2807 case 2:
2809 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2810 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2812 JobW = (LPBYTE)info2W;
2813 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2814 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2815 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2816 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2817 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2818 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2819 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2820 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2821 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2822 info2W->Status = info2A->Status;
2823 info2W->Priority = info2A->Priority;
2824 info2W->Position = info2A->Position;
2825 info2W->StartTime = info2A->StartTime;
2826 info2W->UntilTime = info2A->UntilTime;
2827 info2W->PagesPrinted = info2A->PagesPrinted;
2828 break;
2830 case 3:
2831 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2832 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2833 break;
2834 default:
2835 SetLastError(ERROR_INVALID_LEVEL);
2836 return FALSE;
2839 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2841 switch(Level)
2843 case 1:
2845 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2846 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2847 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2848 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2849 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2850 break;
2852 case 2:
2854 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2855 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2856 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2857 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2858 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2859 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2860 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2861 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2862 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2863 break;
2866 HeapFree(GetProcessHeap(), 0, JobW);
2868 return ret;
2871 /*****************************************************************************
2872 * SetJobW [WINSPOOL.@]
2874 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2875 LPBYTE pJob, DWORD Command)
2877 BOOL ret = FALSE;
2878 job_t *job;
2880 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2881 FIXME("Ignoring everything other than document title\n");
2883 EnterCriticalSection(&printer_handles_cs);
2884 job = get_job(hPrinter, JobId);
2885 if(!job)
2886 goto end;
2888 switch(Level)
2890 case 0:
2891 break;
2892 case 1:
2894 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2895 HeapFree(GetProcessHeap(), 0, job->document_title);
2896 job->document_title = strdupW(info1->pDocument);
2897 break;
2899 case 2:
2901 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2902 HeapFree(GetProcessHeap(), 0, job->document_title);
2903 job->document_title = strdupW(info2->pDocument);
2904 break;
2906 case 3:
2907 break;
2908 default:
2909 SetLastError(ERROR_INVALID_LEVEL);
2910 goto end;
2912 ret = TRUE;
2913 end:
2914 LeaveCriticalSection(&printer_handles_cs);
2915 return ret;
2918 /*****************************************************************************
2919 * EndDocPrinter [WINSPOOL.@]
2921 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2923 opened_printer_t *printer;
2924 BOOL ret = FALSE;
2925 TRACE("(%p)\n", hPrinter);
2927 EnterCriticalSection(&printer_handles_cs);
2929 printer = get_opened_printer(hPrinter);
2930 if(!printer)
2932 SetLastError(ERROR_INVALID_HANDLE);
2933 goto end;
2936 if(!printer->doc)
2938 SetLastError(ERROR_SPL_NO_STARTDOC);
2939 goto end;
2942 CloseHandle(printer->doc->hf);
2943 ScheduleJob(hPrinter, printer->doc->job_id);
2944 HeapFree(GetProcessHeap(), 0, printer->doc);
2945 printer->doc = NULL;
2946 ret = TRUE;
2947 end:
2948 LeaveCriticalSection(&printer_handles_cs);
2949 return ret;
2952 /*****************************************************************************
2953 * EndPagePrinter [WINSPOOL.@]
2955 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2957 FIXME("(%p): stub\n", hPrinter);
2958 return TRUE;
2961 /*****************************************************************************
2962 * StartDocPrinterA [WINSPOOL.@]
2964 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2966 UNICODE_STRING usBuffer;
2967 DOC_INFO_2W doc2W;
2968 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2969 DWORD ret;
2971 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2972 or one (DOC_INFO_3) extra DWORDs */
2974 switch(Level) {
2975 case 2:
2976 doc2W.JobId = doc2->JobId;
2977 /* fall through */
2978 case 3:
2979 doc2W.dwMode = doc2->dwMode;
2980 /* fall through */
2981 case 1:
2982 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2983 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2984 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2985 break;
2987 default:
2988 SetLastError(ERROR_INVALID_LEVEL);
2989 return FALSE;
2992 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2994 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2995 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2996 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2998 return ret;
3001 /*****************************************************************************
3002 * StartDocPrinterW [WINSPOOL.@]
3004 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3006 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3007 opened_printer_t *printer;
3008 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3009 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3010 JOB_INFO_1W job_info;
3011 DWORD needed, ret = 0;
3012 HANDLE hf;
3013 WCHAR *filename;
3015 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3016 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3017 debugstr_w(doc->pDatatype));
3019 if(Level < 1 || Level > 3)
3021 SetLastError(ERROR_INVALID_LEVEL);
3022 return 0;
3025 EnterCriticalSection(&printer_handles_cs);
3026 printer = get_opened_printer(hPrinter);
3027 if(!printer)
3029 SetLastError(ERROR_INVALID_HANDLE);
3030 goto end;
3033 if(printer->doc)
3035 SetLastError(ERROR_INVALID_PRINTER_STATE);
3036 goto end;
3039 /* Even if we're printing to a file we still add a print job, we'll
3040 just ignore the spool file name */
3042 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3044 ERR("AddJob failed gle %u\n", GetLastError());
3045 goto end;
3048 if(doc->pOutputFile)
3049 filename = doc->pOutputFile;
3050 else
3051 filename = addjob->Path;
3053 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3054 if(hf == INVALID_HANDLE_VALUE)
3055 goto end;
3057 memset(&job_info, 0, sizeof(job_info));
3058 job_info.pDocument = doc->pDocName;
3059 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3061 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3062 printer->doc->hf = hf;
3063 ret = printer->doc->job_id = addjob->JobId;
3064 end:
3065 LeaveCriticalSection(&printer_handles_cs);
3067 return ret;
3070 /*****************************************************************************
3071 * StartPagePrinter [WINSPOOL.@]
3073 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3075 FIXME("(%p): stub\n", hPrinter);
3076 return TRUE;
3079 /*****************************************************************************
3080 * GetFormA [WINSPOOL.@]
3082 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3083 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3085 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3086 Level,pForm,cbBuf,pcbNeeded);
3087 return FALSE;
3090 /*****************************************************************************
3091 * GetFormW [WINSPOOL.@]
3093 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3094 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3096 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3097 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3098 return FALSE;
3101 /*****************************************************************************
3102 * SetFormA [WINSPOOL.@]
3104 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3105 LPBYTE pForm)
3107 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3108 return FALSE;
3111 /*****************************************************************************
3112 * SetFormW [WINSPOOL.@]
3114 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3115 LPBYTE pForm)
3117 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3118 return FALSE;
3121 /*****************************************************************************
3122 * ReadPrinter [WINSPOOL.@]
3124 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3125 LPDWORD pNoBytesRead)
3127 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3128 return FALSE;
3131 /*****************************************************************************
3132 * ResetPrinterA [WINSPOOL.@]
3134 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3136 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3137 return FALSE;
3140 /*****************************************************************************
3141 * ResetPrinterW [WINSPOOL.@]
3143 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3145 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3146 return FALSE;
3149 /*****************************************************************************
3150 * WINSPOOL_GetDWORDFromReg
3152 * Return DWORD associated with ValueName from hkey.
3154 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3156 DWORD sz = sizeof(DWORD), type, value = 0;
3157 LONG ret;
3159 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3161 if(ret != ERROR_SUCCESS) {
3162 WARN("Got ret = %d on name %s\n", ret, ValueName);
3163 return 0;
3165 if(type != REG_DWORD) {
3166 ERR("Got type %d\n", type);
3167 return 0;
3169 return value;
3173 /*****************************************************************************
3174 * get_filename_from_reg [internal]
3176 * Get ValueName from hkey storing result in out
3177 * when the Value in the registry has only a filename, use driverdir as prefix
3178 * outlen is space left in out
3179 * String is stored either as unicode or ascii
3183 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3184 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3186 WCHAR filename[MAX_PATH];
3187 DWORD size;
3188 DWORD type;
3189 LONG ret;
3190 LPWSTR buffer = filename;
3191 LPWSTR ptr;
3193 *needed = 0;
3194 size = sizeof(filename);
3195 buffer[0] = '\0';
3196 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3197 if (ret == ERROR_MORE_DATA) {
3198 TRACE("need dynamic buffer: %u\n", size);
3199 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3200 if (!buffer) {
3201 /* No Memory is bad */
3202 return FALSE;
3204 buffer[0] = '\0';
3205 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3208 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3209 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3210 return FALSE;
3213 ptr = buffer;
3214 while (ptr) {
3215 /* do we have a full path ? */
3216 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3217 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3219 if (!ret) {
3220 /* we must build the full Path */
3221 *needed += dirlen;
3222 if ((out) && (outlen > dirlen)) {
3223 if (unicode) {
3224 lstrcpyW((LPWSTR)out, driverdir);
3226 else
3228 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3230 out += dirlen;
3231 outlen -= dirlen;
3233 else
3234 out = NULL;
3237 /* write the filename */
3238 if (unicode) {
3239 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3240 if ((out) && (outlen >= size)) {
3241 lstrcpyW((LPWSTR)out, ptr);
3242 out += size;
3243 outlen -= size;
3245 else
3246 out = NULL;
3248 else
3250 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3251 if ((out) && (outlen >= size)) {
3252 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3253 out += size;
3254 outlen -= size;
3256 else
3257 out = NULL;
3259 *needed += size;
3260 ptr += lstrlenW(ptr)+1;
3261 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3264 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3266 /* write the multisz-termination */
3267 if (type == REG_MULTI_SZ) {
3268 size = (unicode) ? sizeof(WCHAR) : 1;
3270 *needed += size;
3271 if (out && (outlen >= size)) {
3272 memset (out, 0, size);
3275 return TRUE;
3278 /*****************************************************************************
3279 * WINSPOOL_GetStringFromReg
3281 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3282 * String is stored either as unicode or ascii.
3283 * Bit of a hack here to get the ValueName if we want ascii.
3285 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3286 DWORD buflen, DWORD *needed,
3287 BOOL unicode)
3289 DWORD sz = buflen, type;
3290 LONG ret;
3292 if(unicode)
3293 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3294 else {
3295 LPSTR ValueNameA = strdupWtoA(ValueName);
3296 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3297 HeapFree(GetProcessHeap(),0,ValueNameA);
3299 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3300 WARN("Got ret = %d\n", ret);
3301 *needed = 0;
3302 return FALSE;
3304 /* add space for terminating '\0' */
3305 sz += unicode ? sizeof(WCHAR) : 1;
3306 *needed = sz;
3308 if (ptr)
3309 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3311 return TRUE;
3314 /*****************************************************************************
3315 * WINSPOOL_GetDefaultDevMode
3317 * Get a default DevMode values for wineps.
3318 * FIXME - use ppd.
3321 static void WINSPOOL_GetDefaultDevMode(
3322 LPBYTE ptr,
3323 DWORD buflen, DWORD *needed,
3324 BOOL unicode)
3326 DEVMODEA dm;
3327 static const char szwps[] = "wineps.drv";
3329 /* fill default DEVMODE - should be read from ppd... */
3330 ZeroMemory( &dm, sizeof(dm) );
3331 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3332 dm.dmSpecVersion = DM_SPECVERSION;
3333 dm.dmDriverVersion = 1;
3334 dm.dmSize = sizeof(DEVMODEA);
3335 dm.dmDriverExtra = 0;
3336 dm.dmFields =
3337 DM_ORIENTATION | DM_PAPERSIZE |
3338 DM_PAPERLENGTH | DM_PAPERWIDTH |
3339 DM_SCALE |
3340 DM_COPIES |
3341 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3342 DM_YRESOLUTION | DM_TTOPTION;
3344 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3345 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3346 dm.u1.s1.dmPaperLength = 2970;
3347 dm.u1.s1.dmPaperWidth = 2100;
3349 dm.u1.s1.dmScale = 100;
3350 dm.u1.s1.dmCopies = 1;
3351 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3352 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3353 /* dm.dmColor */
3354 /* dm.dmDuplex */
3355 dm.dmYResolution = 300; /* 300dpi */
3356 dm.dmTTOption = DMTT_BITMAP;
3357 /* dm.dmCollate */
3358 /* dm.dmFormName */
3359 /* dm.dmLogPixels */
3360 /* dm.dmBitsPerPel */
3361 /* dm.dmPelsWidth */
3362 /* dm.dmPelsHeight */
3363 /* dm.u2.dmDisplayFlags */
3364 /* dm.dmDisplayFrequency */
3365 /* dm.dmICMMethod */
3366 /* dm.dmICMIntent */
3367 /* dm.dmMediaType */
3368 /* dm.dmDitherType */
3369 /* dm.dmReserved1 */
3370 /* dm.dmReserved2 */
3371 /* dm.dmPanningWidth */
3372 /* dm.dmPanningHeight */
3374 if(unicode) {
3375 if(buflen >= sizeof(DEVMODEW)) {
3376 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3377 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3378 HeapFree(GetProcessHeap(),0,pdmW);
3380 *needed = sizeof(DEVMODEW);
3382 else
3384 if(buflen >= sizeof(DEVMODEA)) {
3385 memcpy(ptr, &dm, sizeof(DEVMODEA));
3387 *needed = sizeof(DEVMODEA);
3391 /*****************************************************************************
3392 * WINSPOOL_GetDevModeFromReg
3394 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3395 * DevMode is stored either as unicode or ascii.
3397 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3398 LPBYTE ptr,
3399 DWORD buflen, DWORD *needed,
3400 BOOL unicode)
3402 DWORD sz = buflen, type;
3403 LONG ret;
3405 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3406 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3407 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3408 if (sz < sizeof(DEVMODEA))
3410 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3411 return FALSE;
3413 /* ensures that dmSize is not erratically bogus if registry is invalid */
3414 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3415 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3416 if(unicode) {
3417 sz += (CCHDEVICENAME + CCHFORMNAME);
3418 if(buflen >= sz) {
3419 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3420 memcpy(ptr, dmW, sz);
3421 HeapFree(GetProcessHeap(),0,dmW);
3424 *needed = sz;
3425 return TRUE;
3428 /*********************************************************************
3429 * WINSPOOL_GetPrinter_1
3431 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3432 * The strings are either stored as unicode or ascii.
3434 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3435 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3436 BOOL unicode)
3438 DWORD size, left = cbBuf;
3439 BOOL space = (cbBuf > 0);
3440 LPBYTE ptr = buf;
3442 *pcbNeeded = 0;
3444 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3445 unicode)) {
3446 if(space && size <= left) {
3447 pi1->pName = (LPWSTR)ptr;
3448 ptr += size;
3449 left -= size;
3450 } else
3451 space = FALSE;
3452 *pcbNeeded += size;
3455 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3456 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3457 unicode)) {
3458 if(space && size <= left) {
3459 pi1->pDescription = (LPWSTR)ptr;
3460 ptr += size;
3461 left -= size;
3462 } else
3463 space = FALSE;
3464 *pcbNeeded += size;
3467 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3468 unicode)) {
3469 if(space && size <= left) {
3470 pi1->pComment = (LPWSTR)ptr;
3471 ptr += size;
3472 left -= size;
3473 } else
3474 space = FALSE;
3475 *pcbNeeded += size;
3478 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3480 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3481 memset(pi1, 0, sizeof(*pi1));
3483 return space;
3485 /*********************************************************************
3486 * WINSPOOL_GetPrinter_2
3488 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3489 * The strings are either stored as unicode or ascii.
3491 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3492 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3493 BOOL unicode)
3495 DWORD size, left = cbBuf;
3496 BOOL space = (cbBuf > 0);
3497 LPBYTE ptr = buf;
3499 *pcbNeeded = 0;
3501 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3502 unicode)) {
3503 if(space && size <= left) {
3504 pi2->pPrinterName = (LPWSTR)ptr;
3505 ptr += size;
3506 left -= size;
3507 } else
3508 space = FALSE;
3509 *pcbNeeded += size;
3511 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3512 unicode)) {
3513 if(space && size <= left) {
3514 pi2->pShareName = (LPWSTR)ptr;
3515 ptr += size;
3516 left -= size;
3517 } else
3518 space = FALSE;
3519 *pcbNeeded += size;
3521 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3522 unicode)) {
3523 if(space && size <= left) {
3524 pi2->pPortName = (LPWSTR)ptr;
3525 ptr += size;
3526 left -= size;
3527 } else
3528 space = FALSE;
3529 *pcbNeeded += size;
3531 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3532 &size, unicode)) {
3533 if(space && size <= left) {
3534 pi2->pDriverName = (LPWSTR)ptr;
3535 ptr += size;
3536 left -= size;
3537 } else
3538 space = FALSE;
3539 *pcbNeeded += size;
3541 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3542 unicode)) {
3543 if(space && size <= left) {
3544 pi2->pComment = (LPWSTR)ptr;
3545 ptr += size;
3546 left -= size;
3547 } else
3548 space = FALSE;
3549 *pcbNeeded += size;
3551 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3552 unicode)) {
3553 if(space && size <= left) {
3554 pi2->pLocation = (LPWSTR)ptr;
3555 ptr += size;
3556 left -= size;
3557 } else
3558 space = FALSE;
3559 *pcbNeeded += size;
3561 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3562 &size, unicode)) {
3563 if(space && size <= left) {
3564 pi2->pDevMode = (LPDEVMODEW)ptr;
3565 ptr += size;
3566 left -= size;
3567 } else
3568 space = FALSE;
3569 *pcbNeeded += size;
3571 else
3573 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3574 if(space && size <= left) {
3575 pi2->pDevMode = (LPDEVMODEW)ptr;
3576 ptr += size;
3577 left -= size;
3578 } else
3579 space = FALSE;
3580 *pcbNeeded += size;
3582 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3583 &size, unicode)) {
3584 if(space && size <= left) {
3585 pi2->pSepFile = (LPWSTR)ptr;
3586 ptr += size;
3587 left -= size;
3588 } else
3589 space = FALSE;
3590 *pcbNeeded += size;
3592 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3593 &size, unicode)) {
3594 if(space && size <= left) {
3595 pi2->pPrintProcessor = (LPWSTR)ptr;
3596 ptr += size;
3597 left -= size;
3598 } else
3599 space = FALSE;
3600 *pcbNeeded += size;
3602 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3603 &size, unicode)) {
3604 if(space && size <= left) {
3605 pi2->pDatatype = (LPWSTR)ptr;
3606 ptr += size;
3607 left -= size;
3608 } else
3609 space = FALSE;
3610 *pcbNeeded += size;
3612 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3613 &size, unicode)) {
3614 if(space && size <= left) {
3615 pi2->pParameters = (LPWSTR)ptr;
3616 ptr += size;
3617 left -= size;
3618 } else
3619 space = FALSE;
3620 *pcbNeeded += size;
3622 if(pi2) {
3623 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3624 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3625 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3626 "Default Priority");
3627 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3628 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3631 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3632 memset(pi2, 0, sizeof(*pi2));
3634 return space;
3637 /*********************************************************************
3638 * WINSPOOL_GetPrinter_4
3640 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3642 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3643 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3644 BOOL unicode)
3646 DWORD size, left = cbBuf;
3647 BOOL space = (cbBuf > 0);
3648 LPBYTE ptr = buf;
3650 *pcbNeeded = 0;
3652 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3653 unicode)) {
3654 if(space && size <= left) {
3655 pi4->pPrinterName = (LPWSTR)ptr;
3656 ptr += size;
3657 left -= size;
3658 } else
3659 space = FALSE;
3660 *pcbNeeded += size;
3662 if(pi4) {
3663 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3666 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3667 memset(pi4, 0, sizeof(*pi4));
3669 return space;
3672 /*********************************************************************
3673 * WINSPOOL_GetPrinter_5
3675 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3677 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3678 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3679 BOOL unicode)
3681 DWORD size, left = cbBuf;
3682 BOOL space = (cbBuf > 0);
3683 LPBYTE ptr = buf;
3685 *pcbNeeded = 0;
3687 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3688 unicode)) {
3689 if(space && size <= left) {
3690 pi5->pPrinterName = (LPWSTR)ptr;
3691 ptr += size;
3692 left -= size;
3693 } else
3694 space = FALSE;
3695 *pcbNeeded += size;
3697 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3698 unicode)) {
3699 if(space && size <= left) {
3700 pi5->pPortName = (LPWSTR)ptr;
3701 ptr += size;
3702 left -= size;
3703 } else
3704 space = FALSE;
3705 *pcbNeeded += size;
3707 if(pi5) {
3708 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3709 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3710 "dnsTimeout");
3711 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3712 "txTimeout");
3715 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3716 memset(pi5, 0, sizeof(*pi5));
3718 return space;
3721 /*********************************************************************
3722 * WINSPOOL_GetPrinter_7
3724 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3726 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3727 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3729 DWORD size, left = cbBuf;
3730 BOOL space = (cbBuf > 0);
3731 LPBYTE ptr = buf;
3733 *pcbNeeded = 0;
3735 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3737 if (space && size <= left) {
3738 pi7->pszObjectGUID = (LPWSTR)ptr;
3739 ptr += size;
3740 left -= size;
3741 } else
3742 space = FALSE;
3743 *pcbNeeded += size;
3745 if (pi7) {
3746 /* We do not have a Directory Service */
3747 pi7->dwAction = DSPRINT_UNPUBLISH;
3750 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3751 memset(pi7, 0, sizeof(*pi7));
3753 return space;
3756 /*********************************************************************
3757 * WINSPOOL_GetPrinter_9
3759 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3760 * The strings are either stored as unicode or ascii.
3762 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3763 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3765 DWORD size;
3766 BOOL space = (cbBuf > 0);
3768 *pcbNeeded = 0;
3770 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3771 if(space && size <= cbBuf) {
3772 pi9->pDevMode = (LPDEVMODEW)buf;
3773 } else
3774 space = FALSE;
3775 *pcbNeeded += size;
3777 else
3779 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3780 if(space && size <= cbBuf) {
3781 pi9->pDevMode = (LPDEVMODEW)buf;
3782 } else
3783 space = FALSE;
3784 *pcbNeeded += size;
3787 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3788 memset(pi9, 0, sizeof(*pi9));
3790 return space;
3793 /*****************************************************************************
3794 * WINSPOOL_GetPrinter
3796 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3797 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3798 * just a collection of pointers to strings.
3800 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3801 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3803 LPCWSTR name;
3804 DWORD size, needed = 0;
3805 LPBYTE ptr = NULL;
3806 HKEY hkeyPrinter, hkeyPrinters;
3807 BOOL ret;
3809 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3811 if (!(name = get_opened_printer_name(hPrinter))) {
3812 SetLastError(ERROR_INVALID_HANDLE);
3813 return FALSE;
3816 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3817 ERROR_SUCCESS) {
3818 ERR("Can't create Printers key\n");
3819 return FALSE;
3821 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3823 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3824 RegCloseKey(hkeyPrinters);
3825 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3826 return FALSE;
3829 switch(Level) {
3830 case 2:
3832 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3834 size = sizeof(PRINTER_INFO_2W);
3835 if(size <= cbBuf) {
3836 ptr = pPrinter + size;
3837 cbBuf -= size;
3838 memset(pPrinter, 0, size);
3839 } else {
3840 pi2 = NULL;
3841 cbBuf = 0;
3843 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3844 unicode);
3845 needed += size;
3846 break;
3849 case 4:
3851 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3853 size = sizeof(PRINTER_INFO_4W);
3854 if(size <= cbBuf) {
3855 ptr = pPrinter + size;
3856 cbBuf -= size;
3857 memset(pPrinter, 0, size);
3858 } else {
3859 pi4 = NULL;
3860 cbBuf = 0;
3862 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3863 unicode);
3864 needed += size;
3865 break;
3869 case 5:
3871 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3873 size = sizeof(PRINTER_INFO_5W);
3874 if(size <= cbBuf) {
3875 ptr = pPrinter + size;
3876 cbBuf -= size;
3877 memset(pPrinter, 0, size);
3878 } else {
3879 pi5 = NULL;
3880 cbBuf = 0;
3883 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3884 unicode);
3885 needed += size;
3886 break;
3890 case 6:
3892 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3894 size = sizeof(PRINTER_INFO_6);
3895 if (size <= cbBuf) {
3896 /* FIXME: We do not update the status yet */
3897 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3898 ret = TRUE;
3899 } else {
3900 ret = FALSE;
3903 needed += size;
3904 break;
3907 case 7:
3909 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3911 size = sizeof(PRINTER_INFO_7W);
3912 if (size <= cbBuf) {
3913 ptr = pPrinter + size;
3914 cbBuf -= size;
3915 memset(pPrinter, 0, size);
3916 } else {
3917 pi7 = NULL;
3918 cbBuf = 0;
3921 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
3922 needed += size;
3923 break;
3927 case 9:
3929 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3931 size = sizeof(PRINTER_INFO_9W);
3932 if(size <= cbBuf) {
3933 ptr = pPrinter + size;
3934 cbBuf -= size;
3935 memset(pPrinter, 0, size);
3936 } else {
3937 pi9 = NULL;
3938 cbBuf = 0;
3941 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
3942 needed += size;
3943 break;
3947 default:
3948 FIXME("Unimplemented level %d\n", Level);
3949 SetLastError(ERROR_INVALID_LEVEL);
3950 RegCloseKey(hkeyPrinters);
3951 RegCloseKey(hkeyPrinter);
3952 return FALSE;
3955 RegCloseKey(hkeyPrinter);
3956 RegCloseKey(hkeyPrinters);
3958 TRACE("returning %d needed = %d\n", ret, needed);
3959 if(pcbNeeded) *pcbNeeded = needed;
3960 if(!ret)
3961 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3962 return ret;
3965 /*****************************************************************************
3966 * GetPrinterW [WINSPOOL.@]
3968 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3969 DWORD cbBuf, LPDWORD pcbNeeded)
3971 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3972 TRUE);
3975 /*****************************************************************************
3976 * GetPrinterA [WINSPOOL.@]
3978 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3979 DWORD cbBuf, LPDWORD pcbNeeded)
3981 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3982 FALSE);
3985 /*****************************************************************************
3986 * WINSPOOL_EnumPrinters
3988 * Implementation of EnumPrintersA|W
3990 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3991 DWORD dwLevel, LPBYTE lpbPrinters,
3992 DWORD cbBuf, LPDWORD lpdwNeeded,
3993 LPDWORD lpdwReturned, BOOL unicode)
3996 HKEY hkeyPrinters, hkeyPrinter;
3997 WCHAR PrinterName[255];
3998 DWORD needed = 0, number = 0;
3999 DWORD used, i, left;
4000 PBYTE pi, buf;
4002 if(lpbPrinters)
4003 memset(lpbPrinters, 0, cbBuf);
4004 if(lpdwReturned)
4005 *lpdwReturned = 0;
4006 if(lpdwNeeded)
4007 *lpdwNeeded = 0;
4009 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4010 if(dwType == PRINTER_ENUM_DEFAULT)
4011 return TRUE;
4013 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4014 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4015 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4016 if (!dwType) {
4017 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4018 *lpdwNeeded = 0;
4019 *lpdwReturned = 0;
4020 return TRUE;
4025 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4026 FIXME("dwType = %08x\n", dwType);
4027 SetLastError(ERROR_INVALID_FLAGS);
4028 return FALSE;
4031 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4032 ERROR_SUCCESS) {
4033 ERR("Can't create Printers key\n");
4034 return FALSE;
4037 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4038 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4039 RegCloseKey(hkeyPrinters);
4040 ERR("Can't query Printers key\n");
4041 return FALSE;
4043 TRACE("Found %d printers\n", number);
4045 switch(dwLevel) {
4046 case 1:
4047 used = number * sizeof(PRINTER_INFO_1W);
4048 break;
4049 case 2:
4050 used = number * sizeof(PRINTER_INFO_2W);
4051 break;
4052 case 4:
4053 used = number * sizeof(PRINTER_INFO_4W);
4054 break;
4055 case 5:
4056 used = number * sizeof(PRINTER_INFO_5W);
4057 break;
4059 default:
4060 SetLastError(ERROR_INVALID_LEVEL);
4061 RegCloseKey(hkeyPrinters);
4062 return FALSE;
4064 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4066 for(i = 0; i < number; i++) {
4067 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4068 ERROR_SUCCESS) {
4069 ERR("Can't enum key number %d\n", i);
4070 RegCloseKey(hkeyPrinters);
4071 return FALSE;
4073 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4074 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4075 ERROR_SUCCESS) {
4076 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4077 RegCloseKey(hkeyPrinters);
4078 return FALSE;
4081 if(cbBuf > used) {
4082 buf = lpbPrinters + used;
4083 left = cbBuf - used;
4084 } else {
4085 buf = NULL;
4086 left = 0;
4089 switch(dwLevel) {
4090 case 1:
4091 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4092 left, &needed, unicode);
4093 used += needed;
4094 if(pi) pi += sizeof(PRINTER_INFO_1W);
4095 break;
4096 case 2:
4097 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4098 left, &needed, unicode);
4099 used += needed;
4100 if(pi) pi += sizeof(PRINTER_INFO_2W);
4101 break;
4102 case 4:
4103 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4104 left, &needed, unicode);
4105 used += needed;
4106 if(pi) pi += sizeof(PRINTER_INFO_4W);
4107 break;
4108 case 5:
4109 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4110 left, &needed, unicode);
4111 used += needed;
4112 if(pi) pi += sizeof(PRINTER_INFO_5W);
4113 break;
4114 default:
4115 ERR("Shouldn't be here!\n");
4116 RegCloseKey(hkeyPrinter);
4117 RegCloseKey(hkeyPrinters);
4118 return FALSE;
4120 RegCloseKey(hkeyPrinter);
4122 RegCloseKey(hkeyPrinters);
4124 if(lpdwNeeded)
4125 *lpdwNeeded = used;
4127 if(used > cbBuf) {
4128 if(lpbPrinters)
4129 memset(lpbPrinters, 0, cbBuf);
4130 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4131 return FALSE;
4133 if(lpdwReturned)
4134 *lpdwReturned = number;
4135 SetLastError(ERROR_SUCCESS);
4136 return TRUE;
4140 /******************************************************************
4141 * EnumPrintersW [WINSPOOL.@]
4143 * Enumerates the available printers, print servers and print
4144 * providers, depending on the specified flags, name and level.
4146 * RETURNS:
4148 * If level is set to 1:
4149 * Returns an array of PRINTER_INFO_1 data structures in the
4150 * lpbPrinters buffer.
4152 * If level is set to 2:
4153 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4154 * Returns an array of PRINTER_INFO_2 data structures in the
4155 * lpbPrinters buffer. Note that according to MSDN also an
4156 * OpenPrinter should be performed on every remote printer.
4158 * If level is set to 4 (officially WinNT only):
4159 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4160 * Fast: Only the registry is queried to retrieve printer names,
4161 * no connection to the driver is made.
4162 * Returns an array of PRINTER_INFO_4 data structures in the
4163 * lpbPrinters buffer.
4165 * If level is set to 5 (officially WinNT4/Win9x only):
4166 * Fast: Only the registry is queried to retrieve printer names,
4167 * no connection to the driver is made.
4168 * Returns an array of PRINTER_INFO_5 data structures in the
4169 * lpbPrinters buffer.
4171 * If level set to 3 or 6+:
4172 * returns zero (failure!)
4174 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4175 * for information.
4177 * BUGS:
4178 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4179 * - Only levels 2, 4 and 5 are implemented at the moment.
4180 * - 16-bit printer drivers are not enumerated.
4181 * - Returned amount of bytes used/needed does not match the real Windoze
4182 * implementation (as in this implementation, all strings are part
4183 * of the buffer, whereas Win32 keeps them somewhere else)
4184 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4186 * NOTE:
4187 * - In a regular Wine installation, no registry settings for printers
4188 * exist, which makes this function return an empty list.
4190 BOOL WINAPI EnumPrintersW(
4191 DWORD dwType, /* [in] Types of print objects to enumerate */
4192 LPWSTR lpszName, /* [in] name of objects to enumerate */
4193 DWORD dwLevel, /* [in] type of printer info structure */
4194 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4195 DWORD cbBuf, /* [in] max size of buffer in bytes */
4196 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4197 LPDWORD lpdwReturned /* [out] number of entries returned */
4200 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4201 lpdwNeeded, lpdwReturned, TRUE);
4204 /******************************************************************
4205 * EnumPrintersA [WINSPOOL.@]
4207 * See EnumPrintersW
4210 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4211 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4213 BOOL ret;
4214 UNICODE_STRING pNameU;
4215 LPWSTR pNameW;
4216 LPBYTE pPrintersW;
4218 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4219 pPrinters, cbBuf, pcbNeeded, pcReturned);
4221 pNameW = asciitounicode(&pNameU, pName);
4223 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4224 MS Office need this */
4225 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4227 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4229 RtlFreeUnicodeString(&pNameU);
4230 if (ret) {
4231 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4233 HeapFree(GetProcessHeap(), 0, pPrintersW);
4234 return ret;
4237 /*****************************************************************************
4238 * WINSPOOL_GetDriverInfoFromReg [internal]
4240 * Enters the information from the registry into the DRIVER_INFO struct
4242 * RETURNS
4243 * zero if the printer driver does not exist in the registry
4244 * (only if Level > 1) otherwise nonzero
4246 static BOOL WINSPOOL_GetDriverInfoFromReg(
4247 HKEY hkeyDrivers,
4248 LPWSTR DriverName,
4249 const printenv_t * env,
4250 DWORD Level,
4251 LPBYTE ptr, /* DRIVER_INFO */
4252 LPBYTE pDriverStrings, /* strings buffer */
4253 DWORD cbBuf, /* size of string buffer */
4254 LPDWORD pcbNeeded, /* space needed for str. */
4255 BOOL unicode) /* type of strings */
4257 DWORD size, tmp;
4258 HKEY hkeyDriver;
4259 WCHAR driverdir[MAX_PATH];
4260 DWORD dirlen;
4261 LPBYTE strPtr = pDriverStrings;
4262 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4264 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4265 debugstr_w(DriverName), env,
4266 Level, di, pDriverStrings, cbBuf, unicode);
4268 if (di) ZeroMemory(di, di_sizeof[Level]);
4270 if (unicode) {
4271 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4272 if (*pcbNeeded <= cbBuf)
4273 strcpyW((LPWSTR)strPtr, DriverName);
4275 else
4277 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4278 if (*pcbNeeded <= cbBuf)
4279 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4282 /* pName for level 1 has a different offset! */
4283 if (Level == 1) {
4284 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4285 return TRUE;
4288 /* .cVersion and .pName for level > 1 */
4289 if (di) {
4290 di->cVersion = env->driverversion;
4291 di->pName = (LPWSTR) strPtr;
4292 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4295 /* Reserve Space for the largest subdir and a Backslash*/
4296 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4297 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4298 /* Should never Fail */
4299 return FALSE;
4301 lstrcatW(driverdir, env->versionsubdir);
4302 lstrcatW(driverdir, backslashW);
4304 /* dirlen must not include the terminating zero */
4305 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4306 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4308 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4309 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4310 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4311 return FALSE;
4314 /* pEnvironment */
4315 if (unicode)
4316 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4317 else
4318 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4320 *pcbNeeded += size;
4321 if (*pcbNeeded <= cbBuf) {
4322 if (unicode) {
4323 lstrcpyW((LPWSTR)strPtr, env->envname);
4325 else
4327 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4329 if (di) di->pEnvironment = (LPWSTR)strPtr;
4330 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4333 /* .pDriverPath is the Graphics rendering engine.
4334 The full Path is required to avoid a crash in some apps */
4335 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4336 *pcbNeeded += size;
4337 if (*pcbNeeded <= cbBuf)
4338 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4340 if (di) di->pDriverPath = (LPWSTR)strPtr;
4341 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4344 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4345 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4346 *pcbNeeded += size;
4347 if (*pcbNeeded <= cbBuf)
4348 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4350 if (di) di->pDataFile = (LPWSTR)strPtr;
4351 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4354 /* .pConfigFile is the Driver user Interface */
4355 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4356 *pcbNeeded += size;
4357 if (*pcbNeeded <= cbBuf)
4358 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4360 if (di) di->pConfigFile = (LPWSTR)strPtr;
4361 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4364 if (Level == 2 ) {
4365 RegCloseKey(hkeyDriver);
4366 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4367 return TRUE;
4370 if (Level == 5 ) {
4371 RegCloseKey(hkeyDriver);
4372 FIXME("level 5: incomplete\n");
4373 return TRUE;
4376 /* .pHelpFile */
4377 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4378 *pcbNeeded += size;
4379 if (*pcbNeeded <= cbBuf)
4380 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4382 if (di) di->pHelpFile = (LPWSTR)strPtr;
4383 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4386 /* .pDependentFiles */
4387 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4388 *pcbNeeded += size;
4389 if (*pcbNeeded <= cbBuf)
4390 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4392 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4393 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4395 else if (GetVersion() & 0x80000000) {
4396 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4397 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4398 *pcbNeeded += size;
4399 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4401 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4402 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4405 /* .pMonitorName is the optional Language Monitor */
4406 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4407 *pcbNeeded += size;
4408 if (*pcbNeeded <= cbBuf)
4409 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4411 if (di) di->pMonitorName = (LPWSTR)strPtr;
4412 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4415 /* .pDefaultDataType */
4416 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4417 *pcbNeeded += size;
4418 if(*pcbNeeded <= cbBuf)
4419 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4421 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4422 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4425 if (Level == 3 ) {
4426 RegCloseKey(hkeyDriver);
4427 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4428 return TRUE;
4431 /* .pszzPreviousNames */
4432 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4433 *pcbNeeded += size;
4434 if(*pcbNeeded <= cbBuf)
4435 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4437 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4438 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4441 if (Level == 4 ) {
4442 RegCloseKey(hkeyDriver);
4443 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4444 return TRUE;
4447 /* support is missing, but not important enough for a FIXME */
4448 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4450 /* .pszMfgName */
4451 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4452 *pcbNeeded += size;
4453 if(*pcbNeeded <= cbBuf)
4454 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4456 if (di) di->pszMfgName = (LPWSTR)strPtr;
4457 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4460 /* .pszOEMUrl */
4461 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4462 *pcbNeeded += size;
4463 if(*pcbNeeded <= cbBuf)
4464 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4466 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4467 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4470 /* .pszHardwareID */
4471 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4472 *pcbNeeded += size;
4473 if(*pcbNeeded <= cbBuf)
4474 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4476 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4477 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4480 /* .pszProvider */
4481 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4482 *pcbNeeded += size;
4483 if(*pcbNeeded <= cbBuf)
4484 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4486 if (di) di->pszProvider = (LPWSTR)strPtr;
4487 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4490 if (Level == 6 ) {
4491 RegCloseKey(hkeyDriver);
4492 return TRUE;
4495 /* support is missing, but not important enough for a FIXME */
4496 TRACE("level 8: incomplete\n");
4498 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4499 RegCloseKey(hkeyDriver);
4500 return TRUE;
4503 /*****************************************************************************
4504 * WINSPOOL_GetPrinterDriver
4506 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4507 DWORD Level, LPBYTE pDriverInfo,
4508 DWORD cbBuf, LPDWORD pcbNeeded,
4509 BOOL unicode)
4511 LPCWSTR name;
4512 WCHAR DriverName[100];
4513 DWORD ret, type, size, needed = 0;
4514 LPBYTE ptr = NULL;
4515 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4516 const printenv_t * env;
4518 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4519 Level,pDriverInfo,cbBuf, pcbNeeded);
4522 if (!(name = get_opened_printer_name(hPrinter))) {
4523 SetLastError(ERROR_INVALID_HANDLE);
4524 return FALSE;
4527 if (Level < 1 || Level == 7 || Level > 8) {
4528 SetLastError(ERROR_INVALID_LEVEL);
4529 return FALSE;
4532 env = validate_envW(pEnvironment);
4533 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4535 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4536 ERROR_SUCCESS) {
4537 ERR("Can't create Printers key\n");
4538 return FALSE;
4540 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4541 != ERROR_SUCCESS) {
4542 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4543 RegCloseKey(hkeyPrinters);
4544 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4545 return FALSE;
4547 size = sizeof(DriverName);
4548 DriverName[0] = 0;
4549 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4550 (LPBYTE)DriverName, &size);
4551 RegCloseKey(hkeyPrinter);
4552 RegCloseKey(hkeyPrinters);
4553 if(ret != ERROR_SUCCESS) {
4554 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4555 return FALSE;
4558 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4559 if(!hkeyDrivers) {
4560 ERR("Can't create Drivers key\n");
4561 return FALSE;
4564 size = di_sizeof[Level];
4565 if ((size <= cbBuf) && pDriverInfo)
4566 ptr = pDriverInfo + size;
4568 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4569 env, Level, pDriverInfo, ptr,
4570 (cbBuf < size) ? 0 : cbBuf - size,
4571 &needed, unicode)) {
4572 RegCloseKey(hkeyDrivers);
4573 return FALSE;
4576 RegCloseKey(hkeyDrivers);
4578 if(pcbNeeded) *pcbNeeded = size + needed;
4579 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4580 if(cbBuf >= needed) return TRUE;
4581 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4582 return FALSE;
4585 /*****************************************************************************
4586 * GetPrinterDriverA [WINSPOOL.@]
4588 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4589 DWORD Level, LPBYTE pDriverInfo,
4590 DWORD cbBuf, LPDWORD pcbNeeded)
4592 BOOL ret;
4593 UNICODE_STRING pEnvW;
4594 PWSTR pwstrEnvW;
4596 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4597 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4598 cbBuf, pcbNeeded, FALSE);
4599 RtlFreeUnicodeString(&pEnvW);
4600 return ret;
4602 /*****************************************************************************
4603 * GetPrinterDriverW [WINSPOOL.@]
4605 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4606 DWORD Level, LPBYTE pDriverInfo,
4607 DWORD cbBuf, LPDWORD pcbNeeded)
4609 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4610 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4613 /*****************************************************************************
4614 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4616 * Return the PATH for the Printer-Drivers (UNICODE)
4618 * PARAMS
4619 * pName [I] Servername (NT only) or NULL (local Computer)
4620 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4621 * Level [I] Structure-Level (must be 1)
4622 * pDriverDirectory [O] PTR to Buffer that receives the Result
4623 * cbBuf [I] Size of Buffer at pDriverDirectory
4624 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4625 * required for pDriverDirectory
4627 * RETURNS
4628 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4629 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4630 * if cbBuf is too small
4632 * Native Values returned in pDriverDirectory on Success:
4633 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4634 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4635 *| win9x(Windows 4.0): "%winsysdir%"
4637 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4639 * FIXME
4640 *- Only NULL or "" is supported for pName
4643 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4644 DWORD Level, LPBYTE pDriverDirectory,
4645 DWORD cbBuf, LPDWORD pcbNeeded)
4647 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4648 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4650 if ((backend == NULL) && !load_backend()) return FALSE;
4652 if (Level != 1) {
4653 /* (Level != 1) is ignored in win9x */
4654 SetLastError(ERROR_INVALID_LEVEL);
4655 return FALSE;
4657 if (pcbNeeded == NULL) {
4658 /* (pcbNeeded == NULL) is ignored in win9x */
4659 SetLastError(RPC_X_NULL_REF_POINTER);
4660 return FALSE;
4663 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4664 pDriverDirectory, cbBuf, pcbNeeded);
4669 /*****************************************************************************
4670 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4672 * Return the PATH for the Printer-Drivers (ANSI)
4674 * See GetPrinterDriverDirectoryW.
4676 * NOTES
4677 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4680 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4681 DWORD Level, LPBYTE pDriverDirectory,
4682 DWORD cbBuf, LPDWORD pcbNeeded)
4684 UNICODE_STRING nameW, environmentW;
4685 BOOL ret;
4686 DWORD pcbNeededW;
4687 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4688 WCHAR *driverDirectoryW = NULL;
4690 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4691 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4693 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4695 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4696 else nameW.Buffer = NULL;
4697 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4698 else environmentW.Buffer = NULL;
4700 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4701 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4702 if (ret) {
4703 DWORD needed;
4704 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4705 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4706 if(pcbNeeded)
4707 *pcbNeeded = needed;
4708 ret = (needed <= cbBuf) ? TRUE : FALSE;
4709 } else
4710 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4712 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4714 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4715 RtlFreeUnicodeString(&environmentW);
4716 RtlFreeUnicodeString(&nameW);
4718 return ret;
4721 /*****************************************************************************
4722 * AddPrinterDriverA [WINSPOOL.@]
4724 * See AddPrinterDriverW.
4727 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4729 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4730 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4733 /******************************************************************************
4734 * AddPrinterDriverW (WINSPOOL.@)
4736 * Install a Printer Driver
4738 * PARAMS
4739 * pName [I] Servername or NULL (local Computer)
4740 * level [I] Level for the supplied DRIVER_INFO_*W struct
4741 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4743 * RESULTS
4744 * Success: TRUE
4745 * Failure: FALSE
4748 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4750 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4751 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4754 /*****************************************************************************
4755 * AddPrintProcessorA [WINSPOOL.@]
4757 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4758 LPSTR pPrintProcessorName)
4760 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4761 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4762 return FALSE;
4765 /*****************************************************************************
4766 * AddPrintProcessorW [WINSPOOL.@]
4768 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4769 LPWSTR pPrintProcessorName)
4771 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4772 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4773 return FALSE;
4776 /*****************************************************************************
4777 * AddPrintProvidorA [WINSPOOL.@]
4779 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4781 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4782 return FALSE;
4785 /*****************************************************************************
4786 * AddPrintProvidorW [WINSPOOL.@]
4788 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4790 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4791 return FALSE;
4794 /*****************************************************************************
4795 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4797 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4798 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4800 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4801 pDevModeOutput, pDevModeInput);
4802 return 0;
4805 /*****************************************************************************
4806 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4808 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4809 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4811 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4812 pDevModeOutput, pDevModeInput);
4813 return 0;
4816 /*****************************************************************************
4817 * PrinterProperties [WINSPOOL.@]
4819 * Displays a dialog to set the properties of the printer.
4821 * RETURNS
4822 * nonzero on success or zero on failure
4824 * BUGS
4825 * implemented as stub only
4827 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4828 HANDLE hPrinter /* [in] handle to printer object */
4830 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4831 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4832 return FALSE;
4835 /*****************************************************************************
4836 * EnumJobsA [WINSPOOL.@]
4839 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4840 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4841 LPDWORD pcReturned)
4843 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4844 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4846 if(pcbNeeded) *pcbNeeded = 0;
4847 if(pcReturned) *pcReturned = 0;
4848 return FALSE;
4852 /*****************************************************************************
4853 * EnumJobsW [WINSPOOL.@]
4856 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4857 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4858 LPDWORD pcReturned)
4860 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4861 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4863 if(pcbNeeded) *pcbNeeded = 0;
4864 if(pcReturned) *pcReturned = 0;
4865 return FALSE;
4868 /*****************************************************************************
4869 * WINSPOOL_EnumPrinterDrivers [internal]
4871 * Delivers information about all printer drivers installed on the
4872 * localhost or a given server
4874 * RETURNS
4875 * nonzero on success or zero on failure. If the buffer for the returned
4876 * information is too small the function will return an error
4878 * BUGS
4879 * - only implemented for localhost, foreign hosts will return an error
4881 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4882 DWORD Level, LPBYTE pDriverInfo,
4883 DWORD cbBuf, LPDWORD pcbNeeded,
4884 LPDWORD pcReturned, BOOL unicode)
4886 { HKEY hkeyDrivers;
4887 DWORD i, needed, number = 0, size = 0;
4888 WCHAR DriverNameW[255];
4889 PBYTE ptr;
4890 const printenv_t * env;
4892 TRACE("%s,%s,%d,%p,%d,%d\n",
4893 debugstr_w(pName), debugstr_w(pEnvironment),
4894 Level, pDriverInfo, cbBuf, unicode);
4896 /* check for local drivers */
4897 if((pName) && (pName[0])) {
4898 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4899 SetLastError(ERROR_ACCESS_DENIED);
4900 return FALSE;
4903 env = validate_envW(pEnvironment);
4904 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4906 /* check input parameter */
4907 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4908 SetLastError(ERROR_INVALID_LEVEL);
4909 return FALSE;
4912 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
4913 SetLastError(RPC_X_NULL_REF_POINTER);
4914 return FALSE;
4917 /* initialize return values */
4918 if(pDriverInfo)
4919 memset( pDriverInfo, 0, cbBuf);
4920 *pcbNeeded = 0;
4921 *pcReturned = 0;
4923 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4924 if(!hkeyDrivers) {
4925 ERR("Can't open Drivers key\n");
4926 return FALSE;
4929 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4930 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4931 RegCloseKey(hkeyDrivers);
4932 ERR("Can't query Drivers key\n");
4933 return FALSE;
4935 TRACE("Found %d Drivers\n", number);
4937 /* get size of single struct
4938 * unicode and ascii structure have the same size
4940 size = di_sizeof[Level];
4942 /* calculate required buffer size */
4943 *pcbNeeded = size * number;
4945 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4946 i < number;
4947 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4948 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4949 != ERROR_SUCCESS) {
4950 ERR("Can't enum key number %d\n", i);
4951 RegCloseKey(hkeyDrivers);
4952 return FALSE;
4954 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4955 env, Level, ptr,
4956 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4957 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4958 &needed, unicode)) {
4959 RegCloseKey(hkeyDrivers);
4960 return FALSE;
4962 *pcbNeeded += needed;
4965 RegCloseKey(hkeyDrivers);
4967 if(cbBuf < *pcbNeeded){
4968 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4969 return FALSE;
4972 *pcReturned = number;
4973 return TRUE;
4976 /*****************************************************************************
4977 * EnumPrinterDriversW [WINSPOOL.@]
4979 * see function EnumPrinterDrivers for RETURNS, BUGS
4981 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4982 LPBYTE pDriverInfo, DWORD cbBuf,
4983 LPDWORD pcbNeeded, LPDWORD pcReturned)
4985 static const WCHAR allW[] = {'a','l','l',0};
4987 if (pEnvironment && !strcmpW(pEnvironment, allW))
4989 BOOL ret;
4990 DWORD i, needed, returned, bufsize = cbBuf;
4992 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4994 needed = returned = 0;
4995 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4996 pDriverInfo, bufsize, &needed, &returned, TRUE);
4997 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4998 else if (ret)
5000 bufsize -= needed;
5001 if (pDriverInfo) pDriverInfo += needed;
5002 if (pcReturned) *pcReturned += returned;
5004 if (pcbNeeded) *pcbNeeded += needed;
5006 return ret;
5008 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5009 cbBuf, pcbNeeded, pcReturned, TRUE);
5012 /*****************************************************************************
5013 * EnumPrinterDriversA [WINSPOOL.@]
5015 * see function EnumPrinterDrivers for RETURNS, BUGS
5017 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5018 LPBYTE pDriverInfo, DWORD cbBuf,
5019 LPDWORD pcbNeeded, LPDWORD pcReturned)
5021 BOOL ret;
5022 UNICODE_STRING pNameW, pEnvironmentW;
5023 PWSTR pwstrNameW, pwstrEnvironmentW;
5025 pwstrNameW = asciitounicode(&pNameW, pName);
5026 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5028 if (pEnvironment && !strcmp(pEnvironment, "all"))
5030 DWORD i, needed, returned, bufsize = cbBuf;
5032 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5034 needed = returned = 0;
5035 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
5036 pDriverInfo, bufsize, &needed, &returned, FALSE);
5037 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
5038 else if (ret)
5040 bufsize -= needed;
5041 if (pDriverInfo) pDriverInfo += needed;
5042 if (pcReturned) *pcReturned += returned;
5044 if (pcbNeeded) *pcbNeeded += needed;
5047 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5048 Level, pDriverInfo, cbBuf, pcbNeeded,
5049 pcReturned, FALSE);
5050 RtlFreeUnicodeString(&pNameW);
5051 RtlFreeUnicodeString(&pEnvironmentW);
5053 return ret;
5056 /******************************************************************************
5057 * EnumPortsA (WINSPOOL.@)
5059 * See EnumPortsW.
5062 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5063 LPDWORD pcbNeeded, LPDWORD pcReturned)
5065 BOOL res;
5066 LPBYTE bufferW = NULL;
5067 LPWSTR nameW = NULL;
5068 DWORD needed = 0;
5069 DWORD numentries = 0;
5070 INT len;
5072 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5073 cbBuf, pcbNeeded, pcReturned);
5075 /* convert servername to unicode */
5076 if (pName) {
5077 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5078 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5079 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5081 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5082 needed = cbBuf * sizeof(WCHAR);
5083 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5084 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5086 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5087 if (pcbNeeded) needed = *pcbNeeded;
5088 /* HeapReAlloc return NULL, when bufferW was NULL */
5089 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5090 HeapAlloc(GetProcessHeap(), 0, needed);
5092 /* Try again with the large Buffer */
5093 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5095 needed = pcbNeeded ? *pcbNeeded : 0;
5096 numentries = pcReturned ? *pcReturned : 0;
5099 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5100 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5102 if (res) {
5103 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5104 DWORD entrysize = 0;
5105 DWORD index;
5106 LPSTR ptr;
5107 LPPORT_INFO_2W pi2w;
5108 LPPORT_INFO_2A pi2a;
5110 needed = 0;
5111 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5113 /* First pass: calculate the size for all Entries */
5114 pi2w = (LPPORT_INFO_2W) bufferW;
5115 pi2a = (LPPORT_INFO_2A) pPorts;
5116 index = 0;
5117 while (index < numentries) {
5118 index++;
5119 needed += entrysize; /* PORT_INFO_?A */
5120 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5122 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5123 NULL, 0, NULL, NULL);
5124 if (Level > 1) {
5125 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5126 NULL, 0, NULL, NULL);
5127 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5128 NULL, 0, NULL, NULL);
5130 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5131 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5132 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5135 /* check for errors and quit on failure */
5136 if (cbBuf < needed) {
5137 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5138 res = FALSE;
5139 goto cleanup;
5141 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5142 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5143 cbBuf -= len ; /* free Bytes in the user-Buffer */
5144 pi2w = (LPPORT_INFO_2W) bufferW;
5145 pi2a = (LPPORT_INFO_2A) pPorts;
5146 index = 0;
5147 /* Second Pass: Fill the User Buffer (if we have one) */
5148 while ((index < numentries) && pPorts) {
5149 index++;
5150 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5151 pi2a->pPortName = ptr;
5152 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5153 ptr, cbBuf , NULL, NULL);
5154 ptr += len;
5155 cbBuf -= len;
5156 if (Level > 1) {
5157 pi2a->pMonitorName = ptr;
5158 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5159 ptr, cbBuf, NULL, NULL);
5160 ptr += len;
5161 cbBuf -= len;
5163 pi2a->pDescription = ptr;
5164 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5165 ptr, cbBuf, NULL, NULL);
5166 ptr += len;
5167 cbBuf -= len;
5169 pi2a->fPortType = pi2w->fPortType;
5170 pi2a->Reserved = 0; /* documented: "must be zero" */
5173 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5174 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5175 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5179 cleanup:
5180 if (pcbNeeded) *pcbNeeded = needed;
5181 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5183 HeapFree(GetProcessHeap(), 0, nameW);
5184 HeapFree(GetProcessHeap(), 0, bufferW);
5186 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5187 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5189 return (res);
5193 /******************************************************************************
5194 * EnumPortsW (WINSPOOL.@)
5196 * Enumerate available Ports
5198 * PARAMS
5199 * pName [I] Servername or NULL (local Computer)
5200 * Level [I] Structure-Level (1 or 2)
5201 * pPorts [O] PTR to Buffer that receives the Result
5202 * cbBuf [I] Size of Buffer at pPorts
5203 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5204 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5206 * RETURNS
5207 * Success: TRUE
5208 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5211 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5214 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5215 cbBuf, pcbNeeded, pcReturned);
5217 if ((backend == NULL) && !load_backend()) return FALSE;
5219 /* Level is not checked in win9x */
5220 if (!Level || (Level > 2)) {
5221 WARN("level (%d) is ignored in win9x\n", Level);
5222 SetLastError(ERROR_INVALID_LEVEL);
5223 return FALSE;
5225 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5226 SetLastError(RPC_X_NULL_REF_POINTER);
5227 return FALSE;
5230 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5233 /******************************************************************************
5234 * GetDefaultPrinterW (WINSPOOL.@)
5236 * FIXME
5237 * This function must read the value from data 'device' of key
5238 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5240 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5242 BOOL retval = TRUE;
5243 DWORD insize, len;
5244 WCHAR *buffer, *ptr;
5246 if (!namesize)
5248 SetLastError(ERROR_INVALID_PARAMETER);
5249 return FALSE;
5252 /* make the buffer big enough for the stuff from the profile/registry,
5253 * the content must fit into the local buffer to compute the correct
5254 * size even if the extern buffer is too small or not given.
5255 * (20 for ,driver,port) */
5256 insize = *namesize;
5257 len = max(100, (insize + 20));
5258 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5260 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5262 SetLastError (ERROR_FILE_NOT_FOUND);
5263 retval = FALSE;
5264 goto end;
5266 TRACE("%s\n", debugstr_w(buffer));
5268 if ((ptr = strchrW(buffer, ',')) == NULL)
5270 SetLastError(ERROR_INVALID_NAME);
5271 retval = FALSE;
5272 goto end;
5275 *ptr = 0;
5276 *namesize = strlenW(buffer) + 1;
5277 if(!name || (*namesize > insize))
5279 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5280 retval = FALSE;
5281 goto end;
5283 strcpyW(name, buffer);
5285 end:
5286 HeapFree( GetProcessHeap(), 0, buffer);
5287 return retval;
5291 /******************************************************************************
5292 * GetDefaultPrinterA (WINSPOOL.@)
5294 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5296 BOOL retval = TRUE;
5297 DWORD insize = 0;
5298 WCHAR *bufferW = NULL;
5300 if (!namesize)
5302 SetLastError(ERROR_INVALID_PARAMETER);
5303 return FALSE;
5306 if(name && *namesize) {
5307 insize = *namesize;
5308 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5311 if(!GetDefaultPrinterW( bufferW, namesize)) {
5312 retval = FALSE;
5313 goto end;
5316 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5317 NULL, NULL);
5318 if (!*namesize)
5320 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5321 retval = FALSE;
5323 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5325 end:
5326 HeapFree( GetProcessHeap(), 0, bufferW);
5327 return retval;
5331 /******************************************************************************
5332 * SetDefaultPrinterW (WINSPOOL.204)
5334 * Set the Name of the Default Printer
5336 * PARAMS
5337 * pszPrinter [I] Name of the Printer or NULL
5339 * RETURNS
5340 * Success: True
5341 * Failure: FALSE
5343 * NOTES
5344 * When the Parameter is NULL or points to an Empty String and
5345 * a Default Printer was already present, then this Function changes nothing.
5346 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5347 * the First enumerated local Printer is used.
5350 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5353 TRACE("(%s)\n", debugstr_w(pszPrinter));
5355 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5356 return FALSE;
5359 /******************************************************************************
5360 * SetDefaultPrinterA (WINSPOOL.202)
5362 * See SetDefaultPrinterW.
5365 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5368 TRACE("(%s)\n", debugstr_a(pszPrinter));
5370 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5371 return FALSE;
5375 /******************************************************************************
5376 * SetPrinterDataExA (WINSPOOL.@)
5378 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5379 LPCSTR pValueName, DWORD Type,
5380 LPBYTE pData, DWORD cbData)
5382 HKEY hkeyPrinter, hkeySubkey;
5383 DWORD ret;
5385 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5386 debugstr_a(pValueName), Type, pData, cbData);
5388 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5389 != ERROR_SUCCESS)
5390 return ret;
5392 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5393 != ERROR_SUCCESS) {
5394 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5395 RegCloseKey(hkeyPrinter);
5396 return ret;
5398 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5399 RegCloseKey(hkeySubkey);
5400 RegCloseKey(hkeyPrinter);
5401 return ret;
5404 /******************************************************************************
5405 * SetPrinterDataExW (WINSPOOL.@)
5407 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5408 LPCWSTR pValueName, DWORD Type,
5409 LPBYTE pData, DWORD cbData)
5411 HKEY hkeyPrinter, hkeySubkey;
5412 DWORD ret;
5414 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5415 debugstr_w(pValueName), Type, pData, cbData);
5417 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5418 != ERROR_SUCCESS)
5419 return ret;
5421 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5422 != ERROR_SUCCESS) {
5423 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5424 RegCloseKey(hkeyPrinter);
5425 return ret;
5427 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5428 RegCloseKey(hkeySubkey);
5429 RegCloseKey(hkeyPrinter);
5430 return ret;
5433 /******************************************************************************
5434 * SetPrinterDataA (WINSPOOL.@)
5436 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5437 LPBYTE pData, DWORD cbData)
5439 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5440 pData, cbData);
5443 /******************************************************************************
5444 * SetPrinterDataW (WINSPOOL.@)
5446 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5447 LPBYTE pData, DWORD cbData)
5449 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5450 pData, cbData);
5453 /******************************************************************************
5454 * GetPrinterDataExA (WINSPOOL.@)
5456 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5457 LPCSTR pValueName, LPDWORD pType,
5458 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5460 HKEY hkeyPrinter, hkeySubkey;
5461 DWORD ret;
5463 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5464 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5465 pcbNeeded);
5467 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5468 != ERROR_SUCCESS)
5469 return ret;
5471 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5472 != ERROR_SUCCESS) {
5473 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5474 RegCloseKey(hkeyPrinter);
5475 return ret;
5477 *pcbNeeded = nSize;
5478 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5479 RegCloseKey(hkeySubkey);
5480 RegCloseKey(hkeyPrinter);
5481 return ret;
5484 /******************************************************************************
5485 * GetPrinterDataExW (WINSPOOL.@)
5487 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5488 LPCWSTR pValueName, LPDWORD pType,
5489 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5491 HKEY hkeyPrinter, hkeySubkey;
5492 DWORD ret;
5494 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5495 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5496 pcbNeeded);
5498 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5499 != ERROR_SUCCESS)
5500 return ret;
5502 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5503 != ERROR_SUCCESS) {
5504 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5505 RegCloseKey(hkeyPrinter);
5506 return ret;
5508 *pcbNeeded = nSize;
5509 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5510 RegCloseKey(hkeySubkey);
5511 RegCloseKey(hkeyPrinter);
5512 return ret;
5515 /******************************************************************************
5516 * GetPrinterDataA (WINSPOOL.@)
5518 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5519 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5521 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5522 pData, nSize, pcbNeeded);
5525 /******************************************************************************
5526 * GetPrinterDataW (WINSPOOL.@)
5528 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5529 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5531 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5532 pData, nSize, pcbNeeded);
5535 /*******************************************************************************
5536 * EnumPrinterDataExW [WINSPOOL.@]
5538 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5539 LPBYTE pEnumValues, DWORD cbEnumValues,
5540 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5542 HKEY hkPrinter, hkSubKey;
5543 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5544 cbValueNameLen, cbMaxValueLen, cbValueLen,
5545 cbBufSize, dwType;
5546 LPWSTR lpValueName;
5547 HANDLE hHeap;
5548 PBYTE lpValue;
5549 PPRINTER_ENUM_VALUESW ppev;
5551 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5553 if (pKeyName == NULL || *pKeyName == 0)
5554 return ERROR_INVALID_PARAMETER;
5556 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5557 if (ret != ERROR_SUCCESS)
5559 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5560 hPrinter, ret);
5561 return ret;
5564 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5565 if (ret != ERROR_SUCCESS)
5567 r = RegCloseKey (hkPrinter);
5568 if (r != ERROR_SUCCESS)
5569 WARN ("RegCloseKey returned %i\n", r);
5570 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5571 debugstr_w (pKeyName), ret);
5572 return ret;
5575 ret = RegCloseKey (hkPrinter);
5576 if (ret != ERROR_SUCCESS)
5578 ERR ("RegCloseKey returned %i\n", ret);
5579 r = RegCloseKey (hkSubKey);
5580 if (r != ERROR_SUCCESS)
5581 WARN ("RegCloseKey returned %i\n", r);
5582 return ret;
5585 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5586 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5587 if (ret != ERROR_SUCCESS)
5589 r = RegCloseKey (hkSubKey);
5590 if (r != ERROR_SUCCESS)
5591 WARN ("RegCloseKey returned %i\n", r);
5592 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5593 return ret;
5596 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5597 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5599 if (cValues == 0) /* empty key */
5601 r = RegCloseKey (hkSubKey);
5602 if (r != ERROR_SUCCESS)
5603 WARN ("RegCloseKey returned %i\n", r);
5604 *pcbEnumValues = *pnEnumValues = 0;
5605 return ERROR_SUCCESS;
5608 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5610 hHeap = GetProcessHeap ();
5611 if (hHeap == NULL)
5613 ERR ("GetProcessHeap failed\n");
5614 r = RegCloseKey (hkSubKey);
5615 if (r != ERROR_SUCCESS)
5616 WARN ("RegCloseKey returned %i\n", r);
5617 return ERROR_OUTOFMEMORY;
5620 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5621 if (lpValueName == NULL)
5623 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5624 r = RegCloseKey (hkSubKey);
5625 if (r != ERROR_SUCCESS)
5626 WARN ("RegCloseKey returned %i\n", r);
5627 return ERROR_OUTOFMEMORY;
5630 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5631 if (lpValue == NULL)
5633 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5634 if (HeapFree (hHeap, 0, lpValueName) == 0)
5635 WARN ("HeapFree failed with code %i\n", GetLastError ());
5636 r = RegCloseKey (hkSubKey);
5637 if (r != ERROR_SUCCESS)
5638 WARN ("RegCloseKey returned %i\n", r);
5639 return ERROR_OUTOFMEMORY;
5642 TRACE ("pass 1: calculating buffer required for all names and values\n");
5644 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5646 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5648 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5650 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5651 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5652 NULL, NULL, lpValue, &cbValueLen);
5653 if (ret != ERROR_SUCCESS)
5655 if (HeapFree (hHeap, 0, lpValue) == 0)
5656 WARN ("HeapFree failed with code %i\n", GetLastError ());
5657 if (HeapFree (hHeap, 0, lpValueName) == 0)
5658 WARN ("HeapFree failed with code %i\n", GetLastError ());
5659 r = RegCloseKey (hkSubKey);
5660 if (r != ERROR_SUCCESS)
5661 WARN ("RegCloseKey returned %i\n", r);
5662 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5663 return ret;
5666 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5667 debugstr_w (lpValueName), dwIndex,
5668 cbValueNameLen + 1, cbValueLen);
5670 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5671 cbBufSize += cbValueLen;
5674 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5676 *pcbEnumValues = cbBufSize;
5677 *pnEnumValues = cValues;
5679 if (cbEnumValues < cbBufSize) /* buffer too small */
5681 if (HeapFree (hHeap, 0, lpValue) == 0)
5682 WARN ("HeapFree failed with code %i\n", GetLastError ());
5683 if (HeapFree (hHeap, 0, lpValueName) == 0)
5684 WARN ("HeapFree failed with code %i\n", GetLastError ());
5685 r = RegCloseKey (hkSubKey);
5686 if (r != ERROR_SUCCESS)
5687 WARN ("RegCloseKey returned %i\n", r);
5688 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5689 return ERROR_MORE_DATA;
5692 TRACE ("pass 2: copying all names and values to buffer\n");
5694 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5695 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5697 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5699 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5700 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5701 NULL, &dwType, lpValue, &cbValueLen);
5702 if (ret != ERROR_SUCCESS)
5704 if (HeapFree (hHeap, 0, lpValue) == 0)
5705 WARN ("HeapFree failed with code %i\n", GetLastError ());
5706 if (HeapFree (hHeap, 0, lpValueName) == 0)
5707 WARN ("HeapFree failed with code %i\n", GetLastError ());
5708 r = RegCloseKey (hkSubKey);
5709 if (r != ERROR_SUCCESS)
5710 WARN ("RegCloseKey returned %i\n", r);
5711 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5712 return ret;
5715 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5716 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5717 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5718 pEnumValues += cbValueNameLen;
5720 /* return # of *bytes* (including trailing \0), not # of chars */
5721 ppev[dwIndex].cbValueName = cbValueNameLen;
5723 ppev[dwIndex].dwType = dwType;
5725 memcpy (pEnumValues, lpValue, cbValueLen);
5726 ppev[dwIndex].pData = pEnumValues;
5727 pEnumValues += cbValueLen;
5729 ppev[dwIndex].cbData = cbValueLen;
5731 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5732 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5735 if (HeapFree (hHeap, 0, lpValue) == 0)
5737 ret = GetLastError ();
5738 ERR ("HeapFree failed with code %i\n", ret);
5739 if (HeapFree (hHeap, 0, lpValueName) == 0)
5740 WARN ("HeapFree failed with code %i\n", GetLastError ());
5741 r = RegCloseKey (hkSubKey);
5742 if (r != ERROR_SUCCESS)
5743 WARN ("RegCloseKey returned %i\n", r);
5744 return ret;
5747 if (HeapFree (hHeap, 0, lpValueName) == 0)
5749 ret = GetLastError ();
5750 ERR ("HeapFree failed with code %i\n", ret);
5751 r = RegCloseKey (hkSubKey);
5752 if (r != ERROR_SUCCESS)
5753 WARN ("RegCloseKey returned %i\n", r);
5754 return ret;
5757 ret = RegCloseKey (hkSubKey);
5758 if (ret != ERROR_SUCCESS)
5760 ERR ("RegCloseKey returned %i\n", ret);
5761 return ret;
5764 return ERROR_SUCCESS;
5767 /*******************************************************************************
5768 * EnumPrinterDataExA [WINSPOOL.@]
5770 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5771 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5772 * what Windows 2000 SP1 does.
5775 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5776 LPBYTE pEnumValues, DWORD cbEnumValues,
5777 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5779 INT len;
5780 LPWSTR pKeyNameW;
5781 DWORD ret, dwIndex, dwBufSize;
5782 HANDLE hHeap;
5783 LPSTR pBuffer;
5785 TRACE ("%p %s\n", hPrinter, pKeyName);
5787 if (pKeyName == NULL || *pKeyName == 0)
5788 return ERROR_INVALID_PARAMETER;
5790 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5791 if (len == 0)
5793 ret = GetLastError ();
5794 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5795 return ret;
5798 hHeap = GetProcessHeap ();
5799 if (hHeap == NULL)
5801 ERR ("GetProcessHeap failed\n");
5802 return ERROR_OUTOFMEMORY;
5805 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5806 if (pKeyNameW == NULL)
5808 ERR ("Failed to allocate %i bytes from process heap\n",
5809 (LONG)(len * sizeof (WCHAR)));
5810 return ERROR_OUTOFMEMORY;
5813 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5815 ret = GetLastError ();
5816 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5817 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5818 WARN ("HeapFree failed with code %i\n", GetLastError ());
5819 return ret;
5822 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5823 pcbEnumValues, pnEnumValues);
5824 if (ret != ERROR_SUCCESS)
5826 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5827 WARN ("HeapFree failed with code %i\n", GetLastError ());
5828 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5829 return ret;
5832 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5834 ret = GetLastError ();
5835 ERR ("HeapFree failed with code %i\n", ret);
5836 return ret;
5839 if (*pnEnumValues == 0) /* empty key */
5840 return ERROR_SUCCESS;
5842 dwBufSize = 0;
5843 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5845 PPRINTER_ENUM_VALUESW ppev =
5846 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5848 if (dwBufSize < ppev->cbValueName)
5849 dwBufSize = ppev->cbValueName;
5851 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5852 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5853 dwBufSize = ppev->cbData;
5856 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5858 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5859 if (pBuffer == NULL)
5861 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5862 return ERROR_OUTOFMEMORY;
5865 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5867 PPRINTER_ENUM_VALUESW ppev =
5868 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5870 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5871 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5872 NULL);
5873 if (len == 0)
5875 ret = GetLastError ();
5876 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5877 if (HeapFree (hHeap, 0, pBuffer) == 0)
5878 WARN ("HeapFree failed with code %i\n", GetLastError ());
5879 return ret;
5882 memcpy (ppev->pValueName, pBuffer, len);
5884 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5886 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5887 ppev->dwType != REG_MULTI_SZ)
5888 continue;
5890 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5891 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5892 if (len == 0)
5894 ret = GetLastError ();
5895 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5896 if (HeapFree (hHeap, 0, pBuffer) == 0)
5897 WARN ("HeapFree failed with code %i\n", GetLastError ());
5898 return ret;
5901 memcpy (ppev->pData, pBuffer, len);
5903 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5904 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5907 if (HeapFree (hHeap, 0, pBuffer) == 0)
5909 ret = GetLastError ();
5910 ERR ("HeapFree failed with code %i\n", ret);
5911 return ret;
5914 return ERROR_SUCCESS;
5917 /******************************************************************************
5918 * AbortPrinter (WINSPOOL.@)
5920 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5922 FIXME("(%p), stub!\n", hPrinter);
5923 return TRUE;
5926 /******************************************************************************
5927 * AddPortA (WINSPOOL.@)
5929 * See AddPortW.
5932 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5934 LPWSTR nameW = NULL;
5935 LPWSTR monitorW = NULL;
5936 DWORD len;
5937 BOOL res;
5939 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5941 if (pName) {
5942 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5943 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5944 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5947 if (pMonitorName) {
5948 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5949 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5950 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5952 res = AddPortW(nameW, hWnd, monitorW);
5953 HeapFree(GetProcessHeap(), 0, nameW);
5954 HeapFree(GetProcessHeap(), 0, monitorW);
5955 return res;
5958 /******************************************************************************
5959 * AddPortW (WINSPOOL.@)
5961 * Add a Port for a specific Monitor
5963 * PARAMS
5964 * pName [I] Servername or NULL (local Computer)
5965 * hWnd [I] Handle to parent Window for the Dialog-Box
5966 * pMonitorName [I] Name of the Monitor that manage the Port
5968 * RETURNS
5969 * Success: TRUE
5970 * Failure: FALSE
5973 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5975 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5977 if ((backend == NULL) && !load_backend()) return FALSE;
5979 if (!pMonitorName) {
5980 SetLastError(RPC_X_NULL_REF_POINTER);
5981 return FALSE;
5984 return backend->fpAddPort(pName, hWnd, pMonitorName);
5987 /******************************************************************************
5988 * AddPortExA (WINSPOOL.@)
5990 * See AddPortExW.
5993 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5995 PORT_INFO_2W pi2W;
5996 PORT_INFO_2A * pi2A;
5997 LPWSTR nameW = NULL;
5998 LPWSTR monitorW = NULL;
5999 DWORD len;
6000 BOOL res;
6002 pi2A = (PORT_INFO_2A *) pBuffer;
6004 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6005 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6007 if ((level < 1) || (level > 2)) {
6008 SetLastError(ERROR_INVALID_LEVEL);
6009 return FALSE;
6012 if (!pi2A) {
6013 SetLastError(ERROR_INVALID_PARAMETER);
6014 return FALSE;
6017 if (pName) {
6018 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6019 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6020 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6023 if (pMonitorName) {
6024 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6025 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6026 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6029 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6031 if (pi2A->pPortName) {
6032 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6033 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6034 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6037 if (level > 1) {
6038 if (pi2A->pMonitorName) {
6039 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6040 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6041 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6044 if (pi2A->pDescription) {
6045 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6046 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6047 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6049 pi2W.fPortType = pi2A->fPortType;
6050 pi2W.Reserved = pi2A->Reserved;
6053 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6055 HeapFree(GetProcessHeap(), 0, nameW);
6056 HeapFree(GetProcessHeap(), 0, monitorW);
6057 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6058 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6059 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6060 return res;
6064 /******************************************************************************
6065 * AddPortExW (WINSPOOL.@)
6067 * Add a Port for a specific Monitor, without presenting a user interface
6069 * PARAMS
6070 * pName [I] Servername or NULL (local Computer)
6071 * level [I] Structure-Level (1 or 2) for pBuffer
6072 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6073 * pMonitorName [I] Name of the Monitor that manage the Port
6075 * RETURNS
6076 * Success: TRUE
6077 * Failure: FALSE
6080 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6082 PORT_INFO_2W * pi2;
6083 monitor_t * pm;
6084 DWORD res = FALSE;
6086 pi2 = (PORT_INFO_2W *) pBuffer;
6088 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6089 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6090 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6091 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6094 if ((level < 1) || (level > 2)) {
6095 SetLastError(ERROR_INVALID_LEVEL);
6096 return FALSE;
6099 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6100 SetLastError(ERROR_INVALID_PARAMETER);
6101 return FALSE;
6104 /* load the Monitor */
6105 pm = monitor_load(pMonitorName, NULL);
6106 if (!pm) {
6107 SetLastError(ERROR_INVALID_PARAMETER);
6108 return FALSE;
6111 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6112 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6113 TRACE("got %u with %u\n", res, GetLastError());
6115 else
6117 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6119 monitor_unload(pm);
6120 return res;
6123 /******************************************************************************
6124 * AddPrinterConnectionA (WINSPOOL.@)
6126 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6128 FIXME("%s\n", debugstr_a(pName));
6129 return FALSE;
6132 /******************************************************************************
6133 * AddPrinterConnectionW (WINSPOOL.@)
6135 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6137 FIXME("%s\n", debugstr_w(pName));
6138 return FALSE;
6141 /******************************************************************************
6142 * AddPrinterDriverExW (WINSPOOL.@)
6144 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6146 * PARAMS
6147 * pName [I] Servername or NULL (local Computer)
6148 * level [I] Level for the supplied DRIVER_INFO_*W struct
6149 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6150 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6152 * RESULTS
6153 * Success: TRUE
6154 * Failure: FALSE
6157 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6159 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6161 if ((backend == NULL) && !load_backend()) return FALSE;
6163 if (level < 2 || level == 5 || level == 7 || level > 8) {
6164 SetLastError(ERROR_INVALID_LEVEL);
6165 return FALSE;
6168 if (!pDriverInfo) {
6169 SetLastError(ERROR_INVALID_PARAMETER);
6170 return FALSE;
6173 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6176 /******************************************************************************
6177 * AddPrinterDriverExA (WINSPOOL.@)
6179 * See AddPrinterDriverExW.
6182 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6184 DRIVER_INFO_8A *diA;
6185 DRIVER_INFO_8W diW;
6186 LPWSTR nameW = NULL;
6187 DWORD lenA;
6188 DWORD len;
6189 DWORD res = FALSE;
6191 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6193 diA = (DRIVER_INFO_8A *) pDriverInfo;
6194 ZeroMemory(&diW, sizeof(diW));
6196 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6197 SetLastError(ERROR_INVALID_LEVEL);
6198 return FALSE;
6201 if (diA == NULL) {
6202 SetLastError(ERROR_INVALID_PARAMETER);
6203 return FALSE;
6206 /* convert servername to unicode */
6207 if (pName) {
6208 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6209 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6210 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6213 /* common fields */
6214 diW.cVersion = diA->cVersion;
6216 if (diA->pName) {
6217 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6218 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6219 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6222 if (diA->pEnvironment) {
6223 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6224 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6225 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6228 if (diA->pDriverPath) {
6229 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6230 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6231 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6234 if (diA->pDataFile) {
6235 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6236 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6237 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6240 if (diA->pConfigFile) {
6241 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6242 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6243 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6246 if ((Level > 2) && diA->pDependentFiles) {
6247 lenA = multi_sz_lenA(diA->pDependentFiles);
6248 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6249 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6250 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6253 if ((Level > 2) && diA->pMonitorName) {
6254 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6255 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6256 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6259 if ((Level > 3) && diA->pDefaultDataType) {
6260 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6261 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6262 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6265 if ((Level > 3) && diA->pszzPreviousNames) {
6266 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6267 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6268 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6269 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6272 if ((Level > 5) && diA->pszMfgName) {
6273 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6274 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6275 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6278 if ((Level > 5) && diA->pszOEMUrl) {
6279 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6280 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6281 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6284 if ((Level > 5) && diA->pszHardwareID) {
6285 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6286 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6287 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6290 if ((Level > 5) && diA->pszProvider) {
6291 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6292 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6293 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6296 if (Level > 7) {
6297 FIXME("level %u is incomplete\n", Level);
6300 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6301 TRACE("got %u with %u\n", res, GetLastError());
6302 HeapFree(GetProcessHeap(), 0, nameW);
6303 HeapFree(GetProcessHeap(), 0, diW.pName);
6304 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6305 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6306 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6307 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6308 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6309 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6310 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6311 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6312 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6313 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6314 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6315 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6317 TRACE("=> %u with %u\n", res, GetLastError());
6318 return res;
6321 /******************************************************************************
6322 * ConfigurePortA (WINSPOOL.@)
6324 * See ConfigurePortW.
6327 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6329 LPWSTR nameW = NULL;
6330 LPWSTR portW = NULL;
6331 INT len;
6332 DWORD res;
6334 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6336 /* convert servername to unicode */
6337 if (pName) {
6338 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6339 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6340 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6343 /* convert portname to unicode */
6344 if (pPortName) {
6345 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6346 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6347 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6350 res = ConfigurePortW(nameW, hWnd, portW);
6351 HeapFree(GetProcessHeap(), 0, nameW);
6352 HeapFree(GetProcessHeap(), 0, portW);
6353 return res;
6356 /******************************************************************************
6357 * ConfigurePortW (WINSPOOL.@)
6359 * Display the Configuration-Dialog for a specific Port
6361 * PARAMS
6362 * pName [I] Servername or NULL (local Computer)
6363 * hWnd [I] Handle to parent Window for the Dialog-Box
6364 * pPortName [I] Name of the Port, that should be configured
6366 * RETURNS
6367 * Success: TRUE
6368 * Failure: FALSE
6371 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6374 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6376 if ((backend == NULL) && !load_backend()) return FALSE;
6378 if (!pPortName) {
6379 SetLastError(RPC_X_NULL_REF_POINTER);
6380 return FALSE;
6383 return backend->fpConfigurePort(pName, hWnd, pPortName);
6386 /******************************************************************************
6387 * ConnectToPrinterDlg (WINSPOOL.@)
6389 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6391 FIXME("%p %x\n", hWnd, Flags);
6392 return NULL;
6395 /******************************************************************************
6396 * DeletePrinterConnectionA (WINSPOOL.@)
6398 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6400 FIXME("%s\n", debugstr_a(pName));
6401 return TRUE;
6404 /******************************************************************************
6405 * DeletePrinterConnectionW (WINSPOOL.@)
6407 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6409 FIXME("%s\n", debugstr_w(pName));
6410 return TRUE;
6413 /******************************************************************************
6414 * DeletePrinterDriverExW (WINSPOOL.@)
6416 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6417 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6419 HKEY hkey_drivers;
6420 BOOL ret = FALSE;
6422 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6423 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6425 if(pName && pName[0])
6427 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6428 SetLastError(ERROR_INVALID_PARAMETER);
6429 return FALSE;
6432 if(dwDeleteFlag)
6434 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6435 SetLastError(ERROR_INVALID_PARAMETER);
6436 return FALSE;
6439 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6441 if(!hkey_drivers)
6443 ERR("Can't open drivers key\n");
6444 return FALSE;
6447 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6448 ret = TRUE;
6450 RegCloseKey(hkey_drivers);
6452 return ret;
6455 /******************************************************************************
6456 * DeletePrinterDriverExA (WINSPOOL.@)
6458 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6459 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6461 UNICODE_STRING NameW, EnvW, DriverW;
6462 BOOL ret;
6464 asciitounicode(&NameW, pName);
6465 asciitounicode(&EnvW, pEnvironment);
6466 asciitounicode(&DriverW, pDriverName);
6468 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6470 RtlFreeUnicodeString(&DriverW);
6471 RtlFreeUnicodeString(&EnvW);
6472 RtlFreeUnicodeString(&NameW);
6474 return ret;
6477 /******************************************************************************
6478 * DeletePrinterDataExW (WINSPOOL.@)
6480 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6481 LPCWSTR pValueName)
6483 FIXME("%p %s %s\n", hPrinter,
6484 debugstr_w(pKeyName), debugstr_w(pValueName));
6485 return ERROR_INVALID_PARAMETER;
6488 /******************************************************************************
6489 * DeletePrinterDataExA (WINSPOOL.@)
6491 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6492 LPCSTR pValueName)
6494 FIXME("%p %s %s\n", hPrinter,
6495 debugstr_a(pKeyName), debugstr_a(pValueName));
6496 return ERROR_INVALID_PARAMETER;
6499 /******************************************************************************
6500 * DeletePrintProcessorA (WINSPOOL.@)
6502 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6504 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6505 debugstr_a(pPrintProcessorName));
6506 return TRUE;
6509 /******************************************************************************
6510 * DeletePrintProcessorW (WINSPOOL.@)
6512 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6514 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6515 debugstr_w(pPrintProcessorName));
6516 return TRUE;
6519 /******************************************************************************
6520 * DeletePrintProvidorA (WINSPOOL.@)
6522 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6524 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6525 debugstr_a(pPrintProviderName));
6526 return TRUE;
6529 /******************************************************************************
6530 * DeletePrintProvidorW (WINSPOOL.@)
6532 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6534 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6535 debugstr_w(pPrintProviderName));
6536 return TRUE;
6539 /******************************************************************************
6540 * EnumFormsA (WINSPOOL.@)
6542 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6543 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6545 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6546 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6547 return FALSE;
6550 /******************************************************************************
6551 * EnumFormsW (WINSPOOL.@)
6553 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6554 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6556 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6557 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6558 return FALSE;
6561 /*****************************************************************************
6562 * EnumMonitorsA [WINSPOOL.@]
6564 * See EnumMonitorsW.
6567 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6568 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6570 BOOL res;
6571 LPBYTE bufferW = NULL;
6572 LPWSTR nameW = NULL;
6573 DWORD needed = 0;
6574 DWORD numentries = 0;
6575 INT len;
6577 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6578 cbBuf, pcbNeeded, pcReturned);
6580 /* convert servername to unicode */
6581 if (pName) {
6582 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6583 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6584 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6586 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6587 needed = cbBuf * sizeof(WCHAR);
6588 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6589 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6591 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6592 if (pcbNeeded) needed = *pcbNeeded;
6593 /* HeapReAlloc return NULL, when bufferW was NULL */
6594 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6595 HeapAlloc(GetProcessHeap(), 0, needed);
6597 /* Try again with the large Buffer */
6598 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6600 numentries = pcReturned ? *pcReturned : 0;
6601 needed = 0;
6603 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6604 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6606 if (res) {
6607 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6608 DWORD entrysize = 0;
6609 DWORD index;
6610 LPSTR ptr;
6611 LPMONITOR_INFO_2W mi2w;
6612 LPMONITOR_INFO_2A mi2a;
6614 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6615 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6617 /* First pass: calculate the size for all Entries */
6618 mi2w = (LPMONITOR_INFO_2W) bufferW;
6619 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6620 index = 0;
6621 while (index < numentries) {
6622 index++;
6623 needed += entrysize; /* MONITOR_INFO_?A */
6624 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6626 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6627 NULL, 0, NULL, NULL);
6628 if (Level > 1) {
6629 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6630 NULL, 0, NULL, NULL);
6631 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6632 NULL, 0, NULL, NULL);
6634 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6635 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6636 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6639 /* check for errors and quit on failure */
6640 if (cbBuf < needed) {
6641 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6642 res = FALSE;
6643 goto emA_cleanup;
6645 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6646 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6647 cbBuf -= len ; /* free Bytes in the user-Buffer */
6648 mi2w = (LPMONITOR_INFO_2W) bufferW;
6649 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6650 index = 0;
6651 /* Second Pass: Fill the User Buffer (if we have one) */
6652 while ((index < numentries) && pMonitors) {
6653 index++;
6654 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6655 mi2a->pName = ptr;
6656 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6657 ptr, cbBuf , NULL, NULL);
6658 ptr += len;
6659 cbBuf -= len;
6660 if (Level > 1) {
6661 mi2a->pEnvironment = ptr;
6662 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6663 ptr, cbBuf, NULL, NULL);
6664 ptr += len;
6665 cbBuf -= len;
6667 mi2a->pDLLName = ptr;
6668 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6669 ptr, cbBuf, NULL, NULL);
6670 ptr += len;
6671 cbBuf -= len;
6673 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6674 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6675 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6678 emA_cleanup:
6679 if (pcbNeeded) *pcbNeeded = needed;
6680 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6682 HeapFree(GetProcessHeap(), 0, nameW);
6683 HeapFree(GetProcessHeap(), 0, bufferW);
6685 TRACE("returning %d with %d (%d byte for %d entries)\n",
6686 (res), GetLastError(), needed, numentries);
6688 return (res);
6692 /*****************************************************************************
6693 * EnumMonitorsW [WINSPOOL.@]
6695 * Enumerate available Port-Monitors
6697 * PARAMS
6698 * pName [I] Servername or NULL (local Computer)
6699 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6700 * pMonitors [O] PTR to Buffer that receives the Result
6701 * cbBuf [I] Size of Buffer at pMonitors
6702 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6703 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6705 * RETURNS
6706 * Success: TRUE
6707 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6710 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6711 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6714 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6715 cbBuf, pcbNeeded, pcReturned);
6717 if ((backend == NULL) && !load_backend()) return FALSE;
6719 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6720 SetLastError(RPC_X_NULL_REF_POINTER);
6721 return FALSE;
6724 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6727 /******************************************************************************
6728 * SpoolerInit (WINSPOOL.@)
6730 * Initialize the Spooler
6732 * RETURNS
6733 * Success: TRUE
6734 * Failure: FALSE
6736 * NOTES
6737 * The function fails on windows, when the spooler service is not running
6740 BOOL WINAPI SpoolerInit(void)
6743 if ((backend == NULL) && !load_backend()) return FALSE;
6744 return TRUE;
6747 /******************************************************************************
6748 * XcvDataW (WINSPOOL.@)
6750 * Execute commands in the Printmonitor DLL
6752 * PARAMS
6753 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6754 * pszDataName [i] Name of the command to execute
6755 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6756 * cbInputData [i] Size in Bytes of Buffer at pInputData
6757 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6758 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6759 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6760 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6762 * RETURNS
6763 * Success: TRUE
6764 * Failure: FALSE
6766 * NOTES
6767 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6768 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6770 * Minimal List of commands, that a Printmonitor DLL should support:
6772 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6773 *| "AddPort" : Add a Port
6774 *| "DeletePort": Delete a Port
6776 * Many Printmonitors support additional commands. Examples for localspl.dll:
6777 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6778 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6781 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6782 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6783 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6785 opened_printer_t *printer;
6787 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6788 pInputData, cbInputData, pOutputData,
6789 cbOutputData, pcbOutputNeeded, pdwStatus);
6791 if ((backend == NULL) && !load_backend()) return FALSE;
6793 printer = get_opened_printer(hXcv);
6794 if (!printer || (!printer->backend_printer)) {
6795 SetLastError(ERROR_INVALID_HANDLE);
6796 return FALSE;
6799 if (!pcbOutputNeeded) {
6800 SetLastError(ERROR_INVALID_PARAMETER);
6801 return FALSE;
6804 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6805 SetLastError(RPC_X_NULL_REF_POINTER);
6806 return FALSE;
6809 *pcbOutputNeeded = 0;
6811 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6812 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6816 /*****************************************************************************
6817 * EnumPrinterDataA [WINSPOOL.@]
6820 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6821 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6822 DWORD cbData, LPDWORD pcbData )
6824 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6825 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6826 return ERROR_NO_MORE_ITEMS;
6829 /*****************************************************************************
6830 * EnumPrinterDataW [WINSPOOL.@]
6833 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6834 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6835 DWORD cbData, LPDWORD pcbData )
6837 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6838 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6839 return ERROR_NO_MORE_ITEMS;
6842 /*****************************************************************************
6843 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6846 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6847 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6848 LPDWORD pcbNeeded, LPDWORD pcReturned)
6850 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6851 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6852 pcbNeeded, pcReturned);
6853 return FALSE;
6856 /*****************************************************************************
6857 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6860 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6861 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6862 LPDWORD pcbNeeded, LPDWORD pcReturned)
6864 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6865 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6866 pcbNeeded, pcReturned);
6867 return FALSE;
6870 /*****************************************************************************
6871 * EnumPrintProcessorsA [WINSPOOL.@]
6874 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6875 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6877 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6878 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6879 return FALSE;
6882 /*****************************************************************************
6883 * EnumPrintProcessorsW [WINSPOOL.@]
6886 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6887 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6889 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6890 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6891 cbBuf, pcbNeeded, pcbReturned);
6892 return FALSE;
6895 /*****************************************************************************
6896 * ExtDeviceMode [WINSPOOL.@]
6899 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6900 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6901 DWORD fMode)
6903 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6904 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6905 debugstr_a(pProfile), fMode);
6906 return -1;
6909 /*****************************************************************************
6910 * FindClosePrinterChangeNotification [WINSPOOL.@]
6913 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6915 FIXME("Stub: %p\n", hChange);
6916 return TRUE;
6919 /*****************************************************************************
6920 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6923 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6924 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6926 FIXME("Stub: %p %x %x %p\n",
6927 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6928 return INVALID_HANDLE_VALUE;
6931 /*****************************************************************************
6932 * FindNextPrinterChangeNotification [WINSPOOL.@]
6935 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6936 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6938 FIXME("Stub: %p %p %p %p\n",
6939 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6940 return FALSE;
6943 /*****************************************************************************
6944 * FreePrinterNotifyInfo [WINSPOOL.@]
6947 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6949 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6950 return TRUE;
6953 /*****************************************************************************
6954 * string_to_buf
6956 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6957 * ansi depending on the unicode parameter.
6959 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6961 if(!str)
6963 *size = 0;
6964 return TRUE;
6967 if(unicode)
6969 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6970 if(*size <= cb)
6972 memcpy(ptr, str, *size);
6973 return TRUE;
6975 return FALSE;
6977 else
6979 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6980 if(*size <= cb)
6982 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6983 return TRUE;
6985 return FALSE;
6989 /*****************************************************************************
6990 * get_job_info_1
6992 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6993 LPDWORD pcbNeeded, BOOL unicode)
6995 DWORD size, left = cbBuf;
6996 BOOL space = (cbBuf > 0);
6997 LPBYTE ptr = buf;
6999 *pcbNeeded = 0;
7001 if(space)
7003 ji1->JobId = job->job_id;
7006 string_to_buf(job->document_title, ptr, left, &size, unicode);
7007 if(space && size <= left)
7009 ji1->pDocument = (LPWSTR)ptr;
7010 ptr += size;
7011 left -= size;
7013 else
7014 space = FALSE;
7015 *pcbNeeded += size;
7017 return space;
7020 /*****************************************************************************
7021 * get_job_info_2
7023 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7024 LPDWORD pcbNeeded, BOOL unicode)
7026 DWORD size, left = cbBuf;
7027 BOOL space = (cbBuf > 0);
7028 LPBYTE ptr = buf;
7030 *pcbNeeded = 0;
7032 if(space)
7034 ji2->JobId = job->job_id;
7037 string_to_buf(job->document_title, ptr, left, &size, unicode);
7038 if(space && size <= left)
7040 ji2->pDocument = (LPWSTR)ptr;
7041 ptr += size;
7042 left -= size;
7044 else
7045 space = FALSE;
7046 *pcbNeeded += size;
7048 return space;
7051 /*****************************************************************************
7052 * get_job_info
7054 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7055 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7057 BOOL ret = FALSE;
7058 DWORD needed = 0, size;
7059 job_t *job;
7060 LPBYTE ptr = pJob;
7062 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7064 EnterCriticalSection(&printer_handles_cs);
7065 job = get_job(hPrinter, JobId);
7066 if(!job)
7067 goto end;
7069 switch(Level)
7071 case 1:
7072 size = sizeof(JOB_INFO_1W);
7073 if(cbBuf >= size)
7075 cbBuf -= size;
7076 ptr += size;
7077 memset(pJob, 0, size);
7079 else
7080 cbBuf = 0;
7081 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7082 needed += size;
7083 break;
7085 case 2:
7086 size = sizeof(JOB_INFO_2W);
7087 if(cbBuf >= size)
7089 cbBuf -= size;
7090 ptr += size;
7091 memset(pJob, 0, size);
7093 else
7094 cbBuf = 0;
7095 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7096 needed += size;
7097 break;
7099 case 3:
7100 size = sizeof(JOB_INFO_3);
7101 if(cbBuf >= size)
7103 cbBuf -= size;
7104 memset(pJob, 0, size);
7105 ret = TRUE;
7107 else
7108 cbBuf = 0;
7109 needed = size;
7110 break;
7112 default:
7113 SetLastError(ERROR_INVALID_LEVEL);
7114 goto end;
7116 if(pcbNeeded)
7117 *pcbNeeded = needed;
7118 end:
7119 LeaveCriticalSection(&printer_handles_cs);
7120 return ret;
7123 /*****************************************************************************
7124 * GetJobA [WINSPOOL.@]
7127 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7128 DWORD cbBuf, LPDWORD pcbNeeded)
7130 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7133 /*****************************************************************************
7134 * GetJobW [WINSPOOL.@]
7137 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7138 DWORD cbBuf, LPDWORD pcbNeeded)
7140 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7143 /*****************************************************************************
7144 * schedule_lpr
7146 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7148 char *unixname, *queue, *cmd;
7149 char fmt[] = "lpr -P%s %s";
7150 DWORD len;
7151 int r;
7153 if(!(unixname = wine_get_unix_file_name(filename)))
7154 return FALSE;
7156 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7157 queue = HeapAlloc(GetProcessHeap(), 0, len);
7158 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7160 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7161 sprintf(cmd, fmt, queue, unixname);
7163 TRACE("printing with: %s\n", cmd);
7164 r = system(cmd);
7166 HeapFree(GetProcessHeap(), 0, cmd);
7167 HeapFree(GetProcessHeap(), 0, queue);
7168 HeapFree(GetProcessHeap(), 0, unixname);
7169 return (r == 0);
7172 /*****************************************************************************
7173 * schedule_cups
7175 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7177 #ifdef SONAME_LIBCUPS
7178 if(pcupsPrintFile)
7180 char *unixname, *queue, *unix_doc_title;
7181 DWORD len;
7182 BOOL ret;
7184 if(!(unixname = wine_get_unix_file_name(filename)))
7185 return FALSE;
7187 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7188 queue = HeapAlloc(GetProcessHeap(), 0, len);
7189 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7191 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7192 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7193 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7195 TRACE("printing via cups\n");
7196 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7197 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7198 HeapFree(GetProcessHeap(), 0, queue);
7199 HeapFree(GetProcessHeap(), 0, unixname);
7200 return ret;
7202 else
7203 #endif
7205 return schedule_lpr(printer_name, filename);
7209 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7211 LPWSTR filename;
7213 switch(msg)
7215 case WM_INITDIALOG:
7216 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7217 return TRUE;
7219 case WM_COMMAND:
7220 if(HIWORD(wparam) == BN_CLICKED)
7222 if(LOWORD(wparam) == IDOK)
7224 HANDLE hf;
7225 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7226 LPWSTR *output;
7228 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7229 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7231 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7233 WCHAR caption[200], message[200];
7234 int mb_ret;
7236 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7237 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7238 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7239 if(mb_ret == IDCANCEL)
7241 HeapFree(GetProcessHeap(), 0, filename);
7242 return TRUE;
7245 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7246 if(hf == INVALID_HANDLE_VALUE)
7248 WCHAR caption[200], message[200];
7250 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7251 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7252 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7253 HeapFree(GetProcessHeap(), 0, filename);
7254 return TRUE;
7256 CloseHandle(hf);
7257 DeleteFileW(filename);
7258 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7259 *output = filename;
7260 EndDialog(hwnd, IDOK);
7261 return TRUE;
7263 if(LOWORD(wparam) == IDCANCEL)
7265 EndDialog(hwnd, IDCANCEL);
7266 return TRUE;
7269 return FALSE;
7271 return FALSE;
7274 /*****************************************************************************
7275 * get_filename
7277 static BOOL get_filename(LPWSTR *filename)
7279 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7280 file_dlg_proc, (LPARAM)filename) == IDOK;
7283 /*****************************************************************************
7284 * schedule_file
7286 static BOOL schedule_file(LPCWSTR filename)
7288 LPWSTR output = NULL;
7290 if(get_filename(&output))
7292 BOOL r;
7293 TRACE("copy to %s\n", debugstr_w(output));
7294 r = CopyFileW(filename, output, FALSE);
7295 HeapFree(GetProcessHeap(), 0, output);
7296 return r;
7298 return FALSE;
7301 /*****************************************************************************
7302 * schedule_pipe
7304 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7306 #ifdef HAVE_FORK
7307 char *unixname, *cmdA;
7308 DWORD len;
7309 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7310 BOOL ret = FALSE;
7311 char buf[1024];
7313 if(!(unixname = wine_get_unix_file_name(filename)))
7314 return FALSE;
7316 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7317 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7318 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7320 TRACE("printing with: %s\n", cmdA);
7322 if((file_fd = open(unixname, O_RDONLY)) == -1)
7323 goto end;
7325 if (pipe(fds))
7327 ERR("pipe() failed!\n");
7328 goto end;
7331 if (fork() == 0)
7333 close(0);
7334 dup2(fds[0], 0);
7335 close(fds[1]);
7337 /* reset signals that we previously set to SIG_IGN */
7338 signal(SIGPIPE, SIG_DFL);
7339 signal(SIGCHLD, SIG_DFL);
7341 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7342 _exit(1);
7345 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7346 write(fds[1], buf, no_read);
7348 ret = TRUE;
7350 end:
7351 if(file_fd != -1) close(file_fd);
7352 if(fds[0] != -1) close(fds[0]);
7353 if(fds[1] != -1) close(fds[1]);
7355 HeapFree(GetProcessHeap(), 0, cmdA);
7356 HeapFree(GetProcessHeap(), 0, unixname);
7357 return ret;
7358 #else
7359 return FALSE;
7360 #endif
7363 /*****************************************************************************
7364 * schedule_unixfile
7366 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7368 int in_fd, out_fd, no_read;
7369 char buf[1024];
7370 BOOL ret = FALSE;
7371 char *unixname, *outputA;
7372 DWORD len;
7374 if(!(unixname = wine_get_unix_file_name(filename)))
7375 return FALSE;
7377 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7378 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7379 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7381 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7382 in_fd = open(unixname, O_RDONLY);
7383 if(out_fd == -1 || in_fd == -1)
7384 goto end;
7386 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7387 write(out_fd, buf, no_read);
7389 ret = TRUE;
7390 end:
7391 if(in_fd != -1) close(in_fd);
7392 if(out_fd != -1) close(out_fd);
7393 HeapFree(GetProcessHeap(), 0, outputA);
7394 HeapFree(GetProcessHeap(), 0, unixname);
7395 return ret;
7398 /*****************************************************************************
7399 * ScheduleJob [WINSPOOL.@]
7402 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7404 opened_printer_t *printer;
7405 BOOL ret = FALSE;
7406 struct list *cursor, *cursor2;
7408 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7409 EnterCriticalSection(&printer_handles_cs);
7410 printer = get_opened_printer(hPrinter);
7411 if(!printer)
7412 goto end;
7414 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7416 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7417 HANDLE hf;
7419 if(job->job_id != dwJobID) continue;
7421 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7422 if(hf != INVALID_HANDLE_VALUE)
7424 PRINTER_INFO_5W *pi5;
7425 DWORD needed;
7426 HKEY hkey;
7427 WCHAR output[1024];
7428 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7429 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7431 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7432 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7433 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7434 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7435 debugstr_w(pi5->pPortName));
7437 output[0] = 0;
7439 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7440 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7442 DWORD type, count = sizeof(output);
7443 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7444 RegCloseKey(hkey);
7446 if(output[0] == '|')
7448 ret = schedule_pipe(output + 1, job->filename);
7450 else if(output[0])
7452 ret = schedule_unixfile(output, job->filename);
7454 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7456 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7458 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7460 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7462 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7464 ret = schedule_file(job->filename);
7466 else
7468 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7470 HeapFree(GetProcessHeap(), 0, pi5);
7471 CloseHandle(hf);
7472 DeleteFileW(job->filename);
7474 list_remove(cursor);
7475 HeapFree(GetProcessHeap(), 0, job->document_title);
7476 HeapFree(GetProcessHeap(), 0, job->filename);
7477 HeapFree(GetProcessHeap(), 0, job);
7478 break;
7480 end:
7481 LeaveCriticalSection(&printer_handles_cs);
7482 return ret;
7485 /*****************************************************************************
7486 * StartDocDlgA [WINSPOOL.@]
7488 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7490 UNICODE_STRING usBuffer;
7491 DOCINFOW docW;
7492 LPWSTR retW;
7493 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7494 LPSTR ret = NULL;
7496 docW.cbSize = sizeof(docW);
7497 if (doc->lpszDocName)
7499 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7500 if (!(docW.lpszDocName = docnameW)) return NULL;
7502 if (doc->lpszOutput)
7504 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7505 if (!(docW.lpszOutput = outputW)) return NULL;
7507 if (doc->lpszDatatype)
7509 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7510 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7512 docW.fwType = doc->fwType;
7514 retW = StartDocDlgW(hPrinter, &docW);
7516 if(retW)
7518 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7519 ret = HeapAlloc(GetProcessHeap(), 0, len);
7520 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7521 HeapFree(GetProcessHeap(), 0, retW);
7524 HeapFree(GetProcessHeap(), 0, datatypeW);
7525 HeapFree(GetProcessHeap(), 0, outputW);
7526 HeapFree(GetProcessHeap(), 0, docnameW);
7528 return ret;
7531 /*****************************************************************************
7532 * StartDocDlgW [WINSPOOL.@]
7534 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7535 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7536 * port is "FILE:". Also returns the full path if passed a relative path.
7538 * The caller should free the returned string from the process heap.
7540 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7542 LPWSTR ret = NULL;
7543 DWORD len, attr;
7545 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7547 PRINTER_INFO_5W *pi5;
7548 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7549 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7550 return NULL;
7551 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7552 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7553 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7555 HeapFree(GetProcessHeap(), 0, pi5);
7556 return NULL;
7558 HeapFree(GetProcessHeap(), 0, pi5);
7561 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7563 LPWSTR name;
7565 if (get_filename(&name))
7567 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7569 HeapFree(GetProcessHeap(), 0, name);
7570 return NULL;
7572 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7573 GetFullPathNameW(name, len, ret, NULL);
7574 HeapFree(GetProcessHeap(), 0, name);
7576 return ret;
7579 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7580 return NULL;
7582 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7583 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7585 attr = GetFileAttributesW(ret);
7586 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7588 HeapFree(GetProcessHeap(), 0, ret);
7589 ret = NULL;
7591 return ret;